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