]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
1 | /* |
2 | * mkfs.c - make a linux (minix) file-system. | |
3 | * | |
4 | * (C) 1991 Linus Torvalds. This file may be redistributed as per | |
5 | * the Linux copyright. | |
6 | */ | |
7 | ||
8 | /* | |
726f69e2 | 9 | * DD.MM.YY |
6dbe3af9 | 10 | * |
726f69e2 KZ |
11 | * 24.11.91 - Time began. Used the fsck sources to get started. |
12 | * | |
13 | * 25.11.91 - Corrected some bugs. Added support for ".badblocks" | |
6dbe3af9 KZ |
14 | * The algorithm for ".badblocks" is a bit weird, but |
15 | * it should work. Oh, well. | |
16 | * | |
726f69e2 KZ |
17 | * 25.01.92 - Added the -l option for getting the list of bad blocks |
18 | * out of a named file. (Dave Rivers, rivers@ponds.uucp) | |
6dbe3af9 | 19 | * |
726f69e2 | 20 | * 28.02.92 - Added %-information when using -c. |
6dbe3af9 | 21 | * |
726f69e2 | 22 | * 28.02.93 - Added support for other namelengths than the original |
6dbe3af9 KZ |
23 | * 14 characters so that I can test the new kernel routines.. |
24 | * | |
726f69e2 KZ |
25 | * 09.10.93 - Make exit status conform to that required by fsutil |
26 | * (Rik Faith, faith@cs.unc.edu) | |
6dbe3af9 | 27 | * |
726f69e2 KZ |
28 | * 31.10.93 - Added inode request feature, for backup floppies: use |
29 | * 32 inodes, for a news partition use more. | |
30 | * (Scott Heavner, sdh@po.cwru.edu) | |
6dbe3af9 | 31 | * |
726f69e2 KZ |
32 | * 03.01.94 - Added support for file system valid flag. |
33 | * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) | |
fd6b7a7f | 34 | * |
66ee8158 KZ |
35 | * 30.10.94 - Added support for v2 filesystem |
36 | * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) | |
6dbe3af9 | 37 | * |
726f69e2 KZ |
38 | * 09.11.94 - Added test to prevent overwrite of mounted fs adapted |
39 | * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs | |
40 | * program. (Daniel Quinlan, quinlan@yggdrasil.com) | |
41 | * | |
42 | * 03.20.95 - Clear first 512 bytes of filesystem to make certain that | |
43 | * the filesystem is not misidentified as a MS-DOS FAT filesystem. | |
44 | * (Daniel Quinlan, quinlan@yggdrasil.com) | |
6dbe3af9 | 45 | * |
fd6b7a7f KZ |
46 | * 02.07.96 - Added small patch from Russell King to make the program a |
47 | * good deal more portable (janl@math.uio.no) | |
48 | * | |
49 | * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] | |
6dbe3af9 KZ |
50 | * |
51 | * -c for readablility checking (SLOW!) | |
52 | * -l for getting a list of bad blocks from a file. | |
53 | * -n for namelength (currently the kernel only uses 14 or 30) | |
54 | * -i for number of inodes | |
fd6b7a7f | 55 | * -v for v2 filesystem |
6dbe3af9 KZ |
56 | * |
57 | * The device may be a block device or a image of one, but this isn't | |
58 | * enforced (but it's not much fun on a character device :-). | |
59 | */ | |
60 | ||
61 | #include <stdio.h> | |
62 | #include <time.h> | |
63 | #include <unistd.h> | |
64 | #include <string.h> | |
65 | #include <signal.h> | |
66 | #include <fcntl.h> | |
67 | #include <ctype.h> | |
68 | #include <stdlib.h> | |
69 | #include <termios.h> | |
70 | #include <sys/stat.h> | |
fd6b7a7f | 71 | #include <sys/ioctl.h> |
6dbe3af9 | 72 | #include <mntent.h> |
7eda085c | 73 | #include <getopt.h> |
6dbe3af9 | 74 | |
22853e4a | 75 | #include "minix.h" |
7eda085c | 76 | #include "nls.h" |
7eda085c | 77 | |
22853e4a KZ |
78 | #ifndef BLKGETSIZE |
79 | #define BLKGETSIZE _IO(0x12,96) /* return device size */ | |
80 | #endif | |
81 | ||
fd6b7a7f KZ |
82 | #ifdef MINIX2_SUPER_MAGIC2 |
83 | #define HAVE_MINIX2 1 | |
84 | #endif | |
85 | ||
6dbe3af9 KZ |
86 | #ifndef __GNUC__ |
87 | #error "needs gcc for the bitop-__asm__'s" | |
88 | #endif | |
89 | ||
6dbe3af9 KZ |
90 | #define MINIX_ROOT_INO 1 |
91 | #define MINIX_BAD_INO 2 | |
92 | ||
93 | #define TEST_BUFFER_BLOCKS 16 | |
94 | #define MAX_GOOD_BLOCKS 512 | |
95 | ||
96 | #define UPPER(size,n) ((size+((n)-1))/(n)) | |
97 | #define INODE_SIZE (sizeof(struct minix_inode)) | |
fd6b7a7f KZ |
98 | #ifdef HAVE_MINIX2 |
99 | #define INODE_SIZE2 (sizeof(struct minix2_inode)) | |
100 | #define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ | |
101 | : MINIX_INODES_PER_BLOCK)) | |
102 | #else | |
103 | #define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) | |
104 | #endif | |
6dbe3af9 KZ |
105 | #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) |
106 | ||
107 | #define BITS_PER_BLOCK (BLOCK_SIZE<<3) | |
108 | ||
109 | static char * program_name = "mkfs"; | |
110 | static char * device_name = NULL; | |
111 | static int DEV = -1; | |
112 | static long BLOCKS = 0; | |
113 | static int check = 0; | |
114 | static int badblocks = 0; | |
115 | static int namelen = 30; /* default (changed to 30, per Linus's | |
116 | suggestion, Sun Nov 21 08:05:07 1993) */ | |
fd6b7a7f KZ |
117 | static int dirsize = 32; |
118 | static int magic = MINIX_SUPER_MAGIC2; | |
119 | static int version2 = 0; | |
6dbe3af9 KZ |
120 | |
121 | static char root_block[BLOCK_SIZE] = "\0"; | |
122 | ||
123 | static char * inode_buffer = NULL; | |
124 | #define Inode (((struct minix_inode *) inode_buffer)-1) | |
fd6b7a7f KZ |
125 | #ifdef HAVE_MINIX2 |
126 | #define Inode2 (((struct minix2_inode *) inode_buffer)-1) | |
127 | #endif | |
6dbe3af9 | 128 | static char super_block_buffer[BLOCK_SIZE]; |
726f69e2 | 129 | static char boot_block_buffer[512]; |
6dbe3af9 KZ |
130 | #define Super (*(struct minix_super_block *)super_block_buffer) |
131 | #define INODES ((unsigned long)Super.s_ninodes) | |
fd6b7a7f KZ |
132 | #ifdef HAVE_MINIX2 |
133 | #define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) | |
134 | #else | |
135 | #define ZONES ((unsigned long)(Super.s_nzones)) | |
136 | #endif | |
6dbe3af9 KZ |
137 | #define IMAPS ((unsigned long)Super.s_imap_blocks) |
138 | #define ZMAPS ((unsigned long)Super.s_zmap_blocks) | |
139 | #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) | |
140 | #define ZONESIZE ((unsigned long)Super.s_log_zone_size) | |
141 | #define MAXSIZE ((unsigned long)Super.s_max_size) | |
142 | #define MAGIC (Super.s_magic) | |
143 | #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) | |
144 | ||
2b6fc908 KZ |
145 | static char *inode_map; |
146 | static char *zone_map; | |
6dbe3af9 KZ |
147 | |
148 | static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; | |
149 | static int used_good_blocks = 0; | |
150 | static unsigned long req_nr_inodes = 0; | |
151 | ||
fd6b7a7f | 152 | #include "bitops.h" |
6dbe3af9 KZ |
153 | |
154 | #define inode_in_use(x) (bit(inode_map,(x))) | |
155 | #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) | |
156 | ||
157 | #define mark_inode(x) (setbit(inode_map,(x))) | |
158 | #define unmark_inode(x) (clrbit(inode_map,(x))) | |
159 | ||
160 | #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) | |
161 | #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) | |
162 | ||
22853e4a KZ |
163 | static void |
164 | fatal_error(const char * fmt_string,int status) { | |
6dbe3af9 KZ |
165 | fprintf(stderr,fmt_string,program_name,device_name); |
166 | exit(status); | |
167 | } | |
168 | ||
22853e4a KZ |
169 | static void |
170 | die(char *str) { | |
7eda085c KZ |
171 | fprintf(stderr, "%s: %s\n", program_name, str); |
172 | exit(8); | |
173 | } | |
174 | ||
22853e4a KZ |
175 | static void |
176 | usage(void) { | |
7eda085c KZ |
177 | fprintf(stderr, "%s (%s)\n", program_name, util_linux_version); |
178 | fprintf(stderr, | |
179 | _("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]\n"), | |
180 | program_name); | |
181 | exit(16); | |
182 | } | |
6dbe3af9 KZ |
183 | |
184 | /* | |
185 | * Check to make certain that our new filesystem won't be created on | |
186 | * an already mounted partition. Code adapted from mke2fs, Copyright | |
187 | * (C) 1994 Theodore Ts'o. Also licensed under GPL. | |
188 | */ | |
22853e4a KZ |
189 | static void |
190 | check_mount(void) { | |
6dbe3af9 KZ |
191 | FILE * f; |
192 | struct mntent * mnt; | |
193 | ||
194 | if ((f = setmntent (MOUNTED, "r")) == NULL) | |
195 | return; | |
196 | while ((mnt = getmntent (f)) != NULL) | |
197 | if (strcmp (device_name, mnt->mnt_fsname) == 0) | |
198 | break; | |
199 | endmntent (f); | |
200 | if (!mnt) | |
201 | return; | |
202 | ||
7eda085c | 203 | die(_("%s is mounted; will not make a filesystem here!")); |
6dbe3af9 KZ |
204 | } |
205 | ||
22853e4a KZ |
206 | static long |
207 | valid_offset (int fd, int offset) { | |
fd6b7a7f KZ |
208 | char ch; |
209 | ||
210 | if (lseek (fd, offset, 0) < 0) | |
211 | return 0; | |
212 | if (read (fd, &ch, 1) < 1) | |
213 | return 0; | |
214 | return 1; | |
215 | } | |
216 | ||
22853e4a KZ |
217 | static int |
218 | count_blocks (int fd) { | |
fd6b7a7f KZ |
219 | int high, low; |
220 | ||
221 | low = 0; | |
222 | for (high = 1; valid_offset (fd, high); high *= 2) | |
223 | low = high; | |
224 | while (low < high - 1) | |
225 | { | |
226 | const int mid = (low + high) / 2; | |
227 | ||
228 | if (valid_offset (fd, mid)) | |
229 | low = mid; | |
230 | else | |
231 | high = mid; | |
232 | } | |
233 | valid_offset (fd, 0); | |
234 | return (low + 1); | |
235 | } | |
236 | ||
22853e4a KZ |
237 | static int |
238 | get_size(const char *file) { | |
fd6b7a7f | 239 | int fd; |
7eda085c | 240 | long size; |
fd6b7a7f KZ |
241 | |
242 | fd = open(file, O_RDWR); | |
243 | if (fd < 0) { | |
244 | perror(file); | |
245 | exit(1); | |
246 | } | |
247 | if (ioctl(fd, BLKGETSIZE, &size) >= 0) { | |
248 | close(fd); | |
249 | return (size * 512); | |
250 | } | |
251 | ||
252 | size = count_blocks(fd); | |
253 | close(fd); | |
254 | return size; | |
255 | } | |
256 | ||
22853e4a KZ |
257 | static void |
258 | write_tables(void) { | |
6dbe3af9 KZ |
259 | /* Mark the super block valid. */ |
260 | Super.s_state |= MINIX_VALID_FS; | |
261 | Super.s_state &= ~MINIX_ERROR_FS; | |
262 | ||
726f69e2 | 263 | if (lseek(DEV, 0, SEEK_SET)) |
7eda085c | 264 | die(_("seek to boot block failed in write_tables")); |
726f69e2 | 265 | if (512 != write(DEV, boot_block_buffer, 512)) |
7eda085c | 266 | die(_("unable to clear boot sector")); |
6dbe3af9 | 267 | if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) |
7eda085c | 268 | die(_("seek failed in write_tables")); |
6dbe3af9 | 269 | if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) |
7eda085c | 270 | die(_("unable to write super-block")); |
6dbe3af9 | 271 | if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE)) |
7eda085c | 272 | die(_("unable to write inode map")); |
6dbe3af9 | 273 | if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE)) |
7eda085c | 274 | die(_("unable to write zone map")); |
6dbe3af9 | 275 | if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE)) |
7eda085c | 276 | die(_("unable to write inodes")); |
726f69e2 | 277 | |
6dbe3af9 KZ |
278 | } |
279 | ||
22853e4a KZ |
280 | static void |
281 | write_block(int blk, char * buffer) { | |
6dbe3af9 | 282 | if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET)) |
7eda085c | 283 | die(_("seek failed in write_block")); |
6dbe3af9 | 284 | if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) |
7eda085c | 285 | die(_("write failed in write_block")); |
6dbe3af9 KZ |
286 | } |
287 | ||
22853e4a KZ |
288 | static int |
289 | get_free_block(void) { | |
6dbe3af9 KZ |
290 | int blk; |
291 | ||
292 | if (used_good_blocks+1 >= MAX_GOOD_BLOCKS) | |
7eda085c | 293 | die(_("too many bad blocks")); |
6dbe3af9 KZ |
294 | if (used_good_blocks) |
295 | blk = good_blocks_table[used_good_blocks-1]+1; | |
296 | else | |
297 | blk = FIRSTZONE; | |
298 | while (blk < ZONES && zone_in_use(blk)) | |
299 | blk++; | |
300 | if (blk >= ZONES) | |
7eda085c | 301 | die(_("not enough good blocks")); |
6dbe3af9 KZ |
302 | good_blocks_table[used_good_blocks] = blk; |
303 | used_good_blocks++; | |
304 | return blk; | |
305 | } | |
306 | ||
22853e4a KZ |
307 | static void |
308 | mark_good_blocks(void) { | |
6dbe3af9 KZ |
309 | int blk; |
310 | ||
311 | for (blk=0 ; blk < used_good_blocks ; blk++) | |
312 | mark_zone(good_blocks_table[blk]); | |
313 | } | |
314 | ||
22853e4a KZ |
315 | static inline int |
316 | next(int zone) { | |
6dbe3af9 KZ |
317 | if (!zone) |
318 | zone = FIRSTZONE-1; | |
319 | while (++zone < ZONES) | |
320 | if (zone_in_use(zone)) | |
321 | return zone; | |
322 | return 0; | |
323 | } | |
324 | ||
22853e4a KZ |
325 | static void |
326 | make_bad_inode(void) { | |
6dbe3af9 KZ |
327 | struct minix_inode * inode = &Inode[MINIX_BAD_INO]; |
328 | int i,j,zone; | |
329 | int ind=0,dind=0; | |
330 | unsigned short ind_block[BLOCK_SIZE>>1]; | |
331 | unsigned short dind_block[BLOCK_SIZE>>1]; | |
332 | ||
333 | #define NEXT_BAD (zone = next(zone)) | |
334 | ||
335 | if (!badblocks) | |
336 | return; | |
337 | mark_inode(MINIX_BAD_INO); | |
338 | inode->i_nlinks = 1; | |
339 | inode->i_time = time(NULL); | |
340 | inode->i_mode = S_IFREG + 0000; | |
341 | inode->i_size = badblocks*BLOCK_SIZE; | |
342 | zone = next(0); | |
343 | for (i=0 ; i<7 ; i++) { | |
344 | inode->i_zone[i] = zone; | |
345 | if (!NEXT_BAD) | |
346 | goto end_bad; | |
347 | } | |
348 | inode->i_zone[7] = ind = get_free_block(); | |
349 | memset(ind_block,0,BLOCK_SIZE); | |
350 | for (i=0 ; i<512 ; i++) { | |
351 | ind_block[i] = zone; | |
352 | if (!NEXT_BAD) | |
353 | goto end_bad; | |
354 | } | |
355 | inode->i_zone[8] = dind = get_free_block(); | |
356 | memset(dind_block,0,BLOCK_SIZE); | |
357 | for (i=0 ; i<512 ; i++) { | |
358 | write_block(ind,(char *) ind_block); | |
359 | dind_block[i] = ind = get_free_block(); | |
360 | memset(ind_block,0,BLOCK_SIZE); | |
361 | for (j=0 ; j<512 ; j++) { | |
362 | ind_block[j] = zone; | |
363 | if (!NEXT_BAD) | |
364 | goto end_bad; | |
365 | } | |
366 | } | |
7eda085c | 367 | die(_("too many bad blocks")); |
6dbe3af9 KZ |
368 | end_bad: |
369 | if (ind) | |
370 | write_block(ind, (char *) ind_block); | |
371 | if (dind) | |
372 | write_block(dind, (char *) dind_block); | |
373 | } | |
374 | ||
fd6b7a7f | 375 | #ifdef HAVE_MINIX2 |
22853e4a KZ |
376 | static void |
377 | make_bad_inode2 (void) { | |
fd6b7a7f KZ |
378 | struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; |
379 | int i, j, zone; | |
380 | int ind = 0, dind = 0; | |
381 | unsigned long ind_block[BLOCK_SIZE >> 2]; | |
382 | unsigned long dind_block[BLOCK_SIZE >> 2]; | |
383 | ||
384 | if (!badblocks) | |
385 | return; | |
386 | mark_inode (MINIX_BAD_INO); | |
387 | inode->i_nlinks = 1; | |
388 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
389 | inode->i_mode = S_IFREG + 0000; | |
390 | inode->i_size = badblocks * BLOCK_SIZE; | |
391 | zone = next (0); | |
392 | for (i = 0; i < 7; i++) { | |
393 | inode->i_zone[i] = zone; | |
394 | if (!NEXT_BAD) | |
395 | goto end_bad; | |
396 | } | |
397 | inode->i_zone[7] = ind = get_free_block (); | |
398 | memset (ind_block, 0, BLOCK_SIZE); | |
399 | for (i = 0; i < 256; i++) { | |
400 | ind_block[i] = zone; | |
401 | if (!NEXT_BAD) | |
402 | goto end_bad; | |
403 | } | |
404 | inode->i_zone[8] = dind = get_free_block (); | |
405 | memset (dind_block, 0, BLOCK_SIZE); | |
406 | for (i = 0; i < 256; i++) { | |
407 | write_block (ind, (char *) ind_block); | |
408 | dind_block[i] = ind = get_free_block (); | |
409 | memset (ind_block, 0, BLOCK_SIZE); | |
410 | for (j = 0; j < 256; j++) { | |
411 | ind_block[j] = zone; | |
412 | if (!NEXT_BAD) | |
413 | goto end_bad; | |
414 | } | |
415 | } | |
416 | /* Could make triple indirect block here */ | |
7eda085c | 417 | die (_("too many bad blocks")); |
fd6b7a7f KZ |
418 | end_bad: |
419 | if (ind) | |
420 | write_block (ind, (char *) ind_block); | |
421 | if (dind) | |
422 | write_block (dind, (char *) dind_block); | |
423 | } | |
424 | #endif | |
425 | ||
22853e4a KZ |
426 | static void |
427 | make_root_inode(void) { | |
6dbe3af9 KZ |
428 | struct minix_inode * inode = &Inode[MINIX_ROOT_INO]; |
429 | ||
430 | mark_inode(MINIX_ROOT_INO); | |
431 | inode->i_zone[0] = get_free_block(); | |
432 | inode->i_nlinks = 2; | |
433 | inode->i_time = time(NULL); | |
434 | if (badblocks) | |
435 | inode->i_size = 3*dirsize; | |
436 | else { | |
437 | root_block[2*dirsize] = '\0'; | |
438 | root_block[2*dirsize+1] = '\0'; | |
439 | inode->i_size = 2*dirsize; | |
440 | } | |
441 | inode->i_mode = S_IFDIR + 0755; | |
2b6fc908 KZ |
442 | inode->i_uid = getuid(); |
443 | if (inode->i_uid) | |
444 | inode->i_gid = getgid(); | |
6dbe3af9 KZ |
445 | write_block(inode->i_zone[0],root_block); |
446 | } | |
447 | ||
fd6b7a7f | 448 | #ifdef HAVE_MINIX2 |
22853e4a KZ |
449 | static void |
450 | make_root_inode2 (void) { | |
fd6b7a7f KZ |
451 | struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; |
452 | ||
453 | mark_inode (MINIX_ROOT_INO); | |
454 | inode->i_zone[0] = get_free_block (); | |
455 | inode->i_nlinks = 2; | |
456 | inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); | |
457 | if (badblocks) | |
458 | inode->i_size = 3 * dirsize; | |
459 | else { | |
460 | root_block[2 * dirsize] = '\0'; | |
461 | root_block[2 * dirsize + 1] = '\0'; | |
462 | inode->i_size = 2 * dirsize; | |
463 | } | |
464 | inode->i_mode = S_IFDIR + 0755; | |
2b6fc908 KZ |
465 | inode->i_uid = getuid(); |
466 | if (inode->i_uid) | |
467 | inode->i_gid = getgid(); | |
fd6b7a7f KZ |
468 | write_block (inode->i_zone[0], root_block); |
469 | } | |
470 | #endif | |
471 | ||
22853e4a KZ |
472 | static void |
473 | setup_tables(void) { | |
6dbe3af9 | 474 | int i; |
fd6b7a7f | 475 | unsigned long inodes; |
6dbe3af9 | 476 | |
6dbe3af9 | 477 | memset(super_block_buffer,0,BLOCK_SIZE); |
726f69e2 | 478 | memset(boot_block_buffer,0,512); |
6dbe3af9 KZ |
479 | MAGIC = magic; |
480 | ZONESIZE = 0; | |
fd6b7a7f | 481 | MAXSIZE = version2 ? 0x7fffffff : (7+512+512*512)*1024; |
6dbe3af9 | 482 | ZONES = BLOCKS; |
eb63b9b8 | 483 | |
6dbe3af9 KZ |
484 | /* some magic nrs: 1 inode / 3 blocks */ |
485 | if ( req_nr_inodes == 0 ) | |
fd6b7a7f | 486 | inodes = BLOCKS/3; |
6dbe3af9 | 487 | else |
fd6b7a7f | 488 | inodes = req_nr_inodes; |
2b6fc908 KZ |
489 | /* Round up inode count to fill block size */ |
490 | #ifdef HAVE_MINIX2 | |
491 | if (version2) | |
492 | inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & | |
493 | ~(MINIX2_INODES_PER_BLOCK - 1)); | |
494 | else | |
495 | #endif | |
496 | inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & | |
497 | ~(MINIX_INODES_PER_BLOCK - 1)); | |
fd6b7a7f KZ |
498 | if (inodes > 65535) |
499 | inodes = 65535; | |
500 | INODES = inodes; | |
2b6fc908 | 501 | IMAPS = UPPER(INODES + 1,BITS_PER_BLOCK); |
eb63b9b8 KZ |
502 | ZMAPS = UPPER(BLOCKS - (1+IMAPS+INODE_BLOCKS), BITS_PER_BLOCK+1); |
503 | /* The old code here | |
504 | * ZMAPS = 0; | |
505 | * while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK)) | |
506 | * ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK); | |
507 | * was no good, since it may loop. - aeb | |
508 | */ | |
6dbe3af9 | 509 | FIRSTZONE = NORM_FIRSTZONE; |
2b6fc908 KZ |
510 | inode_map = malloc(IMAPS * BLOCK_SIZE); |
511 | zone_map = malloc(ZMAPS * BLOCK_SIZE); | |
512 | if (!inode_map || !zone_map) | |
7eda085c | 513 | die(_("unable to allocate buffers for maps")); |
2b6fc908 KZ |
514 | memset(inode_map,0xff,IMAPS * BLOCK_SIZE); |
515 | memset(zone_map,0xff,ZMAPS * BLOCK_SIZE); | |
6dbe3af9 KZ |
516 | for (i = FIRSTZONE ; i<ZONES ; i++) |
517 | unmark_zone(i); | |
2b6fc908 | 518 | for (i = MINIX_ROOT_INO ; i<=INODES ; i++) |
6dbe3af9 KZ |
519 | unmark_inode(i); |
520 | inode_buffer = malloc(INODE_BUFFER_SIZE); | |
521 | if (!inode_buffer) | |
7eda085c | 522 | die(_("unable to allocate buffer for inodes")); |
6dbe3af9 | 523 | memset(inode_buffer,0,INODE_BUFFER_SIZE); |
7eda085c KZ |
524 | printf(_("%ld inodes\n"),INODES); |
525 | printf(_("%ld blocks\n"),ZONES); | |
526 | printf(_("Firstdatazone=%ld (%ld)\n"),FIRSTZONE,NORM_FIRSTZONE); | |
527 | printf(_("Zonesize=%d\n"),BLOCK_SIZE<<ZONESIZE); | |
528 | printf(_("Maxsize=%ld\n\n"),MAXSIZE); | |
6dbe3af9 KZ |
529 | } |
530 | ||
531 | /* | |
532 | * Perform a test of a block; return the number of | |
533 | * blocks readable/writeable. | |
534 | */ | |
22853e4a KZ |
535 | static long |
536 | do_check(char * buffer, int try, unsigned int current_block) { | |
6dbe3af9 KZ |
537 | long got; |
538 | ||
539 | /* Seek to the correct loc. */ | |
540 | if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != | |
66ee8158 KZ |
541 | current_block * BLOCK_SIZE ) { |
542 | die(_("seek failed during testing of blocks")); | |
6dbe3af9 KZ |
543 | } |
544 | ||
545 | ||
546 | /* Try the read */ | |
547 | got = read(DEV, buffer, try * BLOCK_SIZE); | |
548 | if (got < 0) got = 0; | |
549 | if (got & (BLOCK_SIZE - 1 )) { | |
7eda085c | 550 | printf(_("Weird values in do_check: probably bugs\n")); |
6dbe3af9 KZ |
551 | } |
552 | got /= BLOCK_SIZE; | |
553 | return got; | |
554 | } | |
555 | ||
556 | static unsigned int currently_testing = 0; | |
557 | ||
22853e4a KZ |
558 | static void |
559 | alarm_intr(int alnum) { | |
6dbe3af9 KZ |
560 | if (currently_testing >= ZONES) |
561 | return; | |
562 | signal(SIGALRM,alarm_intr); | |
563 | alarm(5); | |
564 | if (!currently_testing) | |
565 | return; | |
566 | printf("%d ...", currently_testing); | |
567 | fflush(stdout); | |
568 | } | |
569 | ||
22853e4a KZ |
570 | static void |
571 | check_blocks(void) { | |
6dbe3af9 KZ |
572 | int try,got; |
573 | static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; | |
574 | ||
575 | currently_testing=0; | |
576 | signal(SIGALRM,alarm_intr); | |
577 | alarm(5); | |
578 | while (currently_testing < ZONES) { | |
579 | if (lseek(DEV,currently_testing*BLOCK_SIZE,SEEK_SET) != | |
580 | currently_testing*BLOCK_SIZE) | |
7eda085c | 581 | die(_("seek failed in check_blocks")); |
6dbe3af9 KZ |
582 | try = TEST_BUFFER_BLOCKS; |
583 | if (currently_testing + try > ZONES) | |
584 | try = ZONES-currently_testing; | |
585 | got = do_check(buffer, try, currently_testing); | |
586 | currently_testing += got; | |
587 | if (got == try) | |
588 | continue; | |
589 | if (currently_testing < FIRSTZONE) | |
7eda085c | 590 | die(_("bad blocks before data-area: cannot make fs")); |
6dbe3af9 KZ |
591 | mark_zone(currently_testing); |
592 | badblocks++; | |
593 | currently_testing++; | |
594 | } | |
7eda085c KZ |
595 | if (badblocks > 1) |
596 | printf(_("%d bad blocks\n"), badblocks); | |
597 | else if (badblocks == 1) | |
598 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
599 | } |
600 | ||
22853e4a KZ |
601 | static void |
602 | get_list_blocks(char *filename) { | |
fd6b7a7f KZ |
603 | FILE *listfile; |
604 | unsigned long blockno; | |
605 | ||
606 | listfile=fopen(filename,"r"); | |
607 | if(listfile == (FILE *)NULL) { | |
7eda085c | 608 | die(_("can't open file of bad blocks")); |
fd6b7a7f KZ |
609 | } |
610 | while(!feof(listfile)) { | |
611 | fscanf(listfile,"%ld\n", &blockno); | |
612 | mark_zone(blockno); | |
613 | badblocks++; | |
614 | } | |
7eda085c KZ |
615 | if(badblocks > 1) |
616 | printf(_("%d bad blocks\n"), badblocks); | |
617 | else if (badblocks == 1) | |
618 | printf(_("one bad block\n")); | |
6dbe3af9 KZ |
619 | } |
620 | ||
22853e4a KZ |
621 | int |
622 | main(int argc, char ** argv) { | |
fd6b7a7f KZ |
623 | int i; |
624 | char * tmp; | |
625 | struct stat statbuf; | |
626 | char * listfile = NULL; | |
eb63b9b8 | 627 | char * p; |
fd6b7a7f KZ |
628 | |
629 | if (argc && *argv) | |
630 | program_name = *argv; | |
eb63b9b8 KZ |
631 | if ((p = strrchr(program_name, '/')) != NULL) |
632 | program_name = p+1; | |
633 | ||
634 | setlocale(LC_ALL, ""); | |
635 | bindtextdomain(PACKAGE, LOCALEDIR); | |
636 | textdomain(PACKAGE); | |
637 | ||
638 | if (argc == 2 && | |
639 | (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) { | |
640 | printf(_("%s from %s\n"), program_name, util_linux_version); | |
641 | exit(0); | |
642 | } | |
643 | ||
fd6b7a7f | 644 | if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) |
7eda085c | 645 | die(_("bad inode size")); |
fd6b7a7f KZ |
646 | #ifdef HAVE_MINIX2 |
647 | if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) | |
7eda085c | 648 | die(_("bad inode size")); |
fd6b7a7f | 649 | #endif |
7eda085c KZ |
650 | opterr = 0; |
651 | while ((i = getopt(argc, argv, "ci:l:n:v")) != EOF) | |
652 | switch (i) { | |
653 | case 'c': | |
654 | check=1; break; | |
655 | case 'i': | |
66ee8158 | 656 | req_nr_inodes = (unsigned long) atol(optarg); |
7eda085c KZ |
657 | break; |
658 | case 'l': | |
659 | listfile = optarg; break; | |
660 | case 'n': | |
661 | i = strtoul(optarg,&tmp,0); | |
662 | if (*tmp) | |
fd6b7a7f | 663 | usage(); |
7eda085c KZ |
664 | if (i == 14) |
665 | magic = MINIX_SUPER_MAGIC; | |
666 | else if (i == 30) | |
667 | magic = MINIX_SUPER_MAGIC2; | |
668 | else | |
fd6b7a7f | 669 | usage(); |
7eda085c KZ |
670 | namelen = i; |
671 | dirsize = i+2; | |
672 | break; | |
673 | case 'v': | |
fd6b7a7f | 674 | #ifdef HAVE_MINIX2 |
7eda085c | 675 | version2 = 1; |
fd6b7a7f | 676 | #else |
7eda085c | 677 | fatal_error(_("%s: not compiled with minix v2 support\n"),-1); |
fd6b7a7f | 678 | #endif |
7eda085c KZ |
679 | break; |
680 | default: | |
681 | usage(); | |
fd6b7a7f | 682 | } |
7eda085c KZ |
683 | argc -= optind; |
684 | argv += optind; | |
685 | if (argc > 0 && !device_name) { | |
686 | device_name = argv[0]; | |
687 | argc--; | |
688 | argv++; | |
689 | } | |
690 | if (argc > 0) { | |
691 | BLOCKS = strtol(argv[0],&tmp,0); | |
692 | if (*tmp) { | |
693 | printf(_("strtol error: number of blocks not specified")); | |
694 | usage(); | |
695 | } | |
fd6b7a7f | 696 | } |
7eda085c | 697 | |
fd6b7a7f KZ |
698 | if (device_name && !BLOCKS) |
699 | BLOCKS = get_size (device_name) / 1024; | |
700 | if (!device_name || BLOCKS<10) { | |
701 | usage(); | |
702 | } | |
703 | #ifdef HAVE_MINIX2 | |
704 | if (version2) { | |
705 | if (namelen == 14) | |
706 | magic = MINIX2_SUPER_MAGIC; | |
707 | else | |
708 | magic = MINIX2_SUPER_MAGIC2; | |
709 | } else | |
710 | #endif | |
711 | if (BLOCKS > 65535) | |
712 | BLOCKS = 65535; | |
713 | check_mount(); /* is it already mounted? */ | |
714 | tmp = root_block; | |
715 | *(short *)tmp = 1; | |
716 | strcpy(tmp+2,"."); | |
717 | tmp += dirsize; | |
718 | *(short *)tmp = 1; | |
719 | strcpy(tmp+2,".."); | |
720 | tmp += dirsize; | |
721 | *(short *)tmp = 2; | |
722 | strcpy(tmp+2,".badblocks"); | |
723 | DEV = open(device_name,O_RDWR ); | |
724 | if (DEV<0) | |
7eda085c | 725 | die(_("unable to open %s")); |
fd6b7a7f | 726 | if (fstat(DEV,&statbuf)<0) |
7eda085c | 727 | die(_("unable to stat %s")); |
fd6b7a7f KZ |
728 | if (!S_ISBLK(statbuf.st_mode)) |
729 | check=0; | |
730 | else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) | |
7eda085c | 731 | die(_("will not try to make filesystem on '%s'")); |
fd6b7a7f KZ |
732 | setup_tables(); |
733 | if (check) | |
734 | check_blocks(); | |
735 | else if (listfile) | |
736 | get_list_blocks(listfile); | |
737 | #ifdef HAVE_MINIX2 | |
738 | if (version2) { | |
739 | make_root_inode2 (); | |
740 | make_bad_inode2 (); | |
741 | } else | |
742 | #endif | |
743 | { | |
744 | make_root_inode(); | |
745 | make_bad_inode(); | |
746 | } | |
747 | mark_good_blocks(); | |
748 | write_tables(); | |
749 | return 0; | |
6dbe3af9 | 750 | } |