1 /* vi: set sw=4 ts=4: */
3 * mkfs.c - make a linux (minix) file-system.
5 * (C) 1991 Linus Torvalds.
7 * Licensed under GPLv2, see file LICENSE in this source tree.
13 * 24.11.91 - Time began. Used the fsck sources to get started.
15 * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
16 * The algorithm for ".badblocks" is a bit weird, but
17 * it should work. Oh, well.
19 * 25.01.92 - Added the -l option for getting the list of bad blocks
20 * out of a named file. (Dave Rivers, rivers@ponds.uucp)
22 * 28.02.92 - Added %-information when using -c.
24 * 28.02.93 - Added support for other namelengths than the original
25 * 14 characters so that I can test the new kernel routines..
27 * 09.10.93 - Make exit status conform to that required by fsutil
28 * (Rik Faith, faith@cs.unc.edu)
30 * 31.10.93 - Added inode request feature, for backup floppies: use
31 * 32 inodes, for a news partition use more.
32 * (Scott Heavner, sdh@po.cwru.edu)
34 * 03.01.94 - Added support for file system valid flag.
35 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
37 * 30.10.94 - added support for v2 filesystem
38 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
40 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
41 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
42 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
44 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
45 * the filesystem is not misidentified as a MS-DOS FAT filesystem.
46 * (Daniel Quinlan, quinlan@yggdrasil.com)
48 * 02.07.96 - Added small patch from Russell King to make the program a
49 * good deal more portable (janl@math.uio.no)
51 * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
53 * -c for readability checking (SLOW!)
54 * -l for getting a list of bad blocks from a file.
55 * -n for namelength (currently the kernel only uses 14 or 30)
56 * -i for number of inodes
57 * -v for v2 filesystem
59 * The device may be a block device or a image of one, but this isn't
60 * enforced (but it's not much fun on a character device :-).
62 * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
63 * removed getopt based parser and added a hand rolled one.
66 //usage:#define mkfs_minix_trivial_usage
67 //usage: "[-c | -l FILE] [-nXX] [-iXX] BLOCKDEV [KBYTES]"
68 //usage:#define mkfs_minix_full_usage "\n\n"
69 //usage: "Make a MINIX filesystem\n"
70 //usage: "\n -c Check device for bad blocks"
71 //usage: "\n -n [14|30] Maximum length of filenames"
72 //usage: "\n -i INODES Number of inodes for the filesystem"
73 //usage: "\n -l FILE Read bad blocks list from FILE"
74 //usage: "\n -v Make version 2 filesystem"
81 /* Store the very same times/uids/gids for image consistency */
87 /* Was using this. Is it useful? NB: this will break testsuite */
88 # define CUR_TIME time(NULL)
89 # define GETUID getuid()
90 # define GETGID getgid()
94 MAX_GOOD_BLOCKS
= 512,
95 TEST_BUFFER_BLOCKS
= 16,
98 #if !ENABLE_FEATURE_MINIX2
99 enum { version2
= 0 };
105 #if ENABLE_FEATURE_MINIX2
107 #define version2 G.version2
110 uint32_t total_blocks
;
118 int used_good_blocks
;
119 unsigned long req_nr_inodes
;
120 unsigned currently_testing
;
122 char root_block
[BLOCK_SIZE
];
123 char superblock_buffer
[BLOCK_SIZE
];
124 char boot_block_buffer
[512];
125 unsigned short good_blocks_table
[MAX_GOOD_BLOCKS
];
126 /* check_blocks(): buffer[] was the biggest static in entire bbox */
127 char check_blocks_buffer
[BLOCK_SIZE
* TEST_BUFFER_BLOCKS
];
129 unsigned short ind_block1
[BLOCK_SIZE
>> 1];
130 unsigned short dind_block1
[BLOCK_SIZE
>> 1];
131 unsigned long ind_block2
[BLOCK_SIZE
>> 2];
132 unsigned long dind_block2
[BLOCK_SIZE
>> 2];
134 #define G (*ptr_to_globals)
135 #define INIT_G() do { \
136 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
139 static ALWAYS_INLINE
unsigned div_roundup(unsigned size
, unsigned n
)
141 return (size
+ n
-1) / n
;
144 #define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
145 #define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
147 #define SB (*(struct minix_superblock*)G.superblock_buffer)
149 #define SB_INODES (SB.s_ninodes)
150 #define SB_IMAPS (SB.s_imap_blocks)
151 #define SB_ZMAPS (SB.s_zmap_blocks)
152 #define SB_FIRSTZONE (SB.s_firstdatazone)
153 #define SB_ZONE_SIZE (SB.s_log_zone_size)
154 #define SB_MAXSIZE (SB.s_max_size)
155 #define SB_MAGIC (SB.s_magic)
157 #if !ENABLE_FEATURE_MINIX2
158 # define SB_ZONES (SB.s_nzones)
159 # define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
161 # define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones)
162 # define INODE_BLOCKS div_roundup(SB_INODES, \
163 (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
166 #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
167 #define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
169 /* Before you ask "where they come from?": */
170 /* setbit/clrbit are supplied by sys/param.h */
172 static int minix_bit(const char* a
, unsigned i
)
174 return a
[i
>> 3] & (1<<(i
& 7));
177 static void minix_setbit(char *a
, unsigned i
)
181 static void minix_clrbit(char *a
, unsigned i
)
186 /* Note: do not assume 0/1, it is 0/nonzero */
187 #define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
188 /*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
190 #define mark_inode(x) minix_setbit(G.inode_map,(x))
191 #define unmark_inode(x) minix_clrbit(G.inode_map,(x))
192 #define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
193 #define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
196 # define BLKGETSIZE _IO(0x12,96) /* return device size */
200 static long valid_offset(int fd
, int offset
)
204 if (lseek(fd
, offset
, SEEK_SET
) < 0)
206 if (read(fd
, &ch
, 1) < 1)
211 static int count_blocks(int fd
)
216 for (high
= 1; valid_offset(fd
, high
); high
*= 2)
219 while (low
< high
- 1) {
220 const int mid
= (low
+ high
) / 2;
222 if (valid_offset(fd
, mid
))
231 static int get_size(const char *file
)
236 fd
= xopen(file
, O_RDWR
);
237 if (ioctl(fd
, BLKGETSIZE
, &size
) >= 0) {
242 size
= count_blocks(fd
);
247 static void write_tables(void)
249 /* Mark the superblock valid. */
250 SB
.s_state
|= MINIX_VALID_FS
;
251 SB
.s_state
&= ~MINIX_ERROR_FS
;
253 msg_eol
= "seek to 0 failed";
254 xlseek(dev_fd
, 0, SEEK_SET
);
256 msg_eol
= "can't clear boot sector";
257 xwrite(dev_fd
, G
.boot_block_buffer
, 512);
259 msg_eol
= "seek to BLOCK_SIZE failed";
260 xlseek(dev_fd
, BLOCK_SIZE
, SEEK_SET
);
262 msg_eol
= "can't write superblock";
263 xwrite(dev_fd
, G
.superblock_buffer
, BLOCK_SIZE
);
265 msg_eol
= "can't write inode map";
266 xwrite(dev_fd
, G
.inode_map
, SB_IMAPS
* BLOCK_SIZE
);
268 msg_eol
= "can't write zone map";
269 xwrite(dev_fd
, G
.zone_map
, SB_ZMAPS
* BLOCK_SIZE
);
271 msg_eol
= "can't write inodes";
272 xwrite(dev_fd
, G
.inode_buffer
, INODE_BUFFER_SIZE
);
277 static void write_block(int blk
, char *buffer
)
279 xlseek(dev_fd
, blk
* BLOCK_SIZE
, SEEK_SET
);
280 xwrite(dev_fd
, buffer
, BLOCK_SIZE
);
283 static int get_free_block(void)
287 if (G
.used_good_blocks
+ 1 >= MAX_GOOD_BLOCKS
)
288 bb_error_msg_and_die("too many bad blocks");
289 if (G
.used_good_blocks
)
290 blk
= G
.good_blocks_table
[G
.used_good_blocks
- 1] + 1;
293 while (blk
< SB_ZONES
&& zone_in_use(blk
))
296 bb_error_msg_and_die("not enough good blocks");
297 G
.good_blocks_table
[G
.used_good_blocks
] = blk
;
298 G
.used_good_blocks
++;
302 static void mark_good_blocks(void)
306 for (blk
= 0; blk
< G
.used_good_blocks
; blk
++)
307 mark_zone(G
.good_blocks_table
[blk
]);
310 static int next(int zone
)
313 zone
= SB_FIRSTZONE
- 1;
314 while (++zone
< SB_ZONES
)
315 if (zone_in_use(zone
))
320 static void make_bad_inode(void)
322 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_BAD_INO
];
324 int ind
= 0, dind
= 0;
325 /* moved to globals to reduce stack usage
326 unsigned short ind_block[BLOCK_SIZE >> 1];
327 unsigned short dind_block[BLOCK_SIZE >> 1];
329 #define ind_block (G.ind_block1)
330 #define dind_block (G.dind_block1)
332 #define NEXT_BAD (zone = next(zone))
336 mark_inode(MINIX_BAD_INO
);
338 /* BTW, setting this makes all images different */
339 /* it's harder to check for bugs then - diff isn't helpful :(... */
340 inode
->i_time
= CUR_TIME
;
341 inode
->i_mode
= S_IFREG
+ 0000;
342 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
344 for (i
= 0; i
< 7; i
++) {
345 inode
->i_zone
[i
] = zone
;
349 inode
->i_zone
[7] = ind
= get_free_block();
350 memset(ind_block
, 0, BLOCK_SIZE
);
351 for (i
= 0; i
< 512; i
++) {
356 inode
->i_zone
[8] = dind
= get_free_block();
357 memset(dind_block
, 0, BLOCK_SIZE
);
358 for (i
= 0; i
< 512; i
++) {
359 write_block(ind
, (char *) ind_block
);
360 dind_block
[i
] = ind
= get_free_block();
361 memset(ind_block
, 0, BLOCK_SIZE
);
362 for (j
= 0; j
< 512; j
++) {
368 bb_error_msg_and_die("too many bad blocks");
371 write_block(ind
, (char *) ind_block
);
373 write_block(dind
, (char *) dind_block
);
378 #if ENABLE_FEATURE_MINIX2
379 static void make_bad_inode2(void)
381 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_BAD_INO
];
383 int ind
= 0, dind
= 0;
384 /* moved to globals to reduce stack usage
385 unsigned long ind_block[BLOCK_SIZE >> 2];
386 unsigned long dind_block[BLOCK_SIZE >> 2];
388 #define ind_block (G.ind_block2)
389 #define dind_block (G.dind_block2)
393 mark_inode(MINIX_BAD_INO
);
395 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
396 inode
->i_mode
= S_IFREG
+ 0000;
397 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
399 for (i
= 0; i
< 7; i
++) {
400 inode
->i_zone
[i
] = zone
;
404 inode
->i_zone
[7] = ind
= get_free_block();
405 memset(ind_block
, 0, BLOCK_SIZE
);
406 for (i
= 0; i
< 256; i
++) {
411 inode
->i_zone
[8] = dind
= get_free_block();
412 memset(dind_block
, 0, BLOCK_SIZE
);
413 for (i
= 0; i
< 256; i
++) {
414 write_block(ind
, (char *) ind_block
);
415 dind_block
[i
] = ind
= get_free_block();
416 memset(ind_block
, 0, BLOCK_SIZE
);
417 for (j
= 0; j
< 256; j
++) {
423 /* Could make triple indirect block here */
424 bb_error_msg_and_die("too many bad blocks");
427 write_block(ind
, (char *) ind_block
);
429 write_block(dind
, (char *) dind_block
);
434 void make_bad_inode2(void);
437 static void make_root_inode(void)
439 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_ROOT_INO
];
441 mark_inode(MINIX_ROOT_INO
);
442 inode
->i_zone
[0] = get_free_block();
444 inode
->i_time
= CUR_TIME
;
446 inode
->i_size
= 3 * G
.dirsize
;
448 G
.root_block
[2 * G
.dirsize
] = '\0';
449 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
450 inode
->i_size
= 2 * G
.dirsize
;
452 inode
->i_mode
= S_IFDIR
+ 0755;
453 inode
->i_uid
= GETUID
;
455 inode
->i_gid
= GETGID
;
456 write_block(inode
->i_zone
[0], G
.root_block
);
459 #if ENABLE_FEATURE_MINIX2
460 static void make_root_inode2(void)
462 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_ROOT_INO
];
464 mark_inode(MINIX_ROOT_INO
);
465 inode
->i_zone
[0] = get_free_block();
467 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
469 inode
->i_size
= 3 * G
.dirsize
;
471 G
.root_block
[2 * G
.dirsize
] = '\0';
472 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
473 inode
->i_size
= 2 * G
.dirsize
;
475 inode
->i_mode
= S_IFDIR
+ 0755;
476 inode
->i_uid
= GETUID
;
478 inode
->i_gid
= GETGID
;
479 write_block(inode
->i_zone
[0], G
.root_block
);
482 void make_root_inode2(void);
486 * Perform a test of a block; return the number of
489 static size_t do_check(char *buffer
, size_t try, unsigned current_block
)
493 /* Seek to the correct loc. */
494 msg_eol
= "seek failed during testing of blocks";
495 xlseek(dev_fd
, current_block
* BLOCK_SIZE
, SEEK_SET
);
499 got
= read(dev_fd
, buffer
, try * BLOCK_SIZE
);
502 try = ((size_t)got
) / BLOCK_SIZE
;
504 if (got
& (BLOCK_SIZE
- 1))
505 fprintf(stderr
, "Short read at block %u\n", (unsigned)(current_block
+ try));
509 static void alarm_intr(int alnum UNUSED_PARAM
)
511 if (G
.currently_testing
>= SB_ZONES
)
513 signal(SIGALRM
, alarm_intr
);
515 if (!G
.currently_testing
)
517 printf("%d ...", G
.currently_testing
);
521 static void check_blocks(void)
525 G
.currently_testing
= 0;
526 signal(SIGALRM
, alarm_intr
);
528 while (G
.currently_testing
< SB_ZONES
) {
529 msg_eol
= "seek failed in check_blocks";
530 xlseek(dev_fd
, G
.currently_testing
* BLOCK_SIZE
, SEEK_SET
);
532 try = TEST_BUFFER_BLOCKS
;
533 if (G
.currently_testing
+ try > SB_ZONES
)
534 try = SB_ZONES
- G
.currently_testing
;
535 got
= do_check(G
.check_blocks_buffer
, try, G
.currently_testing
);
536 G
.currently_testing
+= got
;
539 if (G
.currently_testing
< SB_FIRSTZONE
)
540 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
541 mark_zone(G
.currently_testing
);
543 G
.currently_testing
++;
546 printf("%d bad block(s)\n", G
.badblocks
);
549 static void get_list_blocks(char *filename
)
552 unsigned long blockno
;
554 listfile
= xfopen_for_read(filename
);
555 while (!feof(listfile
)) {
556 fscanf(listfile
, "%ld\n", &blockno
);
560 printf("%d bad block(s)\n", G
.badblocks
);
563 static void setup_tables(void)
565 unsigned long inodes
;
566 unsigned norm_firstzone
;
570 /* memset(G.superblock_buffer, 0, BLOCK_SIZE); */
571 /* memset(G.boot_block_buffer, 0, 512); */
574 SB_MAXSIZE
= version2
? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
576 SB
.s_zones
= G
.total_blocks
;
578 SB
.s_nzones
= G
.total_blocks
;
580 /* some magic nrs: 1 inode / 3 blocks */
581 if (G
.req_nr_inodes
== 0)
582 inodes
= G
.total_blocks
/ 3;
584 inodes
= G
.req_nr_inodes
;
585 /* Round up inode count to fill block size */
587 inodes
= (inodes
+ MINIX2_INODES_PER_BLOCK
- 1) &
588 ~(MINIX2_INODES_PER_BLOCK
- 1);
590 inodes
= (inodes
+ MINIX1_INODES_PER_BLOCK
- 1) &
591 ~(MINIX1_INODES_PER_BLOCK
- 1);
595 SB_IMAPS
= div_roundup(SB_INODES
+ 1, BITS_PER_BLOCK
);
597 /* Real bad hack but overwise mkfs.minix can be thrown
598 * in infinite loop...
600 * dd if=/dev/zero of=test.fs count=10 bs=1024
601 * mkfs.minix -i 200 test.fs
603 /* This code is not insane: NORM_FIRSTZONE is not a constant,
604 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
608 norm_firstzone
= NORM_FIRSTZONE
;
609 sb_zmaps
= div_roundup(G
.total_blocks
- norm_firstzone
+ 1, BITS_PER_BLOCK
);
610 if (SB_ZMAPS
== sb_zmaps
) goto got_it
;
612 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
614 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
617 SB_FIRSTZONE
= norm_firstzone
;
618 G
.inode_map
= xmalloc(SB_IMAPS
* BLOCK_SIZE
);
619 G
.zone_map
= xmalloc(SB_ZMAPS
* BLOCK_SIZE
);
620 memset(G
.inode_map
, 0xff, SB_IMAPS
* BLOCK_SIZE
);
621 memset(G
.zone_map
, 0xff, SB_ZMAPS
* BLOCK_SIZE
);
622 for (i
= SB_FIRSTZONE
; i
< SB_ZONES
; i
++)
624 for (i
= MINIX_ROOT_INO
; i
<= SB_INODES
; i
++)
626 G
.inode_buffer
= xzalloc(INODE_BUFFER_SIZE
);
627 printf("%ld inodes\n", (long)SB_INODES
);
628 printf("%ld blocks\n", (long)SB_ZONES
);
629 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE
, (long)norm_firstzone
);
630 printf("Zonesize=%d\n", BLOCK_SIZE
<< SB_ZONE_SIZE
);
631 printf("Maxsize=%ld\n", (long)SB_MAXSIZE
);
634 int mkfs_minix_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
635 int mkfs_minix_main(int argc UNUSED_PARAM
, char **argv
)
641 char *listfile
= NULL
;
644 /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
647 G
.magic
= MINIX1_SUPER_MAGIC2
;
649 if (INODE_SIZE1
* MINIX1_INODES_PER_BLOCK
!= BLOCK_SIZE
)
650 bb_error_msg_and_die("bad inode size");
651 #if ENABLE_FEATURE_MINIX2
652 if (INODE_SIZE2
* MINIX2_INODES_PER_BLOCK
!= BLOCK_SIZE
)
653 bb_error_msg_and_die("bad inode size");
656 opt_complementary
= "n+"; /* -n N */
657 opt
= getopt32(argv
, "ci:l:n:v", &str_i
, &listfile
, &G
.namelen
);
660 if (opt
& 2) G
.req_nr_inodes
= xatoul(str_i
); // -i
663 if (G
.namelen
== 14) G
.magic
= MINIX1_SUPER_MAGIC
;
664 else if (G
.namelen
== 30) G
.magic
= MINIX1_SUPER_MAGIC2
;
665 else bb_show_usage();
666 G
.dirsize
= G
.namelen
+ 2;
668 if (opt
& 0x10) { // -v
669 #if ENABLE_FEATURE_MINIX2
672 bb_error_msg_and_die("not compiled with minix v2 support");
676 G
.device_name
= *argv
++;
680 G
.total_blocks
= xatou32(*argv
);
682 G
.total_blocks
= get_size(G
.device_name
) / 1024;
684 if (G
.total_blocks
< 10)
685 bb_error_msg_and_die("must have at least 10 blocks");
688 G
.magic
= MINIX2_SUPER_MAGIC2
;
690 G
.magic
= MINIX2_SUPER_MAGIC
;
691 } else if (G
.total_blocks
> 65535)
692 G
.total_blocks
= 65535;
694 /* Check if it is mounted */
695 if (find_mount_point(G
.device_name
, 0))
696 bb_error_msg_and_die("can't format mounted filesystem");
698 xmove_fd(xopen(G
.device_name
, O_RDWR
), dev_fd
);
699 xfstat(dev_fd
, &statbuf
, G
.device_name
);
700 if (!S_ISBLK(statbuf
.st_mode
))
701 opt
&= ~1; // clear -c (check)
703 /* I don't know why someone has special code to prevent mkfs.minix
704 * on IDE devices. Why IDE but not SCSI, etc?... */
706 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340)
708 bb_error_msg_and_die("will not try "
709 "to make filesystem on '%s'", G
.device_name
);
714 strcpy(tmp
+ 2, ".");
717 strcpy(tmp
+ 2, "..");
720 strcpy(tmp
+ 2, ".badblocks");
727 get_list_blocks(listfile
);