2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 * mkfs.minix.c - make a linux (minix) file-system.
10 * (C) 1991 Linus Torvalds. This file may be redistributed as per
11 * the Linux copyright.
15 * 24.11.91 - Time began. Used the fsck sources to get started.
17 * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
18 * The algorithm for ".badblocks" is a bit weird, but
19 * it should work. Oh, well.
21 * 25.01.92 - Added the -l option for getting the list of bad blocks
22 * out of a named file. (Dave Rivers, rivers@ponds.uucp)
24 * 28.02.92 - Added %-information when using -c.
26 * 28.02.93 - Added support for other namelengths than the original
27 * 14 characters so that I can test the new kernel routines..
29 * 09.10.93 - Make exit status conform to that required by fsutil
30 * (Rik Faith, faith@cs.unc.edu)
32 * 31.10.93 - Added inode request feature, for backup floppies: use
33 * 32 inodes, for a news partition use more.
34 * (Scott Heavner, sdh@po.cwru.edu)
36 * 03.01.94 - Added support for file system valid flag.
37 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
39 * 30.10.94 - Added support for v2 filesystem
40 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
42 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
43 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
44 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
46 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
47 * the filesystem is not misidentified as a MS-DOS FAT filesystem.
48 * (Daniel Quinlan, quinlan@yggdrasil.com)
50 * 02.07.96 - Added small patch from Russell King to make the program a
51 * good deal more portable (janl@math.uio.no)
53 * 06.29.11 - Overall cleanups for util-linux and v3 support
54 * Davidlohr Bueso <dave@gnu.org>
56 * 06.20.15 - Do not infinite loop or crash on large devices
57 * Joshua Hudson <joshudson@gmail.com>
75 #include "minix_programs.h"
77 #include "pathnames.h"
79 #include "exitcodes.h"
82 #include "closestream.h"
83 #include "ismounted.h"
85 #define XALLOC_EXIT_CODE MKFS_EX_ERROR
88 #define MINIX_ROOT_INO 1
89 #define MINIX_BAD_INO 2
91 #define TEST_BUFFER_BLOCKS 16
92 #define MAX_GOOD_BLOCKS 512
94 #define MINIX_MAX_INODES 65535
96 #define DEFAULT_FS_VERSION 1
99 * Global variables used in minix_programs.h inline functions
101 int fs_version
= DEFAULT_FS_VERSION
;
102 char *super_block_buffer
;
104 static char *inode_buffer
= NULL
;
106 #define Inode (((struct minix_inode *) inode_buffer) - 1)
107 #define Inode2 (((struct minix2_inode *) inode_buffer) - 1)
110 char *device_name
; /* device on a Minix file system is created */
111 int device_fd
; /* open file descriptor of the device */
112 char *lockmode
; /* as specified by --lock */
113 unsigned long long fs_blocks
; /* device block count for the file system */
114 int fs_used_blocks
; /* used blocks on a device */
115 int fs_bad_blocks
; /* number of bad blocks found from device */
116 uint16_t fs_namelen
; /* maximum length of filenames */
117 size_t fs_dirsize
; /* maximum size of directory */
118 unsigned long fs_inodes
; /* number of inodes */
119 int fs_magic
; /* file system magic number */
121 check_blocks
:1; /* check for bad blocks */
124 static char root_block
[MINIX_BLOCK_SIZE
];
125 static char boot_block_buffer
[512];
126 static unsigned short good_blocks_table
[MAX_GOOD_BLOCKS
];
128 static char *inode_map
;
129 static char *zone_map
;
131 #define zone_in_use(x) (isset(zone_map,(x)-get_first_zone()+1) != 0)
133 #define mark_inode(x) (setbit(inode_map,(x)))
134 #define unmark_inode(x) (clrbit(inode_map,(x)))
136 #define mark_zone(x) (setbit(zone_map,(x)-get_first_zone()+1))
137 #define unmark_zone(x) (clrbit(zone_map,(x)-get_first_zone()+1))
139 static void __attribute__((__noreturn__
)) usage(void)
142 fputs(USAGE_HEADER
, out
);
143 fprintf(out
, _(" %s [options] /dev/name [blocks]\n"), program_invocation_short_name
);
144 fputs(USAGE_OPTIONS
, out
);
145 fputs(_(" -1 use Minix version 1\n"), out
);
146 fputs(_(" -2, -v use Minix version 2\n"), out
);
147 fputs(_(" -3 use Minix version 3\n"), out
);
148 fputs(_(" -n, --namelength <num> maximum length of filenames\n"), out
);
149 fputs(_(" -i, --inodes <num> number of inodes for the filesystem\n"), out
);
150 fputs(_(" -c, --check check the device for bad blocks\n"), out
);
151 fputs(_(" -l, --badblocks <file> list of bad blocks from file\n"), out
);
153 " --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
154 fputs(USAGE_SEPARATOR
, out
);
155 fprintf(out
, USAGE_HELP_OPTIONS(25));
156 fprintf(out
, USAGE_MAN_TAIL("mkfs.minix(8)"));
161 static inline time_t mkfs_minix_time(time_t *t
)
163 const char *str
= getenv("MKFS_MINIX_TEST_SECOND_SINCE_EPOCH");
166 if (str
&& sscanf(str
, "%"SCNd64
, &sec
) == 1)
170 #else /* !TEST_SCRIPT */
171 # define mkfs_minix_time(x) time(x)
174 static void super_set_state(void)
176 switch (fs_version
) {
179 Super
.s_state
|= MINIX_VALID_FS
;
180 Super
.s_state
&= ~MINIX_ERROR_FS
;
187 static void write_tables(const struct fs_control
*ctl
) {
188 unsigned long imaps
= get_nimaps();
189 unsigned long zmaps
= get_nzmaps();
190 size_t buffsz
= get_inode_buffer_size();
192 /* Mark the super block valid. */
195 if (lseek(ctl
->device_fd
, 0, SEEK_SET
))
196 err(MKFS_EX_ERROR
, _("%s: seek to boot block failed "
197 " in write_tables"), ctl
->device_name
);
198 if (write_all(ctl
->device_fd
, boot_block_buffer
, 512))
199 err(MKFS_EX_ERROR
, _("%s: unable to clear boot sector"), ctl
->device_name
);
200 if (MINIX_BLOCK_SIZE
!= lseek(ctl
->device_fd
, MINIX_BLOCK_SIZE
, SEEK_SET
))
201 err(MKFS_EX_ERROR
, _("%s: seek failed in write_tables"), ctl
->device_name
);
203 if (write_all(ctl
->device_fd
, super_block_buffer
, MINIX_BLOCK_SIZE
))
204 err(MKFS_EX_ERROR
, _("%s: unable to write super-block"), ctl
->device_name
);
206 if (write_all(ctl
->device_fd
, inode_map
, imaps
* MINIX_BLOCK_SIZE
))
207 err(MKFS_EX_ERROR
, _("%s: unable to write inode map"), ctl
->device_name
);
209 if (write_all(ctl
->device_fd
, zone_map
, zmaps
* MINIX_BLOCK_SIZE
))
210 err(MKFS_EX_ERROR
, _("%s: unable to write zone map"), ctl
->device_name
);
212 if (write_all(ctl
->device_fd
, inode_buffer
, buffsz
))
213 err(MKFS_EX_ERROR
, _("%s: unable to write inodes"), ctl
->device_name
);
216 static void write_block(const struct fs_control
*ctl
, int blk
, char * buffer
) {
217 if (blk
* MINIX_BLOCK_SIZE
!= lseek(ctl
->device_fd
, blk
* MINIX_BLOCK_SIZE
, SEEK_SET
))
218 errx(MKFS_EX_ERROR
, _("%s: seek failed in write_block"), ctl
->device_name
);
220 if (write_all(ctl
->device_fd
, buffer
, MINIX_BLOCK_SIZE
))
221 errx(MKFS_EX_ERROR
, _("%s: write failed in write_block"), ctl
->device_name
);
224 static int get_free_block(struct fs_control
*ctl
) {
226 unsigned int zones
= get_nzones();
227 unsigned int first_zone
= get_first_zone();
229 if (ctl
->fs_used_blocks
+ 1 >= MAX_GOOD_BLOCKS
)
230 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
231 if (ctl
->fs_used_blocks
)
232 blk
= good_blocks_table
[ctl
->fs_used_blocks
- 1] + 1;
235 while (blk
< zones
&& zone_in_use(blk
))
238 errx(MKFS_EX_ERROR
, _("%s: not enough good blocks"), ctl
->device_name
);
239 good_blocks_table
[ctl
->fs_used_blocks
] = blk
;
240 ctl
->fs_used_blocks
++;
244 static void mark_good_blocks(const struct fs_control
*ctl
) {
247 for (blk
=0 ; blk
< ctl
->fs_used_blocks
; blk
++)
248 mark_zone(good_blocks_table
[blk
]);
251 static inline int next(unsigned long zone
) {
252 unsigned long zones
= get_nzones();
253 unsigned long first_zone
= get_first_zone();
257 while (++zone
< zones
)
258 if (zone_in_use(zone
))
263 static void make_bad_inode_v1(struct fs_control
*ctl
)
265 struct minix_inode
* inode
= &Inode
[MINIX_BAD_INO
];
268 unsigned short ind_block
[MINIX_BLOCK_SIZE
>>1];
269 unsigned short dind_block
[MINIX_BLOCK_SIZE
>>1];
271 #define NEXT_BAD (zone = next(zone))
273 if (!ctl
->fs_bad_blocks
)
275 mark_inode(MINIX_BAD_INO
);
277 inode
->i_time
= mkfs_minix_time(NULL
);
278 inode
->i_mode
= S_IFREG
+ 0000;
279 inode
->i_size
= ctl
->fs_bad_blocks
* MINIX_BLOCK_SIZE
;
281 for (i
=0 ; i
<7 ; i
++) {
282 inode
->i_zone
[i
] = zone
;
286 inode
->i_zone
[7] = ind
= get_free_block(ctl
);
287 memset(ind_block
,0,MINIX_BLOCK_SIZE
);
288 for (i
=0 ; i
<512 ; i
++) {
293 inode
->i_zone
[8] = dind
= get_free_block(ctl
);
294 memset(dind_block
,0,MINIX_BLOCK_SIZE
);
295 for (i
=0 ; i
<512 ; i
++) {
296 write_block(ctl
, ind
,(char *) ind_block
);
297 dind_block
[i
] = ind
= get_free_block(ctl
);
298 memset(ind_block
,0,MINIX_BLOCK_SIZE
);
299 for (j
=0 ; j
<512 ; j
++) {
305 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
308 write_block(ctl
, ind
, (char *) ind_block
);
310 write_block(ctl
, dind
, (char *) dind_block
);
313 static void make_bad_inode_v2_v3 (struct fs_control
*ctl
)
315 struct minix2_inode
*inode
= &Inode2
[MINIX_BAD_INO
];
317 int ind
= 0, dind
= 0;
318 unsigned long ind_block
[MINIX_BLOCK_SIZE
>> 2];
319 unsigned long dind_block
[MINIX_BLOCK_SIZE
>> 2];
321 if (!ctl
->fs_bad_blocks
)
323 mark_inode (MINIX_BAD_INO
);
325 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= mkfs_minix_time(NULL
);
326 inode
->i_mode
= S_IFREG
+ 0000;
327 inode
->i_size
= ctl
->fs_bad_blocks
* MINIX_BLOCK_SIZE
;
329 for (i
= 0; i
< 7; i
++) {
330 inode
->i_zone
[i
] = zone
;
334 inode
->i_zone
[7] = ind
= get_free_block (ctl
);
335 memset (ind_block
, 0, MINIX_BLOCK_SIZE
);
336 for (i
= 0; i
< 256; i
++) {
341 inode
->i_zone
[8] = dind
= get_free_block (ctl
);
342 memset (dind_block
, 0, MINIX_BLOCK_SIZE
);
343 for (i
= 0; i
< 256; i
++) {
344 write_block (ctl
, ind
, (char *) ind_block
);
345 dind_block
[i
] = ind
= get_free_block (ctl
);
346 memset (ind_block
, 0, MINIX_BLOCK_SIZE
);
347 for (j
= 0; j
< 256; j
++) {
353 /* Could make triple indirect block here */
354 errx(MKFS_EX_ERROR
, _("%s: too many bad blocks"), ctl
->device_name
);
357 write_block (ctl
, ind
, (char *) ind_block
);
359 write_block (ctl
, dind
, (char *) dind_block
);
362 static void make_bad_inode(struct fs_control
*ctl
)
364 if (fs_version
< 2) {
365 make_bad_inode_v1(ctl
);
368 make_bad_inode_v2_v3(ctl
);
371 static void make_root_inode_v1(struct fs_control
*ctl
) {
372 struct minix_inode
* inode
= &Inode
[MINIX_ROOT_INO
];
374 mark_inode(MINIX_ROOT_INO
);
375 inode
->i_zone
[0] = get_free_block(ctl
);
377 inode
->i_time
= mkfs_minix_time(NULL
);
378 if (ctl
->fs_bad_blocks
)
379 inode
->i_size
= 3 * ctl
->fs_dirsize
;
381 memset(&root_block
[2 * ctl
->fs_dirsize
], 0, ctl
->fs_dirsize
);
382 inode
->i_size
= 2 * ctl
->fs_dirsize
;
384 inode
->i_mode
= S_IFDIR
+ 0755;
385 inode
->i_uid
= getuid();
387 inode
->i_gid
= getgid();
388 write_block(ctl
, inode
->i_zone
[0],root_block
);
391 static void make_root_inode_v2_v3 (struct fs_control
*ctl
) {
392 struct minix2_inode
*inode
= &Inode2
[MINIX_ROOT_INO
];
394 mark_inode (MINIX_ROOT_INO
);
395 inode
->i_zone
[0] = get_free_block (ctl
);
397 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= mkfs_minix_time(NULL
);
399 if (ctl
->fs_bad_blocks
)
400 inode
->i_size
= 3 * ctl
->fs_dirsize
;
402 memset(&root_block
[2 * ctl
->fs_dirsize
], 0, ctl
->fs_dirsize
);
403 inode
->i_size
= 2 * ctl
->fs_dirsize
;
406 inode
->i_mode
= S_IFDIR
+ 0755;
407 inode
->i_uid
= getuid();
409 inode
->i_gid
= getgid();
410 write_block (ctl
, inode
->i_zone
[0], root_block
);
413 static void make_root_inode(struct fs_control
*ctl
)
415 char *tmp
= root_block
;
417 if (fs_version
== 3) {
418 *(uint32_t *) tmp
= 1;
419 strcpy(tmp
+ 4, ".");
420 tmp
+= ctl
->fs_dirsize
;
421 *(uint32_t *) tmp
= 1;
422 strcpy(tmp
+ 4, "..");
423 tmp
+= ctl
->fs_dirsize
;
424 *(uint32_t *) tmp
= 2;
425 strcpy(tmp
+ 4, ".badblocks");
427 *(uint16_t *) tmp
= 1;
428 strcpy(tmp
+ 2, ".");
429 tmp
+= ctl
->fs_dirsize
;
430 *(uint16_t *) tmp
= 1;
431 strcpy(tmp
+ 2, "..");
432 tmp
+= ctl
->fs_dirsize
;
433 *(uint16_t *) tmp
= 2;
434 strcpy(tmp
+ 2, ".badblocks");
436 if (fs_version
< 2) {
437 make_root_inode_v1(ctl
);
440 make_root_inode_v2_v3(ctl
);
443 static void super_set_nzones(const struct fs_control
*ctl
)
445 switch (fs_version
) {
447 Super3
.s_zones
= ctl
->fs_blocks
;
450 Super
.s_zones
= ctl
->fs_blocks
;
453 Super
.s_nzones
= ctl
->fs_blocks
;
458 static void super_init_maxsize(void)
460 switch (fs_version
) {
462 Super3
.s_max_size
= 2147483647L;
465 Super
.s_max_size
= 0x7fffffff;
468 Super
.s_max_size
= (7+512+512*512)*1024;
473 static void super_set_map_blocks(const struct fs_control
*ctl
, unsigned long inodes
)
475 switch (fs_version
) {
477 Super3
.s_imap_blocks
= UPPER(inodes
+ 1, BITS_PER_BLOCK
);
478 Super3
.s_zmap_blocks
= UPPER(ctl
->fs_blocks
- (1 + get_nimaps() + inode_blocks()),
480 Super3
.s_firstdatazone
= first_zone_data();
483 Super
.s_imap_blocks
= UPPER(inodes
+ 1, BITS_PER_BLOCK
);
484 Super
.s_zmap_blocks
= UPPER(ctl
->fs_blocks
- (1 + get_nimaps() + inode_blocks()),
486 Super
.s_firstdatazone
= first_zone_data();
491 static void super_set_magic(const struct fs_control
*ctl
)
493 switch (fs_version
) {
495 Super3
.s_magic
= ctl
->fs_magic
;
498 Super
.s_magic
= ctl
->fs_magic
;
503 static void setup_tables(const struct fs_control
*ctl
) {
504 unsigned long inodes
, zmaps
, imaps
, zones
, i
;
506 super_block_buffer
= xcalloc(1, MINIX_BLOCK_SIZE
);
508 memset(boot_block_buffer
,0,512);
509 super_set_magic(ctl
);
511 if (fs_version
== 3) {
512 Super3
.s_log_zone_size
= 0;
513 Super3
.s_blocksize
= MINIX_BLOCK_SIZE
;
516 Super
.s_log_zone_size
= 0;
519 super_init_maxsize();
520 super_set_nzones(ctl
);
521 zones
= get_nzones();
523 /* some magic nrs: 1 inode / 3 blocks for smaller filesystems,
524 * for one inode / 16 blocks for large ones. mkfs will eventually
525 * crab about too far when getting close to the maximum size. */
526 if (ctl
->fs_inodes
== 0)
527 if (2048 * 1024 < ctl
->fs_blocks
) /* 2GB */
528 inodes
= ctl
->fs_blocks
/ 16;
529 else if (512 * 1024 < ctl
->fs_blocks
) /* 0.5GB */
530 inodes
= ctl
->fs_blocks
/ 8;
532 inodes
= ctl
->fs_blocks
/ 3;
534 inodes
= ctl
->fs_inodes
;
535 /* Round up inode count to fill block size */
536 if (fs_version
== 2 || fs_version
== 3)
537 inodes
= ((inodes
+ MINIX2_INODES_PER_BLOCK
- 1) &
538 ~(MINIX2_INODES_PER_BLOCK
- 1));
540 inodes
= ((inodes
+ MINIX_INODES_PER_BLOCK
- 1) &
541 ~(MINIX_INODES_PER_BLOCK
- 1));
544 Super3
.s_ninodes
= inodes
;
546 if (inodes
> MINIX_MAX_INODES
)
547 inodes
= MINIX_MAX_INODES
;
548 Super
.s_ninodes
= inodes
;
550 super_set_map_blocks(ctl
, inodes
);
551 if (MINIX_MAX_INODES
< first_zone_data())
553 _("First data block at %jd, which is too far (max %d).\n"
554 "Try specifying fewer inodes by passing --inodes <num>"),
555 (intmax_t)first_zone_data(),
557 imaps
= get_nimaps();
558 zmaps
= get_nzmaps();
560 inode_map
= xmalloc(imaps
* MINIX_BLOCK_SIZE
);
561 zone_map
= xmalloc(zmaps
* MINIX_BLOCK_SIZE
);
562 memset(inode_map
,0xff,imaps
* MINIX_BLOCK_SIZE
);
563 memset(zone_map
,0xff,zmaps
* MINIX_BLOCK_SIZE
);
565 for (i
= get_first_zone() ; i
<zones
; i
++)
567 for (i
= MINIX_ROOT_INO
; i
<=inodes
; i
++)
570 inode_buffer
= xmalloc(get_inode_buffer_size());
571 memset(inode_buffer
,0, get_inode_buffer_size());
573 printf(P_("%lu inode\n", "%lu inodes\n", inodes
), inodes
);
574 printf(P_("%lu block\n", "%lu blocks\n", zones
), zones
);
575 printf(_("Firstdatazone=%jd (%jd)\n"),
576 (intmax_t)get_first_zone(), (intmax_t)first_zone_data());
577 printf(_("Zonesize=%zu\n"), (size_t) MINIX_BLOCK_SIZE
<< get_zone_size());
578 printf(_("Maxsize=%zu\n\n"),get_max_size());
582 * Perform a test of a block; return the number of
583 * blocks readable/writable.
585 static size_t do_check(const struct fs_control
*ctl
, char * buffer
, int try, unsigned int current_block
) {
588 /* Seek to the correct loc. */
589 if (lseek(ctl
->device_fd
, current_block
* MINIX_BLOCK_SIZE
, SEEK_SET
) !=
590 current_block
* MINIX_BLOCK_SIZE
)
591 err(MKFS_EX_ERROR
, _("%s: seek failed during testing of blocks"),
595 got
= read(ctl
->device_fd
, buffer
, try * MINIX_BLOCK_SIZE
);
596 if (got
< 0) got
= 0;
597 if (got
& (MINIX_BLOCK_SIZE
- 1 )) {
598 printf(_("Weird values in do_check: probably bugs\n"));
600 got
/= MINIX_BLOCK_SIZE
;
604 static unsigned int currently_testing
= 0;
606 static void alarm_intr(int alnum
__attribute__ ((__unused__
))) {
607 unsigned long zones
= get_nzones();
609 if (currently_testing
>= zones
)
611 signal(SIGALRM
,alarm_intr
);
613 if (!currently_testing
)
615 printf("%d ...", currently_testing
);
619 static void check_blocks(struct fs_control
*ctl
) {
621 static char buffer
[MINIX_BLOCK_SIZE
* TEST_BUFFER_BLOCKS
];
622 unsigned long zones
= get_nzones();
623 unsigned long first_zone
= get_first_zone();
626 signal(SIGALRM
,alarm_intr
);
628 while (currently_testing
< zones
) {
629 if (lseek(ctl
->device_fd
, currently_testing
* MINIX_BLOCK_SIZE
,SEEK_SET
) !=
630 currently_testing
*MINIX_BLOCK_SIZE
)
631 errx(MKFS_EX_ERROR
, _("%s: seek failed in check_blocks"),
633 try = TEST_BUFFER_BLOCKS
;
634 if (currently_testing
+ try > zones
)
635 try = zones
-currently_testing
;
636 got
= do_check(ctl
, buffer
, try, currently_testing
);
637 currently_testing
+= got
;
640 if (currently_testing
< first_zone
)
641 errx(MKFS_EX_ERROR
, _("%s: bad blocks before data-area: "
642 "cannot make fs"), ctl
->device_name
);
643 mark_zone(currently_testing
);
644 ctl
->fs_bad_blocks
++;
647 if (ctl
->fs_bad_blocks
> 0)
648 printf(P_("%d bad block\n", "%d bad blocks\n", ctl
->fs_bad_blocks
), ctl
->fs_bad_blocks
);
651 static void get_list_blocks(struct fs_control
*ctl
, char *filename
) {
653 unsigned long blockno
;
655 listfile
= fopen(filename
,"r");
656 if (listfile
== NULL
)
657 err(MKFS_EX_ERROR
, _("%s: can't open file of bad blocks"),
660 while (!feof(listfile
)) {
661 if (fscanf(listfile
,"%lu\n", &blockno
) != 1) {
662 printf(_("badblock number input error on line %d\n"), ctl
->fs_bad_blocks
+ 1);
663 errx(MKFS_EX_ERROR
, _("%s: cannot read badblocks file"),
667 ctl
->fs_bad_blocks
++;
671 if (ctl
->fs_bad_blocks
> 0)
672 printf(P_("%d bad block\n", "%d bad blocks\n", ctl
->fs_bad_blocks
), ctl
->fs_bad_blocks
);
675 static int find_super_magic(const struct fs_control
*ctl
)
677 switch (fs_version
) {
679 if (ctl
->fs_namelen
== 14)
680 return MINIX_SUPER_MAGIC
;
681 return MINIX_SUPER_MAGIC2
;
683 if (ctl
->fs_namelen
== 14)
684 return MINIX2_SUPER_MAGIC
;
685 return MINIX2_SUPER_MAGIC2
;
687 return MINIX3_SUPER_MAGIC
;
693 static void determine_device_blocks(struct fs_control
*ctl
, const struct stat
*statbuf
)
695 unsigned long long dev_blocks
= 0;
697 if (S_ISBLK(statbuf
->st_mode
)) {
700 if (blkdev_get_sector_size(ctl
->device_fd
, §orsize
) == -1)
701 sectorsize
= DEFAULT_SECTOR_SIZE
; /* kernel < 2.3.3 */
702 if (MINIX_BLOCK_SIZE
< sectorsize
)
703 errx(MKFS_EX_ERROR
, _("block size smaller than physical "
704 "sector size of %s"), ctl
->device_name
);
705 if (blkdev_get_size(ctl
->device_fd
, &dev_blocks
) == -1)
706 errx(MKFS_EX_ERROR
, _("cannot determine size of %s"), ctl
->device_name
);
707 dev_blocks
/= MINIX_BLOCK_SIZE
;
708 } else if (!S_ISBLK(statbuf
->st_mode
))
709 dev_blocks
= statbuf
->st_size
/ MINIX_BLOCK_SIZE
;
711 ctl
->fs_blocks
= dev_blocks
;
712 else if (dev_blocks
< ctl
->fs_blocks
)
714 _("%s: requested blocks (%llu) exceeds available (%llu) blocks\n"),
715 ctl
->device_name
, ctl
->fs_blocks
, dev_blocks
);
716 if (ctl
->fs_blocks
< 10)
717 errx(MKFS_EX_ERROR
, _("%s: number of blocks too small"), ctl
->device_name
);
718 if (fs_version
== 1 && ctl
->fs_blocks
> MINIX_MAX_INODES
)
719 ctl
->fs_blocks
= MINIX_MAX_INODES
;
720 if (ctl
->fs_blocks
> (4 + ((MINIX_MAX_INODES
- 4) * BITS_PER_BLOCK
)))
721 ctl
->fs_blocks
= 4 + ((MINIX_MAX_INODES
- 4) * BITS_PER_BLOCK
); /* Utter maximum: Clip. */
724 static void check_user_instructions(struct fs_control
*ctl
)
726 switch (fs_version
) {
729 if (ctl
->fs_namelen
== 14 || ctl
->fs_namelen
== 30)
730 ctl
->fs_dirsize
= ctl
->fs_namelen
+ 2;
732 errx(MKFS_EX_ERROR
, _("unsupported name length: %d"), ctl
->fs_namelen
);
735 if (ctl
->fs_namelen
== 60)
736 ctl
->fs_dirsize
= ctl
->fs_namelen
+ 4;
738 errx(MKFS_EX_ERROR
, _("unsupported name length: %d"), ctl
->fs_namelen
);
741 errx(MKFS_EX_ERROR
, _("unsupported minix file system version: %d"), fs_version
);
743 ctl
->fs_magic
= find_super_magic(ctl
);
746 int main(int argc
, char ** argv
)
748 struct fs_control ctl
= {
749 .fs_namelen
= 30, /* keep in sync with DEFAULT_FS_VERSION */
754 char * listfile
= NULL
;
756 OPT_LOCK
= CHAR_MAX
+ 1
758 static const struct option longopts
[] = {
759 {"namelength", required_argument
, NULL
, 'n'},
760 {"inodes", required_argument
, NULL
, 'i'},
761 {"check", no_argument
, NULL
, 'c'},
762 {"badblocks", required_argument
, NULL
, 'l'},
763 {"version", no_argument
, NULL
, 'V'},
764 {"help", no_argument
, NULL
, 'h'},
765 {"lock",optional_argument
, NULL
, OPT_LOCK
},
769 setlocale(LC_ALL
, "");
770 bindtextdomain(PACKAGE
, LOCALEDIR
);
772 close_stdout_atexit();
774 strutils_set_exitcode(MKFS_EX_USAGE
);
776 while ((i
= getopt_long(argc
, argv
, "1v23n:i:cl:Vh", longopts
, NULL
)) != -1)
781 case 'v': /* kept for backwards compatibility */
782 warnx(_("-v is ambiguous, use '-2' instead"));
792 ctl
.fs_namelen
= strtou16_or_err(optarg
,
793 _("failed to parse maximum length of filenames"));
796 ctl
.fs_inodes
= strtoul_or_err(optarg
,
797 _("failed to parse number of inodes"));
800 ctl
.check_blocks
= 1;
810 ctl
.lockmode
= optarg
;
814 print_version(MKFS_EX_OK
);
818 errtryhelp(MKFS_EX_USAGE
);
823 ctl
.device_name
= argv
[0];
828 ctl
.fs_blocks
= strtoul_or_err(argv
[0], _("failed to parse number of blocks"));
830 if (!ctl
.device_name
) {
831 warnx(_("no device specified"));
832 errtryhelp(MKFS_EX_USAGE
);
834 check_user_instructions(&ctl
);
835 if (is_mounted(ctl
.device_name
))
836 errx(MKFS_EX_ERROR
, _("%s is mounted; will not make a filesystem here!"),
838 if (stat(ctl
.device_name
, &statbuf
) < 0)
839 err(MKFS_EX_ERROR
, _("stat of %s failed"), ctl
.device_name
);
840 ctl
.device_fd
= open_blkdev_or_file(&statbuf
, ctl
.device_name
, O_RDWR
);
841 if (ctl
.device_fd
< 0)
842 err(MKFS_EX_ERROR
, _("cannot open %s"), ctl
.device_name
);
843 if (blkdev_lock(ctl
.device_fd
, ctl
.device_name
, ctl
.lockmode
) != 0)
845 determine_device_blocks(&ctl
, &statbuf
);
847 if (ctl
.check_blocks
)
850 get_list_blocks(&ctl
, listfile
);
852 make_root_inode(&ctl
);
853 make_bad_inode(&ctl
);
855 mark_good_blocks(&ctl
);
857 if (close_fd(ctl
.device_fd
) != 0)
858 err(MKFS_EX_ERROR
, _("write failed"));