2 * mkfs.minix.c - make a linux (minix) file-system.
4 * (C) 1991 Linus Torvalds. This file may be redistributed as per
11 * 24.11.91 - Time began. Used the fsck sources to get started.
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.
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)
20 * 28.02.92 - Added %-information when using -c.
22 * 28.02.93 - Added support for other namelengths than the original
23 * 14 characters so that I can test the new kernel routines..
25 * 09.10.93 - Make exit status conform to that required by fsutil
26 * (Rik Faith, faith@cs.unc.edu)
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)
32 * 03.01.94 - Added support for file system valid flag.
33 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
35 * 30.10.94 - Added support for v2 filesystem
36 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
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)
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)
46 * 02.07.96 - Added small patch from Russell King to make the program a
47 * good deal more portable (janl@math.uio.no)
49 * 06.29.11 - Overall cleanups for util-linux and v3 support
50 * Davidlohr Bueso <dave@gnu.org>
52 * 06.20.15 - Do not infinite loop or crash on large devices
53 * Joshua Hudson <joshudson@gmail.com>
71 #include "minix_programs.h"
73 #include "pathnames.h"
75 #include "exitcodes.h"
78 #include "closestream.h"
79 #include "ismounted.h"
81 #define XALLOC_EXIT_CODE MKFS_EX_ERROR
84 #define MINIX_ROOT_INO 1
85 #define MINIX_BAD_INO 2
87 #define TEST_BUFFER_BLOCKS 16
88 #define MAX_GOOD_BLOCKS 512
90 #define MINIX_MAX_INODES 65535
92 #define DEFAULT_FS_VERSION 1
95 * Global variables used in minix_programs.h inline functions
97 int fs_version
= DEFAULT_FS_VERSION
;
98 char *super_block_buffer
;
100 static char *inode_buffer
= NULL
;
102 #define Inode (((struct minix_inode *) inode_buffer) - 1)
103 #define Inode2 (((struct minix2_inode *) inode_buffer) - 1)
106 char *device_name
; /* device on a Minix file system is created */
107 int device_fd
; /* open file descriptor of the device */
108 unsigned long long fs_blocks
; /* device block count for the file system */
109 int fs_used_blocks
; /* used blocks on a device */
110 int fs_bad_blocks
; /* number of bad blocks found from device */
111 uint16_t fs_namelen
; /* maximum length of filenames */
112 size_t fs_dirsize
; /* maximum size of directory */
113 unsigned long fs_inodes
; /* number of inodes */
114 int fs_magic
; /* file system magic number */
116 check_blocks
:1; /* check for bad blocks */
119 static char root_block
[MINIX_BLOCK_SIZE
];
120 static char boot_block_buffer
[512];
121 static unsigned short good_blocks_table
[MAX_GOOD_BLOCKS
];
123 static char *inode_map
;
124 static char *zone_map
;
126 #define zone_in_use(x) (isset(zone_map,(x)-get_first_zone()+1) != 0)
128 #define mark_inode(x) (setbit(inode_map,(x)))
129 #define unmark_inode(x) (clrbit(inode_map,(x)))
131 #define mark_zone(x) (setbit(zone_map,(x)-get_first_zone()+1))
132 #define unmark_zone(x) (clrbit(zone_map,(x)-get_first_zone()+1))
134 static void __attribute__((__noreturn__
)) usage(void)
137 fputs(USAGE_HEADER
, out
);
138 fprintf(out
, _(" %s [options] /dev/name [blocks]\n"), program_invocation_short_name
);
139 fputs(USAGE_OPTIONS
, out
);
140 fputs(_(" -1 use Minix version 1\n"), out
);
141 fputs(_(" -2, -v use Minix version 2\n"), out
);
142 fputs(_(" -3 use Minix version 3\n"), out
);
143 fputs(_(" -n, --namelength <num> maximum length of filenames\n"), out
);
144 fputs(_(" -i, --inodes <num> number of inodes for the filesystem\n"), out
);
145 fputs(_(" -c, --check check the device for bad blocks\n"), out
);
146 fputs(_(" -l, --badblocks <file> list of bad blocks from file\n"), out
);
147 fputs(USAGE_SEPARATOR
, out
);
148 printf(USAGE_HELP_OPTIONS(25));
149 printf(USAGE_MAN_TAIL("mkfs.minix(8)"));
154 static inline time_t mkfs_minix_time(time_t *t
)
156 const char *str
= getenv("MKFS_MINIX_TEST_SECOND_SINCE_EPOCH");
159 if (str
&& sscanf(str
, "%ld", &sec
) == 1)
163 #else /* !TEST_SCRIPT */
164 # define mkfs_minix_time(x) time(x)
167 static void super_set_state(void)
169 switch (fs_version
) {
172 Super
.s_state
|= MINIX_VALID_FS
;
173 Super
.s_state
&= ~MINIX_ERROR_FS
;
180 static void write_tables(const struct fs_control
*ctl
) {
181 unsigned long imaps
= get_nimaps();
182 unsigned long zmaps
= get_nzmaps();
183 size_t buffsz
= get_inode_buffer_size();
185 /* Mark the super block valid. */
188 if (lseek(ctl
->device_fd
, 0, SEEK_SET
))
189 err(MKFS_EX_ERROR
, _("%s: seek to boot block failed "
190 " in write_tables"), ctl
->device_name
);
191 if (write_all(ctl
->device_fd
, boot_block_buffer
, 512))
192 err(MKFS_EX_ERROR
, _("%s: unable to clear boot sector"), ctl
->device_name
);
193 if (MINIX_BLOCK_SIZE
!= lseek(ctl
->device_fd
, MINIX_BLOCK_SIZE
, SEEK_SET
))
194 err(MKFS_EX_ERROR
, _("%s: seek failed in write_tables"), ctl
->device_name
);
196 if (write_all(ctl
->device_fd
, super_block_buffer
, MINIX_BLOCK_SIZE
))
197 err(MKFS_EX_ERROR
, _("%s: unable to write super-block"), ctl
->device_name
);
199 if (write_all(ctl
->device_fd
, inode_map
, imaps
* MINIX_BLOCK_SIZE
))
200 err(MKFS_EX_ERROR
, _("%s: unable to write inode map"), ctl
->device_name
);
202 if (write_all(ctl
->device_fd
, zone_map
, zmaps
* MINIX_BLOCK_SIZE
))
203 err(MKFS_EX_ERROR
, _("%s: unable to write zone map"), ctl
->device_name
);
205 if (write_all(ctl
->device_fd
, inode_buffer
, buffsz
))
206 err(MKFS_EX_ERROR
, _("%s: unable to write inodes"), ctl
->device_name
);
209 static void write_block(const struct fs_control
*ctl
, int blk
, char * buffer
) {
210 if (blk
* MINIX_BLOCK_SIZE
!= lseek(ctl
->device_fd
, blk
* MINIX_BLOCK_SIZE
, SEEK_SET
))
211 errx(MKFS_EX_ERROR
, _("%s: seek failed in write_block"), ctl
->device_name
);
213 if (write_all(ctl
->device_fd
, buffer
, MINIX_BLOCK_SIZE
))
214 errx(MKFS_EX_ERROR
, _("%s: write failed in write_block"), ctl
->device_name
);
217 static int get_free_block(struct fs_control
*ctl
) {
219 unsigned int zones
= get_nzones();
220 unsigned int first_zone
= get_first_zone();
222 if (ctl
->fs_used_blocks
+ 1 >= MAX_GOOD_BLOCKS
)
223 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
224 if (ctl
->fs_used_blocks
)
225 blk
= good_blocks_table
[ctl
->fs_used_blocks
- 1] + 1;
228 while (blk
< zones
&& zone_in_use(blk
))
231 errx(MKFS_EX_ERROR
, _("%s: not enough good blocks"), ctl
->device_name
);
232 good_blocks_table
[ctl
->fs_used_blocks
] = blk
;
233 ctl
->fs_used_blocks
++;
237 static void mark_good_blocks(const struct fs_control
*ctl
) {
240 for (blk
=0 ; blk
< ctl
->fs_used_blocks
; blk
++)
241 mark_zone(good_blocks_table
[blk
]);
244 static inline int next(unsigned long zone
) {
245 unsigned long zones
= get_nzones();
246 unsigned long first_zone
= get_first_zone();
250 while (++zone
< zones
)
251 if (zone_in_use(zone
))
256 static void make_bad_inode_v1(struct fs_control
*ctl
)
258 struct minix_inode
* inode
= &Inode
[MINIX_BAD_INO
];
261 unsigned short ind_block
[MINIX_BLOCK_SIZE
>>1];
262 unsigned short dind_block
[MINIX_BLOCK_SIZE
>>1];
264 #define NEXT_BAD (zone = next(zone))
266 if (!ctl
->fs_bad_blocks
)
268 mark_inode(MINIX_BAD_INO
);
270 inode
->i_time
= mkfs_minix_time(NULL
);
271 inode
->i_mode
= S_IFREG
+ 0000;
272 inode
->i_size
= ctl
->fs_bad_blocks
* MINIX_BLOCK_SIZE
;
274 for (i
=0 ; i
<7 ; i
++) {
275 inode
->i_zone
[i
] = zone
;
279 inode
->i_zone
[7] = ind
= get_free_block(ctl
);
280 memset(ind_block
,0,MINIX_BLOCK_SIZE
);
281 for (i
=0 ; i
<512 ; i
++) {
286 inode
->i_zone
[8] = dind
= get_free_block(ctl
);
287 memset(dind_block
,0,MINIX_BLOCK_SIZE
);
288 for (i
=0 ; i
<512 ; i
++) {
289 write_block(ctl
, ind
,(char *) ind_block
);
290 dind_block
[i
] = ind
= get_free_block(ctl
);
291 memset(ind_block
,0,MINIX_BLOCK_SIZE
);
292 for (j
=0 ; j
<512 ; j
++) {
298 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
301 write_block(ctl
, ind
, (char *) ind_block
);
303 write_block(ctl
, dind
, (char *) dind_block
);
306 static void make_bad_inode_v2_v3 (struct fs_control
*ctl
)
308 struct minix2_inode
*inode
= &Inode2
[MINIX_BAD_INO
];
310 int ind
= 0, dind
= 0;
311 unsigned long ind_block
[MINIX_BLOCK_SIZE
>> 2];
312 unsigned long dind_block
[MINIX_BLOCK_SIZE
>> 2];
314 if (!ctl
->fs_bad_blocks
)
316 mark_inode (MINIX_BAD_INO
);
318 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= mkfs_minix_time(NULL
);
319 inode
->i_mode
= S_IFREG
+ 0000;
320 inode
->i_size
= ctl
->fs_bad_blocks
* MINIX_BLOCK_SIZE
;
322 for (i
= 0; i
< 7; i
++) {
323 inode
->i_zone
[i
] = zone
;
327 inode
->i_zone
[7] = ind
= get_free_block (ctl
);
328 memset (ind_block
, 0, MINIX_BLOCK_SIZE
);
329 for (i
= 0; i
< 256; i
++) {
334 inode
->i_zone
[8] = dind
= get_free_block (ctl
);
335 memset (dind_block
, 0, MINIX_BLOCK_SIZE
);
336 for (i
= 0; i
< 256; i
++) {
337 write_block (ctl
, ind
, (char *) ind_block
);
338 dind_block
[i
] = ind
= get_free_block (ctl
);
339 memset (ind_block
, 0, MINIX_BLOCK_SIZE
);
340 for (j
= 0; j
< 256; j
++) {
346 /* Could make triple indirect block here */
347 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
350 write_block (ctl
, ind
, (char *) ind_block
);
352 write_block (ctl
, dind
, (char *) dind_block
);
355 static void make_bad_inode(struct fs_control
*ctl
)
357 if (fs_version
< 2) {
358 make_bad_inode_v1(ctl
);
361 make_bad_inode_v2_v3(ctl
);
364 static void make_root_inode_v1(struct fs_control
*ctl
) {
365 struct minix_inode
* inode
= &Inode
[MINIX_ROOT_INO
];
367 mark_inode(MINIX_ROOT_INO
);
368 inode
->i_zone
[0] = get_free_block(ctl
);
370 inode
->i_time
= mkfs_minix_time(NULL
);
371 if (ctl
->fs_bad_blocks
)
372 inode
->i_size
= 3 * ctl
->fs_dirsize
;
374 memset(&root_block
[2 * ctl
->fs_dirsize
], 0, ctl
->fs_dirsize
);
375 inode
->i_size
= 2 * ctl
->fs_dirsize
;
377 inode
->i_mode
= S_IFDIR
+ 0755;
378 inode
->i_uid
= getuid();
380 inode
->i_gid
= getgid();
381 write_block(ctl
, inode
->i_zone
[0],root_block
);
384 static void make_root_inode_v2_v3 (struct fs_control
*ctl
) {
385 struct minix2_inode
*inode
= &Inode2
[MINIX_ROOT_INO
];
387 mark_inode (MINIX_ROOT_INO
);
388 inode
->i_zone
[0] = get_free_block (ctl
);
390 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= mkfs_minix_time(NULL
);
392 if (ctl
->fs_bad_blocks
)
393 inode
->i_size
= 3 * ctl
->fs_dirsize
;
395 memset(&root_block
[2 * ctl
->fs_dirsize
], 0, ctl
->fs_dirsize
);
396 inode
->i_size
= 2 * ctl
->fs_dirsize
;
399 inode
->i_mode
= S_IFDIR
+ 0755;
400 inode
->i_uid
= getuid();
402 inode
->i_gid
= getgid();
403 write_block (ctl
, inode
->i_zone
[0], root_block
);
406 static void make_root_inode(struct fs_control
*ctl
)
408 char *tmp
= root_block
;
410 if (fs_version
== 3) {
411 *(uint32_t *) tmp
= 1;
412 strcpy(tmp
+ 4, ".");
413 tmp
+= ctl
->fs_dirsize
;
414 *(uint32_t *) tmp
= 1;
415 strcpy(tmp
+ 4, "..");
416 tmp
+= ctl
->fs_dirsize
;
417 *(uint32_t *) tmp
= 2;
418 strcpy(tmp
+ 4, ".badblocks");
420 *(uint16_t *) tmp
= 1;
421 strcpy(tmp
+ 2, ".");
422 tmp
+= ctl
->fs_dirsize
;
423 *(uint16_t *) tmp
= 1;
424 strcpy(tmp
+ 2, "..");
425 tmp
+= ctl
->fs_dirsize
;
426 *(uint16_t *) tmp
= 2;
427 strcpy(tmp
+ 2, ".badblocks");
429 if (fs_version
< 2) {
430 make_root_inode_v1(ctl
);
433 make_root_inode_v2_v3(ctl
);
436 static void super_set_nzones(const struct fs_control
*ctl
)
438 switch (fs_version
) {
440 Super3
.s_zones
= ctl
->fs_blocks
;
443 Super
.s_zones
= ctl
->fs_blocks
;
446 Super
.s_nzones
= ctl
->fs_blocks
;
451 static void super_init_maxsize(void)
453 switch (fs_version
) {
455 Super3
.s_max_size
= 2147483647L;
458 Super
.s_max_size
= 0x7fffffff;
461 Super
.s_max_size
= (7+512+512*512)*1024;
466 static void super_set_map_blocks(const struct fs_control
*ctl
, unsigned long inodes
)
468 switch (fs_version
) {
470 Super3
.s_imap_blocks
= UPPER(inodes
+ 1, BITS_PER_BLOCK
);
471 Super3
.s_zmap_blocks
= UPPER(ctl
->fs_blocks
- (1 + get_nimaps() + inode_blocks()),
473 Super3
.s_firstdatazone
= first_zone_data();
476 Super
.s_imap_blocks
= UPPER(inodes
+ 1, BITS_PER_BLOCK
);
477 Super
.s_zmap_blocks
= UPPER(ctl
->fs_blocks
- (1 + get_nimaps() + inode_blocks()),
479 Super
.s_firstdatazone
= first_zone_data();
484 static void super_set_magic(const struct fs_control
*ctl
)
486 switch (fs_version
) {
488 Super3
.s_magic
= ctl
->fs_magic
;
491 Super
.s_magic
= ctl
->fs_magic
;
496 static void setup_tables(const struct fs_control
*ctl
) {
497 unsigned long inodes
, zmaps
, imaps
, zones
, i
;
499 super_block_buffer
= xcalloc(1, MINIX_BLOCK_SIZE
);
501 memset(boot_block_buffer
,0,512);
502 super_set_magic(ctl
);
504 if (fs_version
== 3) {
505 Super3
.s_log_zone_size
= 0;
506 Super3
.s_blocksize
= MINIX_BLOCK_SIZE
;
509 Super
.s_log_zone_size
= 0;
512 super_init_maxsize();
513 super_set_nzones(ctl
);
514 zones
= get_nzones();
516 /* some magic nrs: 1 inode / 3 blocks for smaller filesystems,
517 * for one inode / 16 blocks for large ones. mkfs will eventually
518 * crab about too far when getting close to the maximum size. */
519 if (ctl
->fs_inodes
== 0)
520 if (2048 * 1024 < ctl
->fs_blocks
) /* 2GB */
521 inodes
= ctl
->fs_blocks
/ 16;
522 else if (512 * 1024 < ctl
->fs_blocks
) /* 0.5GB */
523 inodes
= ctl
->fs_blocks
/ 8;
525 inodes
= ctl
->fs_blocks
/ 3;
527 inodes
= ctl
->fs_inodes
;
528 /* Round up inode count to fill block size */
529 if (fs_version
== 2 || fs_version
== 3)
530 inodes
= ((inodes
+ MINIX2_INODES_PER_BLOCK
- 1) &
531 ~(MINIX2_INODES_PER_BLOCK
- 1));
533 inodes
= ((inodes
+ MINIX_INODES_PER_BLOCK
- 1) &
534 ~(MINIX_INODES_PER_BLOCK
- 1));
537 Super3
.s_ninodes
= inodes
;
539 if (inodes
> MINIX_MAX_INODES
)
540 inodes
= MINIX_MAX_INODES
;
541 Super
.s_ninodes
= inodes
;
543 super_set_map_blocks(ctl
, inodes
);
544 if (MINIX_MAX_INODES
< first_zone_data())
546 _("First data block at %jd, which is too far (max %d).\n"
547 "Try specifying fewer inodes by passing --inodes <num>"),
548 (intmax_t)first_zone_data(),
550 imaps
= get_nimaps();
551 zmaps
= get_nzmaps();
553 inode_map
= xmalloc(imaps
* MINIX_BLOCK_SIZE
);
554 zone_map
= xmalloc(zmaps
* MINIX_BLOCK_SIZE
);
555 memset(inode_map
,0xff,imaps
* MINIX_BLOCK_SIZE
);
556 memset(zone_map
,0xff,zmaps
* MINIX_BLOCK_SIZE
);
558 for (i
= get_first_zone() ; i
<zones
; i
++)
560 for (i
= MINIX_ROOT_INO
; i
<=inodes
; i
++)
563 inode_buffer
= xmalloc(get_inode_buffer_size());
564 memset(inode_buffer
,0, get_inode_buffer_size());
566 printf(P_("%lu inode\n", "%lu inodes\n", inodes
), inodes
);
567 printf(P_("%lu block\n", "%lu blocks\n", zones
), zones
);
568 printf(_("Firstdatazone=%jd (%jd)\n"),
569 (intmax_t)get_first_zone(), (intmax_t)first_zone_data());
570 printf(_("Zonesize=%zu\n"), (size_t) MINIX_BLOCK_SIZE
<< get_zone_size());
571 printf(_("Maxsize=%zu\n\n"),get_max_size());
575 * Perform a test of a block; return the number of
576 * blocks readable/writable.
578 static size_t do_check(const struct fs_control
*ctl
, char * buffer
, int try, unsigned int current_block
) {
581 /* Seek to the correct loc. */
582 if (lseek(ctl
->device_fd
, current_block
* MINIX_BLOCK_SIZE
, SEEK_SET
) !=
583 current_block
* MINIX_BLOCK_SIZE
)
584 err(MKFS_EX_ERROR
, _("%s: seek failed during testing of blocks"),
588 got
= read(ctl
->device_fd
, buffer
, try * MINIX_BLOCK_SIZE
);
589 if (got
< 0) got
= 0;
590 if (got
& (MINIX_BLOCK_SIZE
- 1 )) {
591 printf(_("Weird values in do_check: probably bugs\n"));
593 got
/= MINIX_BLOCK_SIZE
;
597 static unsigned int currently_testing
= 0;
599 static void alarm_intr(int alnum
__attribute__ ((__unused__
))) {
600 unsigned long zones
= get_nzones();
602 if (currently_testing
>= zones
)
604 signal(SIGALRM
,alarm_intr
);
606 if (!currently_testing
)
608 printf("%d ...", currently_testing
);
612 static void check_blocks(struct fs_control
*ctl
) {
614 static char buffer
[MINIX_BLOCK_SIZE
* TEST_BUFFER_BLOCKS
];
615 unsigned long zones
= get_nzones();
616 unsigned long first_zone
= get_first_zone();
619 signal(SIGALRM
,alarm_intr
);
621 while (currently_testing
< zones
) {
622 if (lseek(ctl
->device_fd
, currently_testing
* MINIX_BLOCK_SIZE
,SEEK_SET
) !=
623 currently_testing
*MINIX_BLOCK_SIZE
)
624 errx(MKFS_EX_ERROR
, _("%s: seek failed in check_blocks"),
626 try = TEST_BUFFER_BLOCKS
;
627 if (currently_testing
+ try > zones
)
628 try = zones
-currently_testing
;
629 got
= do_check(ctl
, buffer
, try, currently_testing
);
630 currently_testing
+= got
;
633 if (currently_testing
< first_zone
)
634 errx(MKFS_EX_ERROR
, _("%s: bad blocks before data-area: "
635 "cannot make fs"), ctl
->device_name
);
636 mark_zone(currently_testing
);
637 ctl
->fs_bad_blocks
++;
640 if (ctl
->fs_bad_blocks
> 0)
641 printf(P_("%d bad block\n", "%d bad blocks\n", ctl
->fs_bad_blocks
), ctl
->fs_bad_blocks
);
644 static void get_list_blocks(struct fs_control
*ctl
, char *filename
) {
646 unsigned long blockno
;
648 listfile
= fopen(filename
,"r");
649 if (listfile
== NULL
)
650 err(MKFS_EX_ERROR
, _("%s: can't open file of bad blocks"),
653 while (!feof(listfile
)) {
654 if (fscanf(listfile
,"%lu\n", &blockno
) != 1) {
655 printf(_("badblock number input error on line %d\n"), ctl
->fs_bad_blocks
+ 1);
656 errx(MKFS_EX_ERROR
, _("%s: cannot read badblocks file"),
660 ctl
->fs_bad_blocks
++;
664 if (ctl
->fs_bad_blocks
> 0)
665 printf(P_("%d bad block\n", "%d bad blocks\n", ctl
->fs_bad_blocks
), ctl
->fs_bad_blocks
);
668 static int find_super_magic(const struct fs_control
*ctl
)
670 switch (fs_version
) {
672 if (ctl
->fs_namelen
== 14)
673 return MINIX_SUPER_MAGIC
;
674 return MINIX_SUPER_MAGIC2
;
676 if (ctl
->fs_namelen
== 14)
677 return MINIX2_SUPER_MAGIC
;
678 return MINIX2_SUPER_MAGIC2
;
680 return MINIX3_SUPER_MAGIC
;
686 static void determine_device_blocks(struct fs_control
*ctl
, const struct stat
*statbuf
)
688 unsigned long long dev_blocks
= 0;
690 if (S_ISBLK(statbuf
->st_mode
)) {
693 if (blkdev_get_sector_size(ctl
->device_fd
, §orsize
) == -1)
694 sectorsize
= DEFAULT_SECTOR_SIZE
; /* kernel < 2.3.3 */
695 if (MINIX_BLOCK_SIZE
< sectorsize
)
696 errx(MKFS_EX_ERROR
, _("block size smaller than physical "
697 "sector size of %s"), ctl
->device_name
);
698 if (blkdev_get_size(ctl
->device_fd
, &dev_blocks
) == -1)
699 errx(MKFS_EX_ERROR
, _("cannot determine size of %s"), ctl
->device_name
);
700 dev_blocks
/= MINIX_BLOCK_SIZE
;
701 } else if (!S_ISBLK(statbuf
->st_mode
))
702 dev_blocks
= statbuf
->st_size
/ MINIX_BLOCK_SIZE
;
704 ctl
->fs_blocks
= dev_blocks
;
705 else if (dev_blocks
< ctl
->fs_blocks
)
707 _("%s: requested blocks (%llu) exceeds available (%llu) blocks\n"),
708 ctl
->device_name
, ctl
->fs_blocks
, dev_blocks
);
709 if (ctl
->fs_blocks
< 10)
710 errx(MKFS_EX_ERROR
, _("%s: number of blocks too small"), ctl
->device_name
);
711 if (fs_version
== 1 && ctl
->fs_blocks
> MINIX_MAX_INODES
)
712 ctl
->fs_blocks
= MINIX_MAX_INODES
;
713 if (ctl
->fs_blocks
> (4 + ((MINIX_MAX_INODES
- 4) * BITS_PER_BLOCK
)))
714 ctl
->fs_blocks
= 4 + ((MINIX_MAX_INODES
- 4) * BITS_PER_BLOCK
); /* Utter maximum: Clip. */
717 static void check_user_instructions(struct fs_control
*ctl
)
719 switch (fs_version
) {
722 if (ctl
->fs_namelen
== 14 || ctl
->fs_namelen
== 30)
723 ctl
->fs_dirsize
= ctl
->fs_namelen
+ 2;
725 errx(MKFS_EX_ERROR
, _("unsupported name length: %d"), ctl
->fs_namelen
);
728 if (ctl
->fs_namelen
== 60)
729 ctl
->fs_dirsize
= ctl
->fs_namelen
+ 4;
731 errx(MKFS_EX_ERROR
, _("unsupported name length: %d"), ctl
->fs_namelen
);
734 errx(MKFS_EX_ERROR
, _("unsupported minix file system version: %d"), fs_version
);
736 ctl
->fs_magic
= find_super_magic(ctl
);
739 int main(int argc
, char ** argv
)
741 struct fs_control ctl
= {
742 .fs_namelen
= 30, /* keep in sync with DEFAULT_FS_VERSION */
747 char * listfile
= NULL
;
748 static const struct option longopts
[] = {
749 {"namelength", required_argument
, NULL
, 'n'},
750 {"inodes", required_argument
, NULL
, 'i'},
751 {"check", no_argument
, NULL
, 'c'},
752 {"badblocks", required_argument
, NULL
, 'l'},
753 {"version", no_argument
, NULL
, 'V'},
754 {"help", no_argument
, NULL
, 'h'},
758 setlocale(LC_ALL
, "");
759 bindtextdomain(PACKAGE
, LOCALEDIR
);
761 close_stdout_atexit();
763 strutils_set_exitcode(MKFS_EX_USAGE
);
765 while ((i
= getopt_long(argc
, argv
, "1v23n:i:cl:Vh", longopts
, NULL
)) != -1)
770 case 'v': /* kept for backwards compatibility */
771 warnx(_("-v is ambiguous, use '-2' instead"));
781 ctl
.fs_namelen
= strtou16_or_err(optarg
,
782 _("failed to parse maximum length of filenames"));
785 ctl
.fs_inodes
= strtoul_or_err(optarg
,
786 _("failed to parse number of inodes"));
789 ctl
.check_blocks
= 1;
795 print_version(MKFS_EX_OK
);
799 errtryhelp(MKFS_EX_USAGE
);
804 ctl
.device_name
= argv
[0];
809 ctl
.fs_blocks
= strtoul_or_err(argv
[0], _("failed to parse number of blocks"));
811 if (!ctl
.device_name
) {
812 warnx(_("no device specified"));
813 errtryhelp(MKFS_EX_USAGE
);
815 check_user_instructions(&ctl
);
816 if (is_mounted(ctl
.device_name
))
817 errx(MKFS_EX_ERROR
, _("%s is mounted; will not make a filesystem here!"),
819 if (stat(ctl
.device_name
, &statbuf
) < 0)
820 err(MKFS_EX_ERROR
, _("stat of %s failed"), ctl
.device_name
);
821 ctl
.device_fd
= open_blkdev_or_file(&statbuf
, ctl
.device_name
, O_RDWR
);
822 if (ctl
.device_fd
< 0)
823 err(MKFS_EX_ERROR
, _("cannot open %s"), ctl
.device_name
);
824 determine_device_blocks(&ctl
, &statbuf
);
826 if (ctl
.check_blocks
)
829 get_list_blocks(&ctl
, listfile
);
831 make_root_inode(&ctl
);
832 make_bad_inode(&ctl
);
834 mark_good_blocks(&ctl
);
836 if (close_fd(ctl
.device_fd
) != 0)
837 err(MKFS_EX_ERROR
, _("write failed"));