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.
71 /* Store the very same times/uids/gids for image consistency */
77 /* Was using this. Is it useful? NB: this will break testsuite */
78 # define CUR_TIME time(NULL)
79 # define GETUID getuid()
80 # define GETGID getgid()
84 MAX_GOOD_BLOCKS
= 512,
85 TEST_BUFFER_BLOCKS
= 16,
88 #if !ENABLE_FEATURE_MINIX2
89 enum { version2
= 0 };
95 #if ENABLE_FEATURE_MINIX2
97 #define version2 G.version2
100 uint32_t total_blocks
;
108 int used_good_blocks
;
109 unsigned long req_nr_inodes
;
110 unsigned currently_testing
;
112 char root_block
[BLOCK_SIZE
];
113 char superblock_buffer
[BLOCK_SIZE
];
114 char boot_block_buffer
[512];
115 unsigned short good_blocks_table
[MAX_GOOD_BLOCKS
];
116 /* check_blocks(): buffer[] was the biggest static in entire bbox */
117 char check_blocks_buffer
[BLOCK_SIZE
* TEST_BUFFER_BLOCKS
];
119 unsigned short ind_block1
[BLOCK_SIZE
>> 1];
120 unsigned short dind_block1
[BLOCK_SIZE
>> 1];
121 unsigned long ind_block2
[BLOCK_SIZE
>> 2];
122 unsigned long dind_block2
[BLOCK_SIZE
>> 2];
124 #define G (*ptr_to_globals)
125 #define INIT_G() do { \
126 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
129 static ALWAYS_INLINE
unsigned div_roundup(unsigned size
, unsigned n
)
131 return (size
+ n
-1) / n
;
134 #define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
135 #define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
137 #define SB (*(struct minix_superblock*)G.superblock_buffer)
139 #define SB_INODES (SB.s_ninodes)
140 #define SB_IMAPS (SB.s_imap_blocks)
141 #define SB_ZMAPS (SB.s_zmap_blocks)
142 #define SB_FIRSTZONE (SB.s_firstdatazone)
143 #define SB_ZONE_SIZE (SB.s_log_zone_size)
144 #define SB_MAXSIZE (SB.s_max_size)
145 #define SB_MAGIC (SB.s_magic)
147 #if !ENABLE_FEATURE_MINIX2
148 # define SB_ZONES (SB.s_nzones)
149 # define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
151 # define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones)
152 # define INODE_BLOCKS div_roundup(SB_INODES, \
153 (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
156 #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
157 #define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
159 /* Before you ask "where they come from?": */
160 /* setbit/clrbit are supplied by sys/param.h */
162 static int minix_bit(const char* a
, unsigned i
)
164 return a
[i
>> 3] & (1<<(i
& 7));
167 static void minix_setbit(char *a
, unsigned i
)
171 static void minix_clrbit(char *a
, unsigned i
)
176 /* Note: do not assume 0/1, it is 0/nonzero */
177 #define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
178 /*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
180 #define mark_inode(x) minix_setbit(G.inode_map,(x))
181 #define unmark_inode(x) minix_clrbit(G.inode_map,(x))
182 #define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
183 #define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
186 # define BLKGETSIZE _IO(0x12,96) /* return device size */
190 static long valid_offset(int fd
, int offset
)
194 if (lseek(fd
, offset
, SEEK_SET
) < 0)
196 if (read(fd
, &ch
, 1) < 1)
201 static int count_blocks(int fd
)
206 for (high
= 1; valid_offset(fd
, high
); high
*= 2)
209 while (low
< high
- 1) {
210 const int mid
= (low
+ high
) / 2;
212 if (valid_offset(fd
, mid
))
221 static int get_size(const char *file
)
226 fd
= xopen(file
, O_RDWR
);
227 if (ioctl(fd
, BLKGETSIZE
, &size
) >= 0) {
232 size
= count_blocks(fd
);
237 static void write_tables(void)
239 /* Mark the superblock valid. */
240 SB
.s_state
|= MINIX_VALID_FS
;
241 SB
.s_state
&= ~MINIX_ERROR_FS
;
243 msg_eol
= "seek to 0 failed";
244 xlseek(dev_fd
, 0, SEEK_SET
);
246 msg_eol
= "can't clear boot sector";
247 xwrite(dev_fd
, G
.boot_block_buffer
, 512);
249 msg_eol
= "seek to BLOCK_SIZE failed";
250 xlseek(dev_fd
, BLOCK_SIZE
, SEEK_SET
);
252 msg_eol
= "can't write superblock";
253 xwrite(dev_fd
, G
.superblock_buffer
, BLOCK_SIZE
);
255 msg_eol
= "can't write inode map";
256 xwrite(dev_fd
, G
.inode_map
, SB_IMAPS
* BLOCK_SIZE
);
258 msg_eol
= "can't write zone map";
259 xwrite(dev_fd
, G
.zone_map
, SB_ZMAPS
* BLOCK_SIZE
);
261 msg_eol
= "can't write inodes";
262 xwrite(dev_fd
, G
.inode_buffer
, INODE_BUFFER_SIZE
);
267 static void write_block(int blk
, char *buffer
)
269 xlseek(dev_fd
, blk
* BLOCK_SIZE
, SEEK_SET
);
270 xwrite(dev_fd
, buffer
, BLOCK_SIZE
);
273 static int get_free_block(void)
277 if (G
.used_good_blocks
+ 1 >= MAX_GOOD_BLOCKS
)
278 bb_error_msg_and_die("too many bad blocks");
279 if (G
.used_good_blocks
)
280 blk
= G
.good_blocks_table
[G
.used_good_blocks
- 1] + 1;
283 while (blk
< SB_ZONES
&& zone_in_use(blk
))
286 bb_error_msg_and_die("not enough good blocks");
287 G
.good_blocks_table
[G
.used_good_blocks
] = blk
;
288 G
.used_good_blocks
++;
292 static void mark_good_blocks(void)
296 for (blk
= 0; blk
< G
.used_good_blocks
; blk
++)
297 mark_zone(G
.good_blocks_table
[blk
]);
300 static int next(int zone
)
303 zone
= SB_FIRSTZONE
- 1;
304 while (++zone
< SB_ZONES
)
305 if (zone_in_use(zone
))
310 static void make_bad_inode(void)
312 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_BAD_INO
];
314 int ind
= 0, dind
= 0;
315 /* moved to globals to reduce stack usage
316 unsigned short ind_block[BLOCK_SIZE >> 1];
317 unsigned short dind_block[BLOCK_SIZE >> 1];
319 #define ind_block (G.ind_block1)
320 #define dind_block (G.dind_block1)
322 #define NEXT_BAD (zone = next(zone))
326 mark_inode(MINIX_BAD_INO
);
328 /* BTW, setting this makes all images different */
329 /* it's harder to check for bugs then - diff isn't helpful :(... */
330 inode
->i_time
= CUR_TIME
;
331 inode
->i_mode
= S_IFREG
+ 0000;
332 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
334 for (i
= 0; i
< 7; i
++) {
335 inode
->i_zone
[i
] = zone
;
339 inode
->i_zone
[7] = ind
= get_free_block();
340 memset(ind_block
, 0, BLOCK_SIZE
);
341 for (i
= 0; i
< 512; i
++) {
346 inode
->i_zone
[8] = dind
= get_free_block();
347 memset(dind_block
, 0, BLOCK_SIZE
);
348 for (i
= 0; i
< 512; i
++) {
349 write_block(ind
, (char *) ind_block
);
350 dind_block
[i
] = ind
= get_free_block();
351 memset(ind_block
, 0, BLOCK_SIZE
);
352 for (j
= 0; j
< 512; j
++) {
358 bb_error_msg_and_die("too many bad blocks");
361 write_block(ind
, (char *) ind_block
);
363 write_block(dind
, (char *) dind_block
);
368 #if ENABLE_FEATURE_MINIX2
369 static void make_bad_inode2(void)
371 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_BAD_INO
];
373 int ind
= 0, dind
= 0;
374 /* moved to globals to reduce stack usage
375 unsigned long ind_block[BLOCK_SIZE >> 2];
376 unsigned long dind_block[BLOCK_SIZE >> 2];
378 #define ind_block (G.ind_block2)
379 #define dind_block (G.dind_block2)
383 mark_inode(MINIX_BAD_INO
);
385 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
386 inode
->i_mode
= S_IFREG
+ 0000;
387 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
389 for (i
= 0; i
< 7; i
++) {
390 inode
->i_zone
[i
] = zone
;
394 inode
->i_zone
[7] = ind
= get_free_block();
395 memset(ind_block
, 0, BLOCK_SIZE
);
396 for (i
= 0; i
< 256; i
++) {
401 inode
->i_zone
[8] = dind
= get_free_block();
402 memset(dind_block
, 0, BLOCK_SIZE
);
403 for (i
= 0; i
< 256; i
++) {
404 write_block(ind
, (char *) ind_block
);
405 dind_block
[i
] = ind
= get_free_block();
406 memset(ind_block
, 0, BLOCK_SIZE
);
407 for (j
= 0; j
< 256; j
++) {
413 /* Could make triple indirect block here */
414 bb_error_msg_and_die("too many bad blocks");
417 write_block(ind
, (char *) ind_block
);
419 write_block(dind
, (char *) dind_block
);
424 void make_bad_inode2(void);
427 static void make_root_inode(void)
429 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_ROOT_INO
];
431 mark_inode(MINIX_ROOT_INO
);
432 inode
->i_zone
[0] = get_free_block();
434 inode
->i_time
= CUR_TIME
;
436 inode
->i_size
= 3 * G
.dirsize
;
438 G
.root_block
[2 * G
.dirsize
] = '\0';
439 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
440 inode
->i_size
= 2 * G
.dirsize
;
442 inode
->i_mode
= S_IFDIR
+ 0755;
443 inode
->i_uid
= GETUID
;
445 inode
->i_gid
= GETGID
;
446 write_block(inode
->i_zone
[0], G
.root_block
);
449 #if ENABLE_FEATURE_MINIX2
450 static void make_root_inode2(void)
452 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_ROOT_INO
];
454 mark_inode(MINIX_ROOT_INO
);
455 inode
->i_zone
[0] = get_free_block();
457 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
459 inode
->i_size
= 3 * G
.dirsize
;
461 G
.root_block
[2 * G
.dirsize
] = '\0';
462 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
463 inode
->i_size
= 2 * G
.dirsize
;
465 inode
->i_mode
= S_IFDIR
+ 0755;
466 inode
->i_uid
= GETUID
;
468 inode
->i_gid
= GETGID
;
469 write_block(inode
->i_zone
[0], G
.root_block
);
472 void make_root_inode2(void);
476 * Perform a test of a block; return the number of
479 static size_t do_check(char *buffer
, size_t try, unsigned current_block
)
483 /* Seek to the correct loc. */
484 msg_eol
= "seek failed during testing of blocks";
485 xlseek(dev_fd
, current_block
* BLOCK_SIZE
, SEEK_SET
);
489 got
= read(dev_fd
, buffer
, try * BLOCK_SIZE
);
492 try = ((size_t)got
) / BLOCK_SIZE
;
494 if (got
& (BLOCK_SIZE
- 1))
495 fprintf(stderr
, "Short read at block %u\n", (unsigned)(current_block
+ try));
499 static void alarm_intr(int alnum UNUSED_PARAM
)
501 if (G
.currently_testing
>= SB_ZONES
)
503 signal(SIGALRM
, alarm_intr
);
505 if (!G
.currently_testing
)
507 printf("%d ...", G
.currently_testing
);
511 static void check_blocks(void)
515 G
.currently_testing
= 0;
516 signal(SIGALRM
, alarm_intr
);
518 while (G
.currently_testing
< SB_ZONES
) {
519 msg_eol
= "seek failed in check_blocks";
520 xlseek(dev_fd
, G
.currently_testing
* BLOCK_SIZE
, SEEK_SET
);
522 try = TEST_BUFFER_BLOCKS
;
523 if (G
.currently_testing
+ try > SB_ZONES
)
524 try = SB_ZONES
- G
.currently_testing
;
525 got
= do_check(G
.check_blocks_buffer
, try, G
.currently_testing
);
526 G
.currently_testing
+= got
;
529 if (G
.currently_testing
< SB_FIRSTZONE
)
530 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
531 mark_zone(G
.currently_testing
);
533 G
.currently_testing
++;
536 printf("%d bad block(s)\n", G
.badblocks
);
539 static void get_list_blocks(char *filename
)
542 unsigned long blockno
;
544 listfile
= xfopen_for_read(filename
);
545 while (!feof(listfile
)) {
546 fscanf(listfile
, "%ld\n", &blockno
);
550 printf("%d bad block(s)\n", G
.badblocks
);
553 static void setup_tables(void)
555 unsigned long inodes
;
556 unsigned norm_firstzone
;
560 /* memset(G.superblock_buffer, 0, BLOCK_SIZE); */
561 /* memset(G.boot_block_buffer, 0, 512); */
564 SB_MAXSIZE
= version2
? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
566 SB
.s_zones
= G
.total_blocks
;
568 SB
.s_nzones
= G
.total_blocks
;
570 /* some magic nrs: 1 inode / 3 blocks */
571 if (G
.req_nr_inodes
== 0)
572 inodes
= G
.total_blocks
/ 3;
574 inodes
= G
.req_nr_inodes
;
575 /* Round up inode count to fill block size */
577 inodes
= (inodes
+ MINIX2_INODES_PER_BLOCK
- 1) &
578 ~(MINIX2_INODES_PER_BLOCK
- 1);
580 inodes
= (inodes
+ MINIX1_INODES_PER_BLOCK
- 1) &
581 ~(MINIX1_INODES_PER_BLOCK
- 1);
585 SB_IMAPS
= div_roundup(SB_INODES
+ 1, BITS_PER_BLOCK
);
587 /* Real bad hack but overwise mkfs.minix can be thrown
588 * in infinite loop...
590 * dd if=/dev/zero of=test.fs count=10 bs=1024
591 * mkfs.minix -i 200 test.fs
593 /* This code is not insane: NORM_FIRSTZONE is not a constant,
594 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
598 norm_firstzone
= NORM_FIRSTZONE
;
599 sb_zmaps
= div_roundup(G
.total_blocks
- norm_firstzone
+ 1, BITS_PER_BLOCK
);
600 if (SB_ZMAPS
== sb_zmaps
) goto got_it
;
602 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
604 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
607 SB_FIRSTZONE
= norm_firstzone
;
608 G
.inode_map
= xmalloc(SB_IMAPS
* BLOCK_SIZE
);
609 G
.zone_map
= xmalloc(SB_ZMAPS
* BLOCK_SIZE
);
610 memset(G
.inode_map
, 0xff, SB_IMAPS
* BLOCK_SIZE
);
611 memset(G
.zone_map
, 0xff, SB_ZMAPS
* BLOCK_SIZE
);
612 for (i
= SB_FIRSTZONE
; i
< SB_ZONES
; i
++)
614 for (i
= MINIX_ROOT_INO
; i
<= SB_INODES
; i
++)
616 G
.inode_buffer
= xzalloc(INODE_BUFFER_SIZE
);
617 printf("%ld inodes\n", (long)SB_INODES
);
618 printf("%ld blocks\n", (long)SB_ZONES
);
619 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE
, (long)norm_firstzone
);
620 printf("Zonesize=%d\n", BLOCK_SIZE
<< SB_ZONE_SIZE
);
621 printf("Maxsize=%ld\n", (long)SB_MAXSIZE
);
624 int mkfs_minix_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
625 int mkfs_minix_main(int argc UNUSED_PARAM
, char **argv
)
631 char *listfile
= NULL
;
634 /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
637 G
.magic
= MINIX1_SUPER_MAGIC2
;
639 if (INODE_SIZE1
* MINIX1_INODES_PER_BLOCK
!= BLOCK_SIZE
)
640 bb_error_msg_and_die("bad inode size");
641 #if ENABLE_FEATURE_MINIX2
642 if (INODE_SIZE2
* MINIX2_INODES_PER_BLOCK
!= BLOCK_SIZE
)
643 bb_error_msg_and_die("bad inode size");
646 opt_complementary
= "n+"; /* -n N */
647 opt
= getopt32(argv
, "ci:l:n:v", &str_i
, &listfile
, &G
.namelen
);
650 if (opt
& 2) G
.req_nr_inodes
= xatoul(str_i
); // -i
653 if (G
.namelen
== 14) G
.magic
= MINIX1_SUPER_MAGIC
;
654 else if (G
.namelen
== 30) G
.magic
= MINIX1_SUPER_MAGIC2
;
655 else bb_show_usage();
656 G
.dirsize
= G
.namelen
+ 2;
658 if (opt
& 0x10) { // -v
659 #if ENABLE_FEATURE_MINIX2
662 bb_error_msg_and_die("not compiled with minix v2 support");
666 G
.device_name
= *argv
++;
670 G
.total_blocks
= xatou32(*argv
);
672 G
.total_blocks
= get_size(G
.device_name
) / 1024;
674 if (G
.total_blocks
< 10)
675 bb_error_msg_and_die("must have at least 10 blocks");
678 G
.magic
= MINIX2_SUPER_MAGIC2
;
680 G
.magic
= MINIX2_SUPER_MAGIC
;
681 } else if (G
.total_blocks
> 65535)
682 G
.total_blocks
= 65535;
684 /* Check if it is mounted */
685 if (find_mount_point(G
.device_name
, 0))
686 bb_error_msg_and_die("can't format mounted filesystem");
688 xmove_fd(xopen(G
.device_name
, O_RDWR
), dev_fd
);
689 xfstat(dev_fd
, &statbuf
, G
.device_name
);
690 if (!S_ISBLK(statbuf
.st_mode
))
691 opt
&= ~1; // clear -c (check)
693 /* I don't know why someone has special code to prevent mkfs.minix
694 * on IDE devices. Why IDE but not SCSI, etc?... */
696 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340)
698 bb_error_msg_and_die("will not try "
699 "to make filesystem on '%s'", G
.device_name
);
704 strcpy(tmp
+ 2, ".");
707 strcpy(tmp
+ 2, "..");
710 strcpy(tmp
+ 2, ".badblocks");
717 get_list_blocks(listfile
);