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 */
199 static void write_tables(void)
201 /* Mark the superblock valid. */
202 SB
.s_state
|= MINIX_VALID_FS
;
203 SB
.s_state
&= ~MINIX_ERROR_FS
;
205 msg_eol
= "seek to 0 failed";
206 xlseek(dev_fd
, 0, SEEK_SET
);
208 msg_eol
= "can't clear boot sector";
209 xwrite(dev_fd
, G
.boot_block_buffer
, 512);
211 msg_eol
= "seek to BLOCK_SIZE failed";
212 xlseek(dev_fd
, BLOCK_SIZE
, SEEK_SET
);
214 msg_eol
= "can't write superblock";
215 xwrite(dev_fd
, G
.superblock_buffer
, BLOCK_SIZE
);
217 msg_eol
= "can't write inode map";
218 xwrite(dev_fd
, G
.inode_map
, SB_IMAPS
* BLOCK_SIZE
);
220 msg_eol
= "can't write zone map";
221 xwrite(dev_fd
, G
.zone_map
, SB_ZMAPS
* BLOCK_SIZE
);
223 msg_eol
= "can't write inodes";
224 xwrite(dev_fd
, G
.inode_buffer
, INODE_BUFFER_SIZE
);
229 static void write_block(int blk
, char *buffer
)
231 xlseek(dev_fd
, blk
* BLOCK_SIZE
, SEEK_SET
);
232 xwrite(dev_fd
, buffer
, BLOCK_SIZE
);
235 static int get_free_block(void)
239 if (G
.used_good_blocks
+ 1 >= MAX_GOOD_BLOCKS
)
240 bb_error_msg_and_die("too many bad blocks");
241 if (G
.used_good_blocks
)
242 blk
= G
.good_blocks_table
[G
.used_good_blocks
- 1] + 1;
245 while (blk
< SB_ZONES
&& zone_in_use(blk
))
248 bb_error_msg_and_die("not enough good blocks");
249 G
.good_blocks_table
[G
.used_good_blocks
] = blk
;
250 G
.used_good_blocks
++;
254 static void mark_good_blocks(void)
258 for (blk
= 0; blk
< G
.used_good_blocks
; blk
++)
259 mark_zone(G
.good_blocks_table
[blk
]);
262 static int next(int zone
)
265 zone
= SB_FIRSTZONE
- 1;
266 while (++zone
< SB_ZONES
)
267 if (zone_in_use(zone
))
272 static void make_bad_inode(void)
274 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_BAD_INO
];
276 int ind
= 0, dind
= 0;
277 /* moved to globals to reduce stack usage
278 unsigned short ind_block[BLOCK_SIZE >> 1];
279 unsigned short dind_block[BLOCK_SIZE >> 1];
281 #define ind_block (G.ind_block1)
282 #define dind_block (G.dind_block1)
284 #define NEXT_BAD (zone = next(zone))
288 mark_inode(MINIX_BAD_INO
);
290 /* BTW, setting this makes all images different */
291 /* it's harder to check for bugs then - diff isn't helpful :(... */
292 inode
->i_time
= CUR_TIME
;
293 inode
->i_mode
= S_IFREG
+ 0000;
294 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
296 for (i
= 0; i
< 7; i
++) {
297 inode
->i_zone
[i
] = zone
;
301 inode
->i_zone
[7] = ind
= get_free_block();
302 memset(ind_block
, 0, BLOCK_SIZE
);
303 for (i
= 0; i
< 512; i
++) {
308 inode
->i_zone
[8] = dind
= get_free_block();
309 memset(dind_block
, 0, BLOCK_SIZE
);
310 for (i
= 0; i
< 512; i
++) {
311 write_block(ind
, (char *) ind_block
);
312 dind_block
[i
] = ind
= get_free_block();
313 memset(ind_block
, 0, BLOCK_SIZE
);
314 for (j
= 0; j
< 512; j
++) {
320 bb_error_msg_and_die("too many bad blocks");
323 write_block(ind
, (char *) ind_block
);
325 write_block(dind
, (char *) dind_block
);
330 #if ENABLE_FEATURE_MINIX2
331 static void make_bad_inode2(void)
333 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_BAD_INO
];
335 int ind
= 0, dind
= 0;
336 /* moved to globals to reduce stack usage
337 unsigned long ind_block[BLOCK_SIZE >> 2];
338 unsigned long dind_block[BLOCK_SIZE >> 2];
340 #define ind_block (G.ind_block2)
341 #define dind_block (G.dind_block2)
345 mark_inode(MINIX_BAD_INO
);
347 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
348 inode
->i_mode
= S_IFREG
+ 0000;
349 inode
->i_size
= G
.badblocks
* BLOCK_SIZE
;
351 for (i
= 0; i
< 7; i
++) {
352 inode
->i_zone
[i
] = zone
;
356 inode
->i_zone
[7] = ind
= get_free_block();
357 memset(ind_block
, 0, BLOCK_SIZE
);
358 for (i
= 0; i
< 256; i
++) {
363 inode
->i_zone
[8] = dind
= get_free_block();
364 memset(dind_block
, 0, BLOCK_SIZE
);
365 for (i
= 0; i
< 256; i
++) {
366 write_block(ind
, (char *) ind_block
);
367 dind_block
[i
] = ind
= get_free_block();
368 memset(ind_block
, 0, BLOCK_SIZE
);
369 for (j
= 0; j
< 256; j
++) {
375 /* Could make triple indirect block here */
376 bb_error_msg_and_die("too many bad blocks");
379 write_block(ind
, (char *) ind_block
);
381 write_block(dind
, (char *) dind_block
);
386 void make_bad_inode2(void);
389 static void make_root_inode(void)
391 struct minix1_inode
*inode
= &INODE_BUF1
[MINIX_ROOT_INO
];
393 mark_inode(MINIX_ROOT_INO
);
394 inode
->i_zone
[0] = get_free_block();
396 inode
->i_time
= CUR_TIME
;
398 inode
->i_size
= 3 * G
.dirsize
;
400 G
.root_block
[2 * G
.dirsize
] = '\0';
401 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
402 inode
->i_size
= 2 * G
.dirsize
;
404 inode
->i_mode
= S_IFDIR
+ 0755;
405 inode
->i_uid
= GETUID
;
407 inode
->i_gid
= GETGID
;
408 write_block(inode
->i_zone
[0], G
.root_block
);
411 #if ENABLE_FEATURE_MINIX2
412 static void make_root_inode2(void)
414 struct minix2_inode
*inode
= &INODE_BUF2
[MINIX_ROOT_INO
];
416 mark_inode(MINIX_ROOT_INO
);
417 inode
->i_zone
[0] = get_free_block();
419 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CUR_TIME
;
421 inode
->i_size
= 3 * G
.dirsize
;
423 G
.root_block
[2 * G
.dirsize
] = '\0';
424 G
.root_block
[2 * G
.dirsize
+ 1] = '\0';
425 inode
->i_size
= 2 * G
.dirsize
;
427 inode
->i_mode
= S_IFDIR
+ 0755;
428 inode
->i_uid
= GETUID
;
430 inode
->i_gid
= GETGID
;
431 write_block(inode
->i_zone
[0], G
.root_block
);
434 void make_root_inode2(void);
438 * Perform a test of a block; return the number of
441 static size_t do_check(char *buffer
, size_t try, unsigned current_block
)
445 /* Seek to the correct loc. */
446 msg_eol
= "seek failed during testing of blocks";
447 xlseek(dev_fd
, current_block
* BLOCK_SIZE
, SEEK_SET
);
451 got
= read(dev_fd
, buffer
, try * BLOCK_SIZE
);
454 try = ((size_t)got
) / BLOCK_SIZE
;
456 if (got
& (BLOCK_SIZE
- 1))
457 fprintf(stderr
, "Short read at block %u\n", (unsigned)(current_block
+ try));
461 static void alarm_intr(int alnum UNUSED_PARAM
)
463 if (G
.currently_testing
>= SB_ZONES
)
465 signal(SIGALRM
, alarm_intr
);
467 if (!G
.currently_testing
)
469 printf("%d ...", G
.currently_testing
);
473 static void check_blocks(void)
477 G
.currently_testing
= 0;
478 signal(SIGALRM
, alarm_intr
);
480 while (G
.currently_testing
< SB_ZONES
) {
481 msg_eol
= "seek failed in check_blocks";
482 xlseek(dev_fd
, G
.currently_testing
* BLOCK_SIZE
, SEEK_SET
);
484 try = TEST_BUFFER_BLOCKS
;
485 if (G
.currently_testing
+ try > SB_ZONES
)
486 try = SB_ZONES
- G
.currently_testing
;
487 got
= do_check(G
.check_blocks_buffer
, try, G
.currently_testing
);
488 G
.currently_testing
+= got
;
491 if (G
.currently_testing
< SB_FIRSTZONE
)
492 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
493 mark_zone(G
.currently_testing
);
495 G
.currently_testing
++;
498 printf("%d bad block(s)\n", G
.badblocks
);
501 static void get_list_blocks(char *filename
)
504 unsigned long blockno
;
506 listfile
= xfopen_for_read(filename
);
507 while (!feof(listfile
)) {
508 fscanf(listfile
, "%lu\n", &blockno
);
512 printf("%d bad block(s)\n", G
.badblocks
);
515 static void setup_tables(void)
517 unsigned long inodes
;
518 unsigned norm_firstzone
;
522 /* memset(G.superblock_buffer, 0, BLOCK_SIZE); */
523 /* memset(G.boot_block_buffer, 0, 512); */
526 SB_MAXSIZE
= version2
? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
528 SB
.s_zones
= G
.total_blocks
;
530 SB
.s_nzones
= G
.total_blocks
;
532 /* some magic nrs: 1 inode / 3 blocks */
533 if (G
.req_nr_inodes
== 0)
534 inodes
= G
.total_blocks
/ 3;
536 inodes
= G
.req_nr_inodes
;
537 /* Round up inode count to fill block size */
539 inodes
= (inodes
+ MINIX2_INODES_PER_BLOCK
- 1) &
540 ~(MINIX2_INODES_PER_BLOCK
- 1);
542 inodes
= (inodes
+ MINIX1_INODES_PER_BLOCK
- 1) &
543 ~(MINIX1_INODES_PER_BLOCK
- 1);
547 SB_IMAPS
= div_roundup(SB_INODES
+ 1, BITS_PER_BLOCK
);
549 /* Real bad hack but overwise mkfs.minix can be thrown
550 * in infinite loop...
552 * dd if=/dev/zero of=test.fs count=10 bs=1024
553 * mkfs.minix -i 200 test.fs
555 /* This code is not insane: NORM_FIRSTZONE is not a constant,
556 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
560 norm_firstzone
= NORM_FIRSTZONE
;
561 sb_zmaps
= div_roundup(G
.total_blocks
- norm_firstzone
+ 1, BITS_PER_BLOCK
);
562 if (SB_ZMAPS
== sb_zmaps
) goto got_it
;
564 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
566 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
569 SB_FIRSTZONE
= norm_firstzone
;
570 G
.inode_map
= xmalloc(SB_IMAPS
* BLOCK_SIZE
);
571 G
.zone_map
= xmalloc(SB_ZMAPS
* BLOCK_SIZE
);
572 memset(G
.inode_map
, 0xff, SB_IMAPS
* BLOCK_SIZE
);
573 memset(G
.zone_map
, 0xff, SB_ZMAPS
* BLOCK_SIZE
);
574 for (i
= SB_FIRSTZONE
; i
< SB_ZONES
; i
++)
576 for (i
= MINIX_ROOT_INO
; i
<= SB_INODES
; i
++)
578 G
.inode_buffer
= xzalloc(INODE_BUFFER_SIZE
);
579 printf("%lu inodes\n", (unsigned long)SB_INODES
);
580 printf("%lu blocks\n", (unsigned long)SB_ZONES
);
581 printf("Firstdatazone=%lu (%lu)\n", (unsigned long)SB_FIRSTZONE
, (unsigned long)norm_firstzone
);
582 printf("Zonesize=%u\n", BLOCK_SIZE
<< SB_ZONE_SIZE
);
583 printf("Maxsize=%lu\n", (unsigned long)SB_MAXSIZE
);
586 int mkfs_minix_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
587 int mkfs_minix_main(int argc UNUSED_PARAM
, char **argv
)
592 char *listfile
= NULL
;
595 /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
598 G
.magic
= MINIX1_SUPER_MAGIC2
;
600 if (INODE_SIZE1
* MINIX1_INODES_PER_BLOCK
!= BLOCK_SIZE
)
601 bb_error_msg_and_die("bad inode size");
602 #if ENABLE_FEATURE_MINIX2
603 if (INODE_SIZE2
* MINIX2_INODES_PER_BLOCK
!= BLOCK_SIZE
)
604 bb_error_msg_and_die("bad inode size");
607 opt_complementary
= "n+"; /* -n N */
608 opt
= getopt32(argv
, "ci:l:n:v", &str_i
, &listfile
, &G
.namelen
);
611 if (opt
& 2) G
.req_nr_inodes
= xatoul(str_i
); // -i
614 if (G
.namelen
== 14) G
.magic
= MINIX1_SUPER_MAGIC
;
615 else if (G
.namelen
== 30) G
.magic
= MINIX1_SUPER_MAGIC2
;
616 else bb_show_usage();
617 G
.dirsize
= G
.namelen
+ 2;
619 if (opt
& 0x10) { // -v
620 #if ENABLE_FEATURE_MINIX2
623 bb_error_msg_and_die("not compiled with minix v2 support");
627 G
.device_name
= argv
[0];
631 /* Check if it is mounted */
632 if (find_mount_point(G
.device_name
, 0))
633 bb_error_msg_and_die("can't format mounted filesystem");
635 xmove_fd(xopen(G
.device_name
, O_RDWR
), dev_fd
);
637 G
.total_blocks
= get_volume_size_in_bytes(dev_fd
, argv
[1], 1024, /*extend:*/ 1) / 1024;
639 if (G
.total_blocks
< 10)
640 bb_error_msg_and_die("must have at least 10 blocks");
643 G
.magic
= MINIX2_SUPER_MAGIC2
;
645 G
.magic
= MINIX2_SUPER_MAGIC
;
646 } else if (G
.total_blocks
> 65535)
647 G
.total_blocks
= 65535;
650 xfstat(dev_fd
, &statbuf
, G
.device_name
);
652 if (!S_ISBLK(statbuf
.st_mode
))
653 opt
&= ~1; // clear -c (check)
655 /* I don't know why someone has special code to prevent mkfs.minix
656 * on IDE devices. Why IDE but not SCSI, etc?... */
657 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340)
659 bb_error_msg_and_die("will not try "
660 "to make filesystem on '%s'", G
.device_name
);
665 strcpy(tmp
+ 2, ".");
668 strcpy(tmp
+ 2, "..");
671 strcpy(tmp
+ 2, ".badblocks");
678 get_list_blocks(listfile
);