1/* vi: set sw=4 ts=4: */ 2/* 3 * mkfs.c - make a linux (minix) file-system. 4 * 5 * (C) 1991 Linus Torvalds. This file may be redistributed as per 6 * the Linux copyright. 7 */ 8 9/* 10 * DD.MM.YY 11 * 12 * 24.11.91 - Time began. Used the fsck sources to get started. 13 * 14 * 25.11.91 - Corrected some bugs. Added support for ".badblocks" 15 * The algorithm for ".badblocks" is a bit weird, but 16 * it should work. Oh, well. 17 * 18 * 25.01.92 - Added the -l option for getting the list of bad blocks 19 * out of a named file. (Dave Rivers, rivers@ponds.uucp) 20 * 21 * 28.02.92 - Added %-information when using -c. 22 * 23 * 28.02.93 - Added support for other namelengths than the original 24 * 14 characters so that I can test the new kernel routines.. 25 * 26 * 09.10.93 - Make exit status conform to that required by fsutil 27 * (Rik Faith, faith@cs.unc.edu) 28 * 29 * 31.10.93 - Added inode request feature, for backup floppies: use 30 * 32 inodes, for a news partition use more. 31 * (Scott Heavner, sdh@po.cwru.edu) 32 * 33 * 03.01.94 - Added support for file system valid flag. 34 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) 35 * 36 * 30.10.94 - added support for v2 filesystem 37 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) 38 * 39 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted 40 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs 41 * program. (Daniel Quinlan, quinlan@yggdrasil.com) 42 * 43 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that 44 * the filesystem is not misidentified as a MS-DOS FAT filesystem. 45 * (Daniel Quinlan, quinlan@yggdrasil.com) 46 * 47 * 02.07.96 - Added small patch from Russell King to make the program a 48 * good deal more portable (janl@math.uio.no) 49 * 50 * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] 51 * 52 * -c for readability checking (SLOW!) 53 * -l for getting a list of bad blocks from a file. 54 * -n for namelength (currently the kernel only uses 14 or 30) 55 * -i for number of inodes 56 * -v for v2 filesystem 57 * 58 * The device may be a block device or a image of one, but this isn't 59 * enforced (but it's not much fun on a character device :-). 60 * 61 * Modified for BusyBox by Erik Andersen <andersen@debian.org> -- 62 * removed getopt based parser and added a hand rolled one. 63 */ 64 65#include "libbb.h" 66#include <mntent.h> 67 68#include "minix.h" 69 70#define DEBUG 0 71 72/* If debugging, store the very same times/uids/gids for image consistency */ 73#if DEBUG 74# define CUR_TIME 0 75# define GETUID 0 76# define GETGID 0 77#else 78# define CUR_TIME time(NULL) 79# define GETUID getuid() 80# define GETGID getgid() 81#endif 82 83enum { 84 MAX_GOOD_BLOCKS = 512, 85 TEST_BUFFER_BLOCKS = 16, 86}; 87 88#if !ENABLE_FEATURE_MINIX2 89enum { version2 = 0 }; 90#endif 91 92struct globals { 93 int dev_fd; 94 95#if ENABLE_FEATURE_MINIX2 96 smallint version2; 97#define version2 G.version2 98#endif 99 char *device_name; 100 uint32_t total_blocks; 101 int badblocks; 102 int namelen; 103 int dirsize; 104 int magic; 105 char *inode_buffer; 106 char *inode_map; 107 char *zone_map; 108 int used_good_blocks; 109 unsigned long req_nr_inodes; 110 unsigned currently_testing; 111 112 113 char root_block[BLOCK_SIZE]; 114 char super_block_buffer[BLOCK_SIZE]; 115 char boot_block_buffer[512]; 116 unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; 117 /* check_blocks(): buffer[] was the biggest static in entire bbox */ 118 char check_blocks_buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; 119}; 120 121#define G (*ptr_to_globals) 122 123static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n) 124{ 125 return (size + n-1) / n; 126} 127 128#define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1) 129#define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1) 130 131#define SB (*(struct minix_super_block*)G.super_block_buffer) 132 133#define SB_INODES (SB.s_ninodes) 134#define SB_IMAPS (SB.s_imap_blocks) 135#define SB_ZMAPS (SB.s_zmap_blocks) 136#define SB_FIRSTZONE (SB.s_firstdatazone) 137#define SB_ZONE_SIZE (SB.s_log_zone_size) 138#define SB_MAXSIZE (SB.s_max_size) 139#define SB_MAGIC (SB.s_magic) 140 141#if !ENABLE_FEATURE_MINIX2 142# define SB_ZONES (SB.s_nzones) 143# define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK) 144#else 145# define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones) 146# define INODE_BLOCKS div_roundup(SB_INODES, \ 147 version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK) 148#endif 149 150#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) 151#define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS) 152 153/* Before you ask "where they come from?": */ 154/* setbit/clrbit are supplied by sys/param.h */ 155 156static int minix_bit(const char* a, unsigned i) 157{ 158 return a[i >> 3] & (1<<(i & 7)); 159} 160 161static void minix_setbit(char *a, unsigned i) 162{ 163 setbit(a, i); 164} 165static void minix_clrbit(char *a, unsigned i) 166{ 167 clrbit(a, i); 168} 169 170/* Note: do not assume 0/1, it is 0/nonzero */ 171#define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1) 172/*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/ 173 174#define mark_inode(x) minix_setbit(G.inode_map,(x)) 175#define unmark_inode(x) minix_clrbit(G.inode_map,(x)) 176#define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1) 177#define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1) 178 179#ifndef BLKGETSIZE 180# define BLKGETSIZE _IO(0x12,96) /* return device size */ 181#endif 182 183 184static long valid_offset(int fd, int offset) 185{ 186 char ch; 187 188 if (lseek(fd, offset, SEEK_SET) < 0) 189 return 0; 190 if (read(fd, &ch, 1) < 1) 191 return 0; 192 return 1; 193} 194 195static int count_blocks(int fd) 196{ 197 int high, low; 198 199 low = 0; 200 for (high = 1; valid_offset(fd, high); high *= 2) 201 low = high; 202 203 while (low < high - 1) { 204 const int mid = (low + high) / 2; 205 206 if (valid_offset(fd, mid)) 207 low = mid; 208 else 209 high = mid; 210 } 211 valid_offset(fd, 0); 212 return (low + 1); 213} 214 215static int get_size(const char *file) 216{ 217 int fd; 218 long size; 219 220 fd = xopen(file, O_RDWR); 221 if (ioctl(fd, BLKGETSIZE, &size) >= 0) { 222 close(fd); 223 return (size * 512); 224 } 225 226 size = count_blocks(fd); 227 close(fd); 228 return size; 229} 230 231static void write_tables(void) 232{ 233 /* Mark the super block valid. */ 234 SB.s_state |= MINIX_VALID_FS; 235 SB.s_state &= ~MINIX_ERROR_FS; 236 237 msg_eol = "seek to 0 failed"; 238 xlseek(G.dev_fd, 0, SEEK_SET); 239 240 msg_eol = "cannot clear boot sector"; 241 xwrite(G.dev_fd, G.boot_block_buffer, 512); 242 243 msg_eol = "seek to BLOCK_SIZE failed"; 244 xlseek(G.dev_fd, BLOCK_SIZE, SEEK_SET); 245 246 msg_eol = "cannot write superblock"; 247 xwrite(G.dev_fd, G.super_block_buffer, BLOCK_SIZE); 248 249 msg_eol = "cannot write inode map"; 250 xwrite(G.dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE); 251 252 msg_eol = "cannot write zone map"; 253 xwrite(G.dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE); 254 255 msg_eol = "cannot write inodes"; 256 xwrite(G.dev_fd, G.inode_buffer, INODE_BUFFER_SIZE); 257 258 msg_eol = "\n"; 259} 260 261static void write_block(int blk, char *buffer) 262{ 263 xlseek(G.dev_fd, blk * BLOCK_SIZE, SEEK_SET); 264 xwrite(G.dev_fd, buffer, BLOCK_SIZE); 265} 266 267static int get_free_block(void) 268{ 269 int blk; 270 271 if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS) 272 bb_error_msg_and_die("too many bad blocks"); 273 if (G.used_good_blocks) 274 blk = G.good_blocks_table[G.used_good_blocks - 1] + 1; 275 else 276 blk = SB_FIRSTZONE; 277 while (blk < SB_ZONES && zone_in_use(blk)) 278 blk++; 279 if (blk >= SB_ZONES) 280 bb_error_msg_and_die("not enough good blocks"); 281 G.good_blocks_table[G.used_good_blocks] = blk; 282 G.used_good_blocks++; 283 return blk; 284} 285 286static void mark_good_blocks(void) 287{ 288 int blk; 289 290 for (blk = 0; blk < G.used_good_blocks; blk++) 291 mark_zone(G.good_blocks_table[blk]); 292} 293 294static int next(int zone) 295{ 296 if (!zone) 297 zone = SB_FIRSTZONE - 1; 298 while (++zone < SB_ZONES) 299 if (zone_in_use(zone)) 300 return zone; 301 return 0; 302} 303 304static void make_bad_inode(void) 305{ 306 struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO]; 307 int i, j, zone; 308 int ind = 0, dind = 0; 309 unsigned short ind_block[BLOCK_SIZE >> 1]; 310 unsigned short dind_block[BLOCK_SIZE >> 1]; 311 312#define NEXT_BAD (zone = next(zone)) 313 314 if (!G.badblocks) 315 return; 316 mark_inode(MINIX_BAD_INO); 317 inode->i_nlinks = 1; 318 /* BTW, setting this makes all images different */ 319 /* it's harder to check for bugs then - diff isn't helpful :(... */ 320 inode->i_time = CUR_TIME; 321 inode->i_mode = S_IFREG + 0000; 322 inode->i_size = G.badblocks * BLOCK_SIZE; 323 zone = next(0); 324 for (i = 0; i < 7; i++) { 325 inode->i_zone[i] = zone; 326 if (!NEXT_BAD) 327 goto end_bad; 328 } 329 inode->i_zone[7] = ind = get_free_block(); 330 memset(ind_block, 0, BLOCK_SIZE); 331 for (i = 0; i < 512; i++) { 332 ind_block[i] = zone; 333 if (!NEXT_BAD) 334 goto end_bad; 335 } 336 inode->i_zone[8] = dind = get_free_block(); 337 memset(dind_block, 0, BLOCK_SIZE); 338 for (i = 0; i < 512; i++) { 339 write_block(ind, (char *) ind_block); 340 dind_block[i] = ind = get_free_block(); 341 memset(ind_block, 0, BLOCK_SIZE); 342 for (j = 0; j < 512; j++) { 343 ind_block[j] = zone; 344 if (!NEXT_BAD) 345 goto end_bad; 346 } 347 } 348 bb_error_msg_and_die("too many bad blocks"); 349 end_bad: 350 if (ind) 351 write_block(ind, (char *) ind_block); 352 if (dind) 353 write_block(dind, (char *) dind_block); 354} 355 356#if ENABLE_FEATURE_MINIX2 357static void make_bad_inode2(void) 358{ 359 struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO]; 360 int i, j, zone; 361 int ind = 0, dind = 0; 362 unsigned long ind_block[BLOCK_SIZE >> 2]; 363 unsigned long dind_block[BLOCK_SIZE >> 2]; 364 365 if (!G.badblocks) 366 return; 367 mark_inode(MINIX_BAD_INO); 368 inode->i_nlinks = 1; 369 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME; 370 inode->i_mode = S_IFREG + 0000; 371 inode->i_size = G.badblocks * BLOCK_SIZE; 372 zone = next(0); 373 for (i = 0; i < 7; i++) { 374 inode->i_zone[i] = zone; 375 if (!NEXT_BAD) 376 goto end_bad; 377 } 378 inode->i_zone[7] = ind = get_free_block(); 379 memset(ind_block, 0, BLOCK_SIZE); 380 for (i = 0; i < 256; i++) { 381 ind_block[i] = zone; 382 if (!NEXT_BAD) 383 goto end_bad; 384 } 385 inode->i_zone[8] = dind = get_free_block(); 386 memset(dind_block, 0, BLOCK_SIZE); 387 for (i = 0; i < 256; i++) { 388 write_block(ind, (char *) ind_block); 389 dind_block[i] = ind = get_free_block(); 390 memset(ind_block, 0, BLOCK_SIZE); 391 for (j = 0; j < 256; j++) { 392 ind_block[j] = zone; 393 if (!NEXT_BAD) 394 goto end_bad; 395 } 396 } 397 /* Could make triple indirect block here */ 398 bb_error_msg_and_die("too many bad blocks"); 399 end_bad: 400 if (ind) 401 write_block(ind, (char *) ind_block); 402 if (dind) 403 write_block(dind, (char *) dind_block); 404} 405#else 406void make_bad_inode2(void); 407#endif 408 409static void make_root_inode(void) 410{ 411 struct minix1_inode *inode = &INODE_BUF1[MINIX_ROOT_INO]; 412 413 mark_inode(MINIX_ROOT_INO); 414 inode->i_zone[0] = get_free_block(); 415 inode->i_nlinks = 2; 416 inode->i_time = CUR_TIME; 417 if (G.badblocks) 418 inode->i_size = 3 * G.dirsize; 419 else { 420 G.root_block[2 * G.dirsize] = '\0'; 421 G.root_block[2 * G.dirsize + 1] = '\0'; 422 inode->i_size = 2 * G.dirsize; 423 } 424 inode->i_mode = S_IFDIR + 0755; 425 inode->i_uid = GETUID; 426 if (inode->i_uid) 427 inode->i_gid = GETGID; 428 write_block(inode->i_zone[0], G.root_block); 429} 430 431#if ENABLE_FEATURE_MINIX2 432static void make_root_inode2(void) 433{ 434 struct minix2_inode *inode = &INODE_BUF2[MINIX_ROOT_INO]; 435 436 mark_inode(MINIX_ROOT_INO); 437 inode->i_zone[0] = get_free_block(); 438 inode->i_nlinks = 2; 439 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME; 440 if (G.badblocks) 441 inode->i_size = 3 * G.dirsize; 442 else { 443 G.root_block[2 * G.dirsize] = '\0'; 444 G.root_block[2 * G.dirsize + 1] = '\0'; 445 inode->i_size = 2 * G.dirsize; 446 } 447 inode->i_mode = S_IFDIR + 0755; 448 inode->i_uid = GETUID; 449 if (inode->i_uid) 450 inode->i_gid = GETGID; 451 write_block(inode->i_zone[0], G.root_block); 452} 453#else 454void make_root_inode2(void); 455#endif 456 457/* 458 * Perform a test of a block; return the number of 459 * blocks readable. 460 */ 461static size_t do_check(char *buffer, size_t try, unsigned current_block) 462{ 463 ssize_t got; 464 465 /* Seek to the correct loc. */ 466 msg_eol = "seek failed during testing of blocks"; 467 xlseek(G.dev_fd, current_block * BLOCK_SIZE, SEEK_SET); 468 msg_eol = "\n"; 469 470 /* Try the read */ 471 got = read(G.dev_fd, buffer, try * BLOCK_SIZE); 472 if (got < 0) 473 got = 0; 474 try = ((size_t)got) / BLOCK_SIZE; 475 476 if (got & (BLOCK_SIZE - 1)) 477 fprintf(stderr, "Short read at block %u\n", (unsigned)(current_block + try)); 478 return try; 479} 480 481static void alarm_intr(int alnum) 482{ 483 if (G.currently_testing >= SB_ZONES) 484 return; 485 signal(SIGALRM, alarm_intr); 486 alarm(5); 487 if (!G.currently_testing) 488 return; 489 printf("%d ...", G.currently_testing); 490 fflush(stdout); 491} 492 493static void check_blocks(void) 494{ 495 size_t try, got; 496 497 G.currently_testing = 0; 498 signal(SIGALRM, alarm_intr); 499 alarm(5); 500 while (G.currently_testing < SB_ZONES) { 501 msg_eol = "seek failed in check_blocks"; 502 xlseek(G.dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET); 503 msg_eol = "\n"; 504 try = TEST_BUFFER_BLOCKS; 505 if (G.currently_testing + try > SB_ZONES) 506 try = SB_ZONES - G.currently_testing; 507 got = do_check(G.check_blocks_buffer, try, G.currently_testing); 508 G.currently_testing += got; 509 if (got == try) 510 continue; 511 if (G.currently_testing < SB_FIRSTZONE) 512 bb_error_msg_and_die("bad blocks before data-area: cannot make fs"); 513 mark_zone(G.currently_testing); 514 G.badblocks++; 515 G.currently_testing++; 516 } 517 alarm(0); 518 printf("%d bad block(s)\n", G.badblocks); 519} 520 521static void get_list_blocks(char *filename) 522{ 523 FILE *listfile; 524 unsigned long blockno; 525 526 listfile = xfopen(filename, "r"); 527 while (!feof(listfile)) { 528 fscanf(listfile, "%ld\n", &blockno); 529 mark_zone(blockno); 530 G.badblocks++; 531 } 532 printf("%d bad block(s)\n", G.badblocks); 533} 534 535static void setup_tables(void) 536{ 537 unsigned long inodes; 538 unsigned norm_firstzone; 539 unsigned sb_zmaps; 540 unsigned i; 541 542 /* memset(G.super_block_buffer, 0, BLOCK_SIZE); */ 543 /* memset(G.boot_block_buffer, 0, 512); */ 544 SB_MAGIC = G.magic; 545 SB_ZONE_SIZE = 0; 546 SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024; 547 if (version2) 548 SB.s_zones = G.total_blocks; 549 else 550 SB.s_nzones = G.total_blocks; 551 552 /* some magic nrs: 1 inode / 3 blocks */ 553 if (G.req_nr_inodes == 0) 554 inodes = G.total_blocks / 3; 555 else 556 inodes = G.req_nr_inodes; 557 /* Round up inode count to fill block size */ 558 if (version2) 559 inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) & 560 ~(MINIX2_INODES_PER_BLOCK - 1); 561 else 562 inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) & 563 ~(MINIX1_INODES_PER_BLOCK - 1); 564 if (inodes > 65535) 565 inodes = 65535; 566 SB_INODES = inodes; 567 SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK); 568 569 /* Real bad hack but overwise mkfs.minix can be thrown 570 * in infinite loop... 571 * try: 572 * dd if=/dev/zero of=test.fs count=10 bs=1024 573 * mkfs.minix -i 200 test.fs 574 */ 575 /* This code is not insane: NORM_FIRSTZONE is not a constant, 576 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */ 577 i = 999; 578 SB_ZMAPS = 0; 579 do { 580 norm_firstzone = NORM_FIRSTZONE; 581 sb_zmaps = div_roundup(G.total_blocks - norm_firstzone + 1, BITS_PER_BLOCK); 582 if (SB_ZMAPS == sb_zmaps) goto got_it; 583 SB_ZMAPS = sb_zmaps; 584 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */ 585 } while (--i); 586 bb_error_msg_and_die("incompatible size/inode count, try different -i N"); 587 got_it: 588 589 SB_FIRSTZONE = norm_firstzone; 590 G.inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE); 591 G.zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE); 592 memset(G.inode_map, 0xff, SB_IMAPS * BLOCK_SIZE); 593 memset(G.zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE); 594 for (i = SB_FIRSTZONE; i < SB_ZONES; i++) 595 unmark_zone(i); 596 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++) 597 unmark_inode(i); 598 G.inode_buffer = xzalloc(INODE_BUFFER_SIZE); 599 printf("%ld inodes\n", (long)SB_INODES); 600 printf("%ld blocks\n", (long)SB_ZONES); 601 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone); 602 printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE); 603 printf("Maxsize=%ld\n", (long)SB_MAXSIZE); 604} 605 606int mkfs_minix_main(int argc, char **argv); 607int mkfs_minix_main(int argc, char **argv) 608{ 609 struct mntent *mp; 610 unsigned opt; 611 char *tmp; 612 struct stat statbuf; 613 char *str_i, *str_n; 614 char *listfile = NULL; 615 616 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 617/* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */ 618 G.namelen = 30; 619 G.dirsize = 32; 620 G.magic = MINIX1_SUPER_MAGIC2; 621 622 if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE) 623 bb_error_msg_and_die("bad inode size"); 624#if ENABLE_FEATURE_MINIX2 625 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) 626 bb_error_msg_and_die("bad inode size"); 627#endif 628 629 opt = getopt32(argv, "ci:l:n:v", &str_i, &listfile, &str_n); 630 argv += optind; 631 //if (opt & 1) -c 632 if (opt & 2) G.req_nr_inodes = xatoul(str_i); // -i 633 //if (opt & 4) -l 634 if (opt & 8) { // -n 635 G.namelen = xatoi_u(str_n); 636 if (G.namelen == 14) G.magic = MINIX1_SUPER_MAGIC; 637 else if (G.namelen == 30) G.magic = MINIX1_SUPER_MAGIC2; 638 else bb_show_usage(); 639 G.dirsize = G.namelen + 2; 640 } 641 if (opt & 0x10) { // -v 642#if ENABLE_FEATURE_MINIX2 643 version2 = 1; 644#else 645 bb_error_msg_and_die("not compiled with minix v2 support"); 646#endif 647 } 648 649 G.device_name = *argv++; 650 if (!G.device_name) 651 bb_show_usage(); 652 if (*argv) 653 G.total_blocks = xatou32(*argv); 654 else 655 G.total_blocks = get_size(G.device_name) / 1024; 656 657 if (G.total_blocks < 10) 658 bb_error_msg_and_die("must have at least 10 blocks"); 659 660 if (version2) { 661 G.magic = MINIX2_SUPER_MAGIC2; 662 if (G.namelen == 14) 663 G.magic = MINIX2_SUPER_MAGIC; 664 } else if (G.total_blocks > 65535) 665 G.total_blocks = 65535; 666 667 /* Check if it is mounted */ 668 mp = find_mount_point(G.device_name, NULL); 669 if (mp && strcmp(G.device_name, mp->mnt_fsname) == 0) 670 bb_error_msg_and_die("%s is mounted on %s; " 671 "refusing to make a filesystem", 672 G.device_name, mp->mnt_dir); 673 674 G.dev_fd = xopen(G.device_name, O_RDWR); 675 if (fstat(G.dev_fd, &statbuf) < 0) 676 bb_error_msg_and_die("cannot stat %s", G.device_name); 677 if (!S_ISBLK(statbuf.st_mode)) 678 opt &= ~1; // clear -c (check) 679 680/* I don't know why someone has special code to prevent mkfs.minix 681 * on IDE devices. Why IDE but not SCSI, etc?... */ 682 683 tmp = G.root_block; 684 *(short *) tmp = 1; 685 strcpy(tmp + 2, "."); 686 tmp += G.dirsize; 687 *(short *) tmp = 1; 688 strcpy(tmp + 2, ".."); 689 tmp += G.dirsize; 690 *(short *) tmp = 2; 691 strcpy(tmp + 2, ".badblocks"); 692 693 setup_tables(); 694 695 if (opt & 1) // -c ? 696 check_blocks(); 697 else if (listfile) 698 get_list_blocks(listfile); 699 700 if (version2) { 701 make_root_inode2(); 702 make_bad_inode2(); 703 } else { 704 make_root_inode(); 705 make_bad_inode(); 706 } 707 708 mark_good_blocks(); 709 write_tables(); 710 return 0; 711} 712