mkfs_minix.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * mkfs.c - make a linux (minix) file-system.
  4. *
  5. * (C) 1991 Linus Torvalds.
  6. *
  7. * Licensed under GPLv2, see file LICENSE in this source tree.
  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. //usage:#define mkfs_minix_trivial_usage
  65. //usage: "[-c | -l FILE] [-nXX] [-iXX] BLOCKDEV [KBYTES]"
  66. //usage:#define mkfs_minix_full_usage "\n\n"
  67. //usage: "Make a MINIX filesystem\n"
  68. //usage: "\n -c Check device for bad blocks"
  69. //usage: "\n -n [14|30] Maximum length of filenames"
  70. //usage: "\n -i INODES Number of inodes for the filesystem"
  71. //usage: "\n -l FILE Read bad blocks list from FILE"
  72. //usage: "\n -v Make version 2 filesystem"
  73. #include "libbb.h"
  74. #include <mntent.h>
  75. #include "minix.h"
  76. /* Store the very same times/uids/gids for image consistency */
  77. #if 1
  78. # define CUR_TIME 0
  79. # define GETUID 0
  80. # define GETGID 0
  81. #else
  82. /* Was using this. Is it useful? NB: this will break testsuite */
  83. # define CUR_TIME time(NULL)
  84. # define GETUID getuid()
  85. # define GETGID getgid()
  86. #endif
  87. enum {
  88. MAX_GOOD_BLOCKS = 512,
  89. TEST_BUFFER_BLOCKS = 16,
  90. };
  91. #if !ENABLE_FEATURE_MINIX2
  92. enum { version2 = 0 };
  93. #endif
  94. enum { dev_fd = 3 };
  95. struct globals {
  96. #if ENABLE_FEATURE_MINIX2
  97. smallint version2;
  98. #define version2 G.version2
  99. #endif
  100. char *device_name;
  101. uint32_t total_blocks;
  102. int badblocks;
  103. int namelen;
  104. int dirsize;
  105. int magic;
  106. char *inode_buffer;
  107. char *inode_map;
  108. char *zone_map;
  109. int used_good_blocks;
  110. unsigned long req_nr_inodes;
  111. 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];
  118. unsigned short ind_block1[BLOCK_SIZE >> 1];
  119. unsigned short dind_block1[BLOCK_SIZE >> 1];
  120. unsigned long ind_block2[BLOCK_SIZE >> 2];
  121. unsigned long dind_block2[BLOCK_SIZE >> 2];
  122. };
  123. #define G (*ptr_to_globals)
  124. #define INIT_G() do { \
  125. SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
  126. } while (0)
  127. static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
  128. {
  129. return (size + n-1) / n;
  130. }
  131. #define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
  132. #define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
  133. #define SB (*(struct minix_superblock*)G.superblock_buffer)
  134. #define SB_INODES (SB.s_ninodes)
  135. #define SB_IMAPS (SB.s_imap_blocks)
  136. #define SB_ZMAPS (SB.s_zmap_blocks)
  137. #define SB_FIRSTZONE (SB.s_firstdatazone)
  138. #define SB_ZONE_SIZE (SB.s_log_zone_size)
  139. #define SB_MAXSIZE (SB.s_max_size)
  140. #define SB_MAGIC (SB.s_magic)
  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. #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
  150. #define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
  151. /* Before you ask "where they come from?": */
  152. /* setbit/clrbit are supplied by sys/param.h */
  153. static int minix_bit(const char* a, unsigned i)
  154. {
  155. return a[i >> 3] & (1<<(i & 7));
  156. }
  157. static void minix_setbit(char *a, unsigned i)
  158. {
  159. setbit(a, i);
  160. }
  161. static void minix_clrbit(char *a, unsigned i)
  162. {
  163. clrbit(a, i);
  164. }
  165. /* Note: do not assume 0/1, it is 0/nonzero */
  166. #define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
  167. /*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
  168. #define mark_inode(x) minix_setbit(G.inode_map,(x))
  169. #define unmark_inode(x) minix_clrbit(G.inode_map,(x))
  170. #define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
  171. #define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
  172. #ifndef BLKGETSIZE
  173. # define BLKGETSIZE _IO(0x12,96) /* return device size */
  174. #endif
  175. static void write_tables(void)
  176. {
  177. /* Mark the superblock valid. */
  178. SB.s_state |= MINIX_VALID_FS;
  179. SB.s_state &= ~MINIX_ERROR_FS;
  180. msg_eol = "seek to 0 failed";
  181. xlseek(dev_fd, 0, SEEK_SET);
  182. msg_eol = "can't clear boot sector";
  183. xwrite(dev_fd, G.boot_block_buffer, 512);
  184. msg_eol = "seek to BLOCK_SIZE failed";
  185. xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
  186. msg_eol = "can't write superblock";
  187. xwrite(dev_fd, G.superblock_buffer, BLOCK_SIZE);
  188. msg_eol = "can't write inode map";
  189. xwrite(dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE);
  190. msg_eol = "can't write zone map";
  191. xwrite(dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE);
  192. msg_eol = "can't write inodes";
  193. xwrite(dev_fd, G.inode_buffer, INODE_BUFFER_SIZE);
  194. msg_eol = "\n";
  195. }
  196. static void write_block(int blk, char *buffer)
  197. {
  198. xlseek(dev_fd, blk * BLOCK_SIZE, SEEK_SET);
  199. xwrite(dev_fd, buffer, BLOCK_SIZE);
  200. }
  201. static int get_free_block(void)
  202. {
  203. int blk;
  204. if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
  205. bb_error_msg_and_die("too many bad blocks");
  206. if (G.used_good_blocks)
  207. blk = G.good_blocks_table[G.used_good_blocks - 1] + 1;
  208. else
  209. blk = SB_FIRSTZONE;
  210. while (blk < SB_ZONES && zone_in_use(blk))
  211. blk++;
  212. if (blk >= SB_ZONES)
  213. bb_error_msg_and_die("not enough good blocks");
  214. G.good_blocks_table[G.used_good_blocks] = blk;
  215. G.used_good_blocks++;
  216. return blk;
  217. }
  218. static void mark_good_blocks(void)
  219. {
  220. int blk;
  221. for (blk = 0; blk < G.used_good_blocks; blk++)
  222. mark_zone(G.good_blocks_table[blk]);
  223. }
  224. static int next(int zone)
  225. {
  226. if (!zone)
  227. zone = SB_FIRSTZONE - 1;
  228. while (++zone < SB_ZONES)
  229. if (zone_in_use(zone))
  230. return zone;
  231. return 0;
  232. }
  233. static void make_bad_inode(void)
  234. {
  235. struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO];
  236. int i, j, zone;
  237. int ind = 0, dind = 0;
  238. /* moved to globals to reduce stack usage
  239. unsigned short ind_block[BLOCK_SIZE >> 1];
  240. unsigned short dind_block[BLOCK_SIZE >> 1];
  241. */
  242. #define ind_block (G.ind_block1)
  243. #define dind_block (G.dind_block1)
  244. #define NEXT_BAD (zone = next(zone))
  245. if (!G.badblocks)
  246. return;
  247. mark_inode(MINIX_BAD_INO);
  248. inode->i_nlinks = 1;
  249. /* BTW, setting this makes all images different */
  250. /* it's harder to check for bugs then - diff isn't helpful :(... */
  251. inode->i_time = CUR_TIME;
  252. inode->i_mode = S_IFREG + 0000;
  253. inode->i_size = G.badblocks * BLOCK_SIZE;
  254. zone = next(0);
  255. for (i = 0; i < 7; i++) {
  256. inode->i_zone[i] = zone;
  257. if (!NEXT_BAD)
  258. goto end_bad;
  259. }
  260. inode->i_zone[7] = ind = get_free_block();
  261. memset(ind_block, 0, BLOCK_SIZE);
  262. for (i = 0; i < 512; i++) {
  263. ind_block[i] = zone;
  264. if (!NEXT_BAD)
  265. goto end_bad;
  266. }
  267. inode->i_zone[8] = dind = get_free_block();
  268. memset(dind_block, 0, BLOCK_SIZE);
  269. for (i = 0; i < 512; i++) {
  270. write_block(ind, (char *) ind_block);
  271. dind_block[i] = ind = get_free_block();
  272. memset(ind_block, 0, BLOCK_SIZE);
  273. for (j = 0; j < 512; j++) {
  274. ind_block[j] = zone;
  275. if (!NEXT_BAD)
  276. goto end_bad;
  277. }
  278. }
  279. bb_error_msg_and_die("too many bad blocks");
  280. end_bad:
  281. if (ind)
  282. write_block(ind, (char *) ind_block);
  283. if (dind)
  284. write_block(dind, (char *) dind_block);
  285. #undef ind_block
  286. #undef dind_block
  287. }
  288. #if ENABLE_FEATURE_MINIX2
  289. static void make_bad_inode2(void)
  290. {
  291. struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO];
  292. int i, j, zone;
  293. int ind = 0, dind = 0;
  294. /* moved to globals to reduce stack usage
  295. unsigned long ind_block[BLOCK_SIZE >> 2];
  296. unsigned long dind_block[BLOCK_SIZE >> 2];
  297. */
  298. #define ind_block (G.ind_block2)
  299. #define dind_block (G.dind_block2)
  300. if (!G.badblocks)
  301. return;
  302. mark_inode(MINIX_BAD_INO);
  303. inode->i_nlinks = 1;
  304. inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
  305. inode->i_mode = S_IFREG + 0000;
  306. inode->i_size = G.badblocks * BLOCK_SIZE;
  307. zone = next(0);
  308. for (i = 0; i < 7; i++) {
  309. inode->i_zone[i] = zone;
  310. if (!NEXT_BAD)
  311. goto end_bad;
  312. }
  313. inode->i_zone[7] = ind = get_free_block();
  314. memset(ind_block, 0, BLOCK_SIZE);
  315. for (i = 0; i < 256; i++) {
  316. ind_block[i] = zone;
  317. if (!NEXT_BAD)
  318. goto end_bad;
  319. }
  320. inode->i_zone[8] = dind = get_free_block();
  321. memset(dind_block, 0, BLOCK_SIZE);
  322. for (i = 0; i < 256; i++) {
  323. write_block(ind, (char *) ind_block);
  324. dind_block[i] = ind = get_free_block();
  325. memset(ind_block, 0, BLOCK_SIZE);
  326. for (j = 0; j < 256; j++) {
  327. ind_block[j] = zone;
  328. if (!NEXT_BAD)
  329. goto end_bad;
  330. }
  331. }
  332. /* Could make triple indirect block here */
  333. bb_error_msg_and_die("too many bad blocks");
  334. end_bad:
  335. if (ind)
  336. write_block(ind, (char *) ind_block);
  337. if (dind)
  338. write_block(dind, (char *) dind_block);
  339. #undef ind_block
  340. #undef dind_block
  341. }
  342. #else
  343. void make_bad_inode2(void);
  344. #endif
  345. static void make_root_inode(void)
  346. {
  347. struct minix1_inode *inode = &INODE_BUF1[MINIX_ROOT_INO];
  348. mark_inode(MINIX_ROOT_INO);
  349. inode->i_zone[0] = get_free_block();
  350. inode->i_nlinks = 2;
  351. inode->i_time = CUR_TIME;
  352. if (G.badblocks)
  353. inode->i_size = 3 * G.dirsize;
  354. else {
  355. G.root_block[2 * G.dirsize] = '\0';
  356. G.root_block[2 * G.dirsize + 1] = '\0';
  357. inode->i_size = 2 * G.dirsize;
  358. }
  359. inode->i_mode = S_IFDIR + 0755;
  360. inode->i_uid = GETUID;
  361. if (inode->i_uid)
  362. inode->i_gid = GETGID;
  363. write_block(inode->i_zone[0], G.root_block);
  364. }
  365. #if ENABLE_FEATURE_MINIX2
  366. static void make_root_inode2(void)
  367. {
  368. struct minix2_inode *inode = &INODE_BUF2[MINIX_ROOT_INO];
  369. mark_inode(MINIX_ROOT_INO);
  370. inode->i_zone[0] = get_free_block();
  371. inode->i_nlinks = 2;
  372. inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
  373. if (G.badblocks)
  374. inode->i_size = 3 * G.dirsize;
  375. else {
  376. G.root_block[2 * G.dirsize] = '\0';
  377. G.root_block[2 * G.dirsize + 1] = '\0';
  378. inode->i_size = 2 * G.dirsize;
  379. }
  380. inode->i_mode = S_IFDIR + 0755;
  381. inode->i_uid = GETUID;
  382. if (inode->i_uid)
  383. inode->i_gid = GETGID;
  384. write_block(inode->i_zone[0], G.root_block);
  385. }
  386. #else
  387. void make_root_inode2(void);
  388. #endif
  389. /*
  390. * Perform a test of a block; return the number of
  391. * blocks readable.
  392. */
  393. static size_t do_check(char *buffer, size_t try, unsigned current_block)
  394. {
  395. ssize_t got;
  396. /* Seek to the correct loc. */
  397. msg_eol = "seek failed during testing of blocks";
  398. xlseek(dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
  399. msg_eol = "\n";
  400. /* Try the read */
  401. got = read(dev_fd, buffer, try * BLOCK_SIZE);
  402. if (got < 0)
  403. got = 0;
  404. try = ((size_t)got) / BLOCK_SIZE;
  405. if (got & (BLOCK_SIZE - 1))
  406. fprintf(stderr, "Short read at block %u\n", (unsigned)(current_block + try));
  407. return try;
  408. }
  409. static void alarm_intr(int alnum UNUSED_PARAM)
  410. {
  411. if (G.currently_testing >= SB_ZONES)
  412. return;
  413. signal(SIGALRM, alarm_intr);
  414. alarm(5);
  415. if (!G.currently_testing)
  416. return;
  417. printf("%d ...", G.currently_testing);
  418. fflush_all();
  419. }
  420. static void check_blocks(void)
  421. {
  422. size_t try, got;
  423. G.currently_testing = 0;
  424. signal(SIGALRM, alarm_intr);
  425. alarm(5);
  426. while (G.currently_testing < SB_ZONES) {
  427. msg_eol = "seek failed in check_blocks";
  428. xlseek(dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET);
  429. msg_eol = "\n";
  430. try = TEST_BUFFER_BLOCKS;
  431. if (G.currently_testing + try > SB_ZONES)
  432. try = SB_ZONES - G.currently_testing;
  433. got = do_check(G.check_blocks_buffer, try, G.currently_testing);
  434. G.currently_testing += got;
  435. if (got == try)
  436. continue;
  437. if (G.currently_testing < SB_FIRSTZONE)
  438. bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
  439. mark_zone(G.currently_testing);
  440. G.badblocks++;
  441. G.currently_testing++;
  442. }
  443. alarm(0);
  444. printf("%d bad block(s)\n", G.badblocks);
  445. }
  446. static void get_list_blocks(char *filename)
  447. {
  448. FILE *listfile;
  449. unsigned long blockno;
  450. listfile = xfopen_for_read(filename);
  451. while (!feof(listfile)) {
  452. fscanf(listfile, "%lu\n", &blockno);
  453. mark_zone(blockno);
  454. G.badblocks++;
  455. }
  456. printf("%d bad block(s)\n", G.badblocks);
  457. }
  458. static void setup_tables(void)
  459. {
  460. unsigned long inodes;
  461. unsigned norm_firstzone;
  462. unsigned sb_zmaps;
  463. unsigned i;
  464. /* memset(G.superblock_buffer, 0, BLOCK_SIZE); */
  465. /* memset(G.boot_block_buffer, 0, 512); */
  466. SB_MAGIC = G.magic;
  467. SB_ZONE_SIZE = 0;
  468. SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
  469. if (version2)
  470. SB.s_zones = G.total_blocks;
  471. else
  472. SB.s_nzones = G.total_blocks;
  473. /* some magic nrs: 1 inode / 3 blocks */
  474. if (G.req_nr_inodes == 0)
  475. inodes = G.total_blocks / 3;
  476. else
  477. inodes = G.req_nr_inodes;
  478. /* Round up inode count to fill block size */
  479. if (version2)
  480. inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) &
  481. ~(MINIX2_INODES_PER_BLOCK - 1);
  482. else
  483. inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) &
  484. ~(MINIX1_INODES_PER_BLOCK - 1);
  485. if (inodes > 65535)
  486. inodes = 65535;
  487. SB_INODES = inodes;
  488. SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK);
  489. /* Real bad hack but overwise mkfs.minix can be thrown
  490. * in infinite loop...
  491. * try:
  492. * dd if=/dev/zero of=test.fs count=10 bs=1024
  493. * mkfs.minix -i 200 test.fs
  494. */
  495. /* This code is not insane: NORM_FIRSTZONE is not a constant,
  496. * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
  497. i = 999;
  498. SB_ZMAPS = 0;
  499. do {
  500. norm_firstzone = NORM_FIRSTZONE;
  501. sb_zmaps = div_roundup(G.total_blocks - norm_firstzone + 1, BITS_PER_BLOCK);
  502. if (SB_ZMAPS == sb_zmaps) goto got_it;
  503. SB_ZMAPS = sb_zmaps;
  504. /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
  505. } while (--i);
  506. bb_error_msg_and_die("incompatible size/inode count, try different -i N");
  507. got_it:
  508. SB_FIRSTZONE = norm_firstzone;
  509. G.inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE);
  510. G.zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE);
  511. memset(G.inode_map, 0xff, SB_IMAPS * BLOCK_SIZE);
  512. memset(G.zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE);
  513. for (i = SB_FIRSTZONE; i < SB_ZONES; i++)
  514. unmark_zone(i);
  515. for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
  516. unmark_inode(i);
  517. G.inode_buffer = xzalloc(INODE_BUFFER_SIZE);
  518. printf("%lu inodes\n", (unsigned long)SB_INODES);
  519. printf("%lu blocks\n", (unsigned long)SB_ZONES);
  520. printf("Firstdatazone=%lu (%lu)\n", (unsigned long)SB_FIRSTZONE, (unsigned long)norm_firstzone);
  521. printf("Zonesize=%u\n", BLOCK_SIZE << SB_ZONE_SIZE);
  522. printf("Maxsize=%lu\n", (unsigned long)SB_MAXSIZE);
  523. }
  524. int mkfs_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  525. int mkfs_minix_main(int argc UNUSED_PARAM, char **argv)
  526. {
  527. unsigned opt;
  528. char *tmp;
  529. char *str_i;
  530. char *listfile = NULL;
  531. INIT_G();
  532. /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
  533. G.namelen = 30;
  534. G.dirsize = 32;
  535. G.magic = MINIX1_SUPER_MAGIC2;
  536. if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
  537. bb_error_msg_and_die("bad inode size");
  538. #if ENABLE_FEATURE_MINIX2
  539. if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
  540. bb_error_msg_and_die("bad inode size");
  541. #endif
  542. opt_complementary = "n+"; /* -n N */
  543. opt = getopt32(argv, "ci:l:n:v", &str_i, &listfile, &G.namelen);
  544. argv += optind;
  545. //if (opt & 1) -c
  546. if (opt & 2) G.req_nr_inodes = xatoul(str_i); // -i
  547. //if (opt & 4) -l
  548. if (opt & 8) { // -n
  549. if (G.namelen == 14) G.magic = MINIX1_SUPER_MAGIC;
  550. else if (G.namelen == 30) G.magic = MINIX1_SUPER_MAGIC2;
  551. else bb_show_usage();
  552. G.dirsize = G.namelen + 2;
  553. }
  554. if (opt & 0x10) { // -v
  555. #if ENABLE_FEATURE_MINIX2
  556. version2 = 1;
  557. #else
  558. bb_error_msg_and_die("not compiled with minix v2 support");
  559. #endif
  560. }
  561. G.device_name = argv[0];
  562. if (!G.device_name)
  563. bb_show_usage();
  564. /* Check if it is mounted */
  565. if (find_mount_point(G.device_name, 0))
  566. bb_error_msg_and_die("can't format mounted filesystem");
  567. xmove_fd(xopen(G.device_name, O_RDWR), dev_fd);
  568. G.total_blocks = get_volume_size_in_bytes(dev_fd, argv[1], 1024, /*extend:*/ 1) / 1024;
  569. if (G.total_blocks < 10)
  570. bb_error_msg_and_die("must have at least 10 blocks");
  571. if (version2) {
  572. G.magic = MINIX2_SUPER_MAGIC2;
  573. if (G.namelen == 14)
  574. G.magic = MINIX2_SUPER_MAGIC;
  575. } else if (G.total_blocks > 65535)
  576. G.total_blocks = 65535;
  577. #if 0
  578. struct stat statbuf;
  579. xfstat(dev_fd, &statbuf, G.device_name);
  580. /* why? */
  581. if (!S_ISBLK(statbuf.st_mode))
  582. opt &= ~1; // clear -c (check)
  583. #if 0
  584. /* I don't know why someone has special code to prevent mkfs.minix
  585. * on IDE devices. Why IDE but not SCSI, etc?... */
  586. else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
  587. /* what is this? */
  588. bb_error_msg_and_die("will not try "
  589. "to make filesystem on '%s'", G.device_name);
  590. #endif
  591. #endif
  592. tmp = G.root_block;
  593. *(short *) tmp = 1;
  594. strcpy(tmp + 2, ".");
  595. tmp += G.dirsize;
  596. *(short *) tmp = 1;
  597. strcpy(tmp + 2, "..");
  598. tmp += G.dirsize;
  599. *(short *) tmp = 2;
  600. strcpy(tmp + 2, ".badblocks");
  601. setup_tables();
  602. if (opt & 1) // -c ?
  603. check_blocks();
  604. else if (listfile)
  605. get_list_blocks(listfile);
  606. if (version2) {
  607. make_root_inode2();
  608. make_bad_inode2();
  609. } else {
  610. make_root_inode();
  611. make_bad_inode();
  612. }
  613. mark_good_blocks();
  614. write_tables();
  615. return 0;
  616. }