mkfs_minix.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  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. * DD.MM.YY
  10. *
  11. * 24.11.91 - Time began. Used the fsck sources to get started.
  12. *
  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.
  16. *
  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)
  19. *
  20. * 28.02.92 - Added %-information when using -c.
  21. *
  22. * 28.02.93 - Added support for other namelengths than the original
  23. * 14 characters so that I can test the new kernel routines..
  24. *
  25. * 09.10.93 - Make exit status conform to that required by fsutil
  26. * (Rik Faith, faith@cs.unc.edu)
  27. *
  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)
  31. *
  32. * 03.01.94 - Added support for file system valid flag.
  33. * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
  34. *
  35. * 30.10.94 - added support for v2 filesystem
  36. * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
  37. *
  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)
  41. *
  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)
  45. *
  46. * 02.07.96 - Added small patch from Russell King to make the program a
  47. * good deal more portable (janl@math.uio.no)
  48. *
  49. * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
  50. *
  51. * -c for readability checking (SLOW!)
  52. * -l for getting a list of bad blocks from a file.
  53. * -n for namelength (currently the kernel only uses 14 or 30)
  54. * -i for number of inodes
  55. * -v for v2 filesystem
  56. *
  57. * The device may be a block device or a image of one, but this isn't
  58. * enforced (but it's not much fun on a character device :-).
  59. *
  60. * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
  61. * removed getopt based parser and added a hand rolled one.
  62. */
  63. #include <stdio.h>
  64. #include <time.h>
  65. #include <unistd.h>
  66. #include <string.h>
  67. #include <signal.h>
  68. #include <fcntl.h>
  69. #include <ctype.h>
  70. #include <stdlib.h>
  71. #include <stdint.h>
  72. #include <termios.h>
  73. #include <sys/ioctl.h>
  74. #include <sys/param.h>
  75. #include <mntent.h>
  76. #include "busybox.h"
  77. #define MINIX_ROOT_INO 1
  78. #define MINIX_LINK_MAX 250
  79. #define MINIX2_LINK_MAX 65530
  80. #define MINIX_I_MAP_SLOTS 8
  81. #define MINIX_Z_MAP_SLOTS 64
  82. #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
  83. #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
  84. #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
  85. #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
  86. #define MINIX_VALID_FS 0x0001 /* Clean fs. */
  87. #define MINIX_ERROR_FS 0x0002 /* fs has errors. */
  88. #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
  89. #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
  90. #define MINIX_V1 0x0001 /* original minix fs */
  91. #define MINIX_V2 0x0002 /* minix V2 fs */
  92. #define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
  93. /*
  94. * This is the original minix inode layout on disk.
  95. * Note the 8-bit gid and atime and ctime.
  96. */
  97. struct minix_inode {
  98. uint16_t i_mode;
  99. uint16_t i_uid;
  100. uint32_t i_size;
  101. uint32_t i_time;
  102. uint8_t i_gid;
  103. uint8_t i_nlinks;
  104. uint16_t i_zone[9];
  105. };
  106. /*
  107. * The new minix inode has all the time entries, as well as
  108. * long block numbers and a third indirect block (7+1+1+1
  109. * instead of 7+1+1). Also, some previously 8-bit values are
  110. * now 16-bit. The inode is now 64 bytes instead of 32.
  111. */
  112. struct minix2_inode {
  113. uint16_t i_mode;
  114. uint16_t i_nlinks;
  115. uint16_t i_uid;
  116. uint16_t i_gid;
  117. uint32_t i_size;
  118. uint32_t i_atime;
  119. uint32_t i_mtime;
  120. uint32_t i_ctime;
  121. uint32_t i_zone[10];
  122. };
  123. /*
  124. * minix super-block data on disk
  125. */
  126. struct minix_super_block {
  127. uint16_t s_ninodes;
  128. uint16_t s_nzones;
  129. uint16_t s_imap_blocks;
  130. uint16_t s_zmap_blocks;
  131. uint16_t s_firstdatazone;
  132. uint16_t s_log_zone_size;
  133. uint32_t s_max_size;
  134. uint16_t s_magic;
  135. uint16_t s_state;
  136. uint32_t s_zones;
  137. };
  138. struct minix_dir_entry {
  139. uint16_t inode;
  140. char name[0];
  141. };
  142. #define BLOCK_SIZE_BITS 10
  143. #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
  144. #define NAME_MAX 255 /* # chars in a file name */
  145. #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
  146. #define MINIX_VALID_FS 0x0001 /* Clean fs. */
  147. #define MINIX_ERROR_FS 0x0002 /* fs has errors. */
  148. #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
  149. #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
  150. #ifndef BLKGETSIZE
  151. #define BLKGETSIZE _IO(0x12,96) /* return device size */
  152. #endif
  153. #ifndef __linux__
  154. #define volatile
  155. #endif
  156. #define MINIX_ROOT_INO 1
  157. #define MINIX_BAD_INO 2
  158. #define TEST_BUFFER_BLOCKS 16
  159. #define MAX_GOOD_BLOCKS 512
  160. #define UPPER(size,n) (((size)+((n)-1))/(n))
  161. #define INODE_SIZE (sizeof(struct minix_inode))
  162. #ifdef CONFIG_FEATURE_MINIX2
  163. #define INODE_SIZE2 (sizeof(struct minix2_inode))
  164. #define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
  165. : MINIX_INODES_PER_BLOCK))
  166. #else
  167. #define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
  168. #endif
  169. #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
  170. #define BITS_PER_BLOCK (BLOCK_SIZE<<3)
  171. static char *device_name;
  172. static int DEV = -1;
  173. static uint32_t BLOCKS;
  174. static int check;
  175. static int badblocks;
  176. static int namelen = 30; /* default (changed to 30, per Linus's
  177. suggestion, Sun Nov 21 08:05:07 1993) */
  178. static int dirsize = 32;
  179. static int magic = MINIX_SUPER_MAGIC2;
  180. static int version2;
  181. static char root_block[BLOCK_SIZE];
  182. static char *inode_buffer;
  183. #define Inode (((struct minix_inode *) inode_buffer)-1)
  184. #ifdef CONFIG_FEATURE_MINIX2
  185. #define Inode2 (((struct minix2_inode *) inode_buffer)-1)
  186. #endif
  187. static char super_block_buffer[BLOCK_SIZE];
  188. static char boot_block_buffer[512];
  189. #define Super (*(struct minix_super_block *)super_block_buffer)
  190. #define INODES (Super.s_ninodes)
  191. #ifdef CONFIG_FEATURE_MINIX2
  192. #define ZONES (version2 ? Super.s_zones : Super.s_nzones)
  193. #else
  194. #define ZONES (Super.s_nzones)
  195. #endif
  196. #define IMAPS (Super.s_imap_blocks)
  197. #define ZMAPS (Super.s_zmap_blocks)
  198. #define FIRSTZONE (Super.s_firstdatazone)
  199. #define ZONESIZE (Super.s_log_zone_size)
  200. #define MAXSIZE (Super.s_max_size)
  201. #define MAGIC (Super.s_magic)
  202. #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
  203. static char *inode_map;
  204. static char *zone_map;
  205. static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
  206. static int used_good_blocks;
  207. static unsigned long req_nr_inodes;
  208. static inline int bit(char * a,unsigned int i)
  209. {
  210. return (a[i >> 3] & (1<<(i & 7))) != 0;
  211. }
  212. #define inode_in_use(x) (bit(inode_map,(x)))
  213. #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
  214. #define mark_inode(x) (setbit(inode_map,(x)))
  215. #define unmark_inode(x) (clrbit(inode_map,(x)))
  216. #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
  217. #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
  218. /*
  219. * Check to make certain that our new filesystem won't be created on
  220. * an already mounted partition. Code adapted from mke2fs, Copyright
  221. * (C) 1994 Theodore Ts'o. Also licensed under GPL.
  222. */
  223. static inline void check_mount(void)
  224. {
  225. FILE *f;
  226. struct mntent *mnt;
  227. if ((f = setmntent(MOUNTED, "r")) == NULL)
  228. return;
  229. while ((mnt = getmntent(f)) != NULL)
  230. if (strcmp(device_name, mnt->mnt_fsname) == 0)
  231. break;
  232. endmntent(f);
  233. if (!mnt)
  234. return;
  235. bb_error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
  236. }
  237. static long valid_offset(int fd, int offset)
  238. {
  239. char ch;
  240. if (lseek(fd, offset, 0) < 0)
  241. return 0;
  242. if (read(fd, &ch, 1) < 1)
  243. return 0;
  244. return 1;
  245. }
  246. static inline int count_blocks(int fd)
  247. {
  248. int high, low;
  249. low = 0;
  250. for (high = 1; valid_offset(fd, high); high *= 2)
  251. low = high;
  252. while (low < high - 1) {
  253. const int mid = (low + high) / 2;
  254. if (valid_offset(fd, mid))
  255. low = mid;
  256. else
  257. high = mid;
  258. }
  259. valid_offset(fd, 0);
  260. return (low + 1);
  261. }
  262. static inline int get_size(const char *file)
  263. {
  264. int fd;
  265. long size;
  266. if ((fd = open(file, O_RDWR)) < 0)
  267. bb_perror_msg_and_die("%s", file);
  268. if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
  269. close(fd);
  270. return (size * 512);
  271. }
  272. size = count_blocks(fd);
  273. close(fd);
  274. return size;
  275. }
  276. static inline void write_tables(void)
  277. {
  278. /* Mark the super block valid. */
  279. Super.s_state |= MINIX_VALID_FS;
  280. Super.s_state &= ~MINIX_ERROR_FS;
  281. if (lseek(DEV, 0, SEEK_SET))
  282. bb_error_msg_and_die("seek to boot block failed in write_tables");
  283. if (512 != write(DEV, boot_block_buffer, 512))
  284. bb_error_msg_and_die("unable to clear boot sector");
  285. if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
  286. bb_error_msg_and_die("seek failed in write_tables");
  287. if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
  288. bb_error_msg_and_die("unable to write super-block");
  289. if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
  290. bb_error_msg_and_die("unable to write inode map");
  291. if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
  292. bb_error_msg_and_die("unable to write zone map");
  293. if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
  294. bb_error_msg_and_die("unable to write inodes");
  295. }
  296. static void write_block(int blk, char *buffer)
  297. {
  298. if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
  299. bb_error_msg_and_die("seek failed in write_block");
  300. if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
  301. bb_error_msg_and_die("write failed in write_block");
  302. }
  303. static int get_free_block(void)
  304. {
  305. int blk;
  306. if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
  307. bb_error_msg_and_die("too many bad blocks");
  308. if (used_good_blocks)
  309. blk = good_blocks_table[used_good_blocks - 1] + 1;
  310. else
  311. blk = FIRSTZONE;
  312. while (blk < ZONES && zone_in_use(blk))
  313. blk++;
  314. if (blk >= ZONES)
  315. bb_error_msg_and_die("not enough good blocks");
  316. good_blocks_table[used_good_blocks] = blk;
  317. used_good_blocks++;
  318. return blk;
  319. }
  320. static inline void mark_good_blocks(void)
  321. {
  322. int blk;
  323. for (blk = 0; blk < used_good_blocks; blk++)
  324. mark_zone(good_blocks_table[blk]);
  325. }
  326. static int next(int zone)
  327. {
  328. if (!zone)
  329. zone = FIRSTZONE - 1;
  330. while (++zone < ZONES)
  331. if (zone_in_use(zone))
  332. return zone;
  333. return 0;
  334. }
  335. static inline void make_bad_inode(void)
  336. {
  337. struct minix_inode *inode = &Inode[MINIX_BAD_INO];
  338. int i, j, zone;
  339. int ind = 0, dind = 0;
  340. unsigned short ind_block[BLOCK_SIZE >> 1];
  341. unsigned short dind_block[BLOCK_SIZE >> 1];
  342. #define NEXT_BAD (zone = next(zone))
  343. if (!badblocks)
  344. return;
  345. mark_inode(MINIX_BAD_INO);
  346. inode->i_nlinks = 1;
  347. inode->i_time = time(NULL);
  348. inode->i_mode = S_IFREG + 0000;
  349. inode->i_size = badblocks * BLOCK_SIZE;
  350. zone = next(0);
  351. for (i = 0; i < 7; i++) {
  352. inode->i_zone[i] = zone;
  353. if (!NEXT_BAD)
  354. goto end_bad;
  355. }
  356. inode->i_zone[7] = ind = get_free_block();
  357. memset(ind_block, 0, BLOCK_SIZE);
  358. for (i = 0; i < 512; i++) {
  359. ind_block[i] = zone;
  360. if (!NEXT_BAD)
  361. goto end_bad;
  362. }
  363. inode->i_zone[8] = dind = get_free_block();
  364. memset(dind_block, 0, BLOCK_SIZE);
  365. for (i = 0; i < 512; 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 < 512; j++) {
  370. ind_block[j] = zone;
  371. if (!NEXT_BAD)
  372. goto end_bad;
  373. }
  374. }
  375. bb_error_msg_and_die("too many bad blocks");
  376. end_bad:
  377. if (ind)
  378. write_block(ind, (char *) ind_block);
  379. if (dind)
  380. write_block(dind, (char *) dind_block);
  381. }
  382. #ifdef CONFIG_FEATURE_MINIX2
  383. static inline void make_bad_inode2(void)
  384. {
  385. struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
  386. int i, j, zone;
  387. int ind = 0, dind = 0;
  388. unsigned long ind_block[BLOCK_SIZE >> 2];
  389. unsigned long dind_block[BLOCK_SIZE >> 2];
  390. if (!badblocks)
  391. return;
  392. mark_inode(MINIX_BAD_INO);
  393. inode->i_nlinks = 1;
  394. inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
  395. inode->i_mode = S_IFREG + 0000;
  396. inode->i_size = badblocks * BLOCK_SIZE;
  397. zone = next(0);
  398. for (i = 0; i < 7; i++) {
  399. inode->i_zone[i] = zone;
  400. if (!NEXT_BAD)
  401. goto end_bad;
  402. }
  403. inode->i_zone[7] = ind = get_free_block();
  404. memset(ind_block, 0, BLOCK_SIZE);
  405. for (i = 0; i < 256; i++) {
  406. ind_block[i] = zone;
  407. if (!NEXT_BAD)
  408. goto end_bad;
  409. }
  410. inode->i_zone[8] = dind = get_free_block();
  411. memset(dind_block, 0, BLOCK_SIZE);
  412. for (i = 0; i < 256; i++) {
  413. write_block(ind, (char *) ind_block);
  414. dind_block[i] = ind = get_free_block();
  415. memset(ind_block, 0, BLOCK_SIZE);
  416. for (j = 0; j < 256; j++) {
  417. ind_block[j] = zone;
  418. if (!NEXT_BAD)
  419. goto end_bad;
  420. }
  421. }
  422. /* Could make triple indirect block here */
  423. bb_error_msg_and_die("too many bad blocks");
  424. end_bad:
  425. if (ind)
  426. write_block(ind, (char *) ind_block);
  427. if (dind)
  428. write_block(dind, (char *) dind_block);
  429. }
  430. #endif
  431. static inline void make_root_inode(void)
  432. {
  433. struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
  434. mark_inode(MINIX_ROOT_INO);
  435. inode->i_zone[0] = get_free_block();
  436. inode->i_nlinks = 2;
  437. inode->i_time = time(NULL);
  438. if (badblocks)
  439. inode->i_size = 3 * dirsize;
  440. else {
  441. root_block[2 * dirsize] = '\0';
  442. root_block[2 * dirsize + 1] = '\0';
  443. inode->i_size = 2 * dirsize;
  444. }
  445. inode->i_mode = S_IFDIR + 0755;
  446. inode->i_uid = getuid();
  447. if (inode->i_uid)
  448. inode->i_gid = getgid();
  449. write_block(inode->i_zone[0], root_block);
  450. }
  451. #ifdef CONFIG_FEATURE_MINIX2
  452. static inline void make_root_inode2(void)
  453. {
  454. struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
  455. mark_inode(MINIX_ROOT_INO);
  456. inode->i_zone[0] = get_free_block();
  457. inode->i_nlinks = 2;
  458. inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
  459. if (badblocks)
  460. inode->i_size = 3 * dirsize;
  461. else {
  462. root_block[2 * dirsize] = '\0';
  463. root_block[2 * dirsize + 1] = '\0';
  464. inode->i_size = 2 * dirsize;
  465. }
  466. inode->i_mode = S_IFDIR + 0755;
  467. inode->i_uid = getuid();
  468. if (inode->i_uid)
  469. inode->i_gid = getgid();
  470. write_block(inode->i_zone[0], root_block);
  471. }
  472. #endif
  473. static inline void setup_tables(void)
  474. {
  475. int i;
  476. unsigned long inodes;
  477. memset(super_block_buffer, 0, BLOCK_SIZE);
  478. memset(boot_block_buffer, 0, 512);
  479. MAGIC = magic;
  480. ZONESIZE = 0;
  481. MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
  482. #ifdef CONFIG_FEATURE_MINIX2
  483. if (version2) {
  484. Super.s_zones = BLOCKS;
  485. } else
  486. #endif
  487. Super.s_nzones = BLOCKS;
  488. /* some magic nrs: 1 inode / 3 blocks */
  489. if (req_nr_inodes == 0)
  490. inodes = BLOCKS / 3;
  491. else
  492. inodes = req_nr_inodes;
  493. /* Round up inode count to fill block size */
  494. #ifdef CONFIG_FEATURE_MINIX2
  495. if (version2)
  496. inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
  497. ~(MINIX2_INODES_PER_BLOCK - 1));
  498. else
  499. #endif
  500. inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
  501. ~(MINIX_INODES_PER_BLOCK - 1));
  502. if (inodes > 65535)
  503. inodes = 65535;
  504. INODES = inodes;
  505. IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
  506. ZMAPS = 0;
  507. i = 0;
  508. while (ZMAPS !=
  509. UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
  510. BITS_PER_BLOCK) && i < 1000) {
  511. ZMAPS =
  512. UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
  513. BITS_PER_BLOCK);
  514. i++;
  515. }
  516. /* Real bad hack but overwise mkfs.minix can be thrown
  517. * in infinite loop...
  518. * try:
  519. * dd if=/dev/zero of=test.fs count=10 bs=1024
  520. * /sbin/mkfs.minix -i 200 test.fs
  521. * */
  522. if (i >= 999) {
  523. bb_error_msg_and_die("unable to allocate buffers for maps");
  524. }
  525. FIRSTZONE = NORM_FIRSTZONE;
  526. inode_map = xmalloc(IMAPS * BLOCK_SIZE);
  527. zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
  528. memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
  529. memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
  530. for (i = FIRSTZONE; i < ZONES; i++)
  531. unmark_zone(i);
  532. for (i = MINIX_ROOT_INO; i <= INODES; i++)
  533. unmark_inode(i);
  534. inode_buffer = xmalloc(INODE_BUFFER_SIZE);
  535. memset(inode_buffer, 0, INODE_BUFFER_SIZE);
  536. printf("%ld inodes\n", (long)INODES);
  537. printf("%ld blocks\n", (long)ZONES);
  538. printf("Firstdatazone=%ld (%ld)\n", (long)FIRSTZONE, (long)NORM_FIRSTZONE);
  539. printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
  540. printf("Maxsize=%ld\n\n", (long)MAXSIZE);
  541. }
  542. /*
  543. * Perform a test of a block; return the number of
  544. * blocks readable/writable.
  545. */
  546. static inline long do_check(char *buffer, int try, unsigned int current_block)
  547. {
  548. long got;
  549. /* Seek to the correct loc. */
  550. if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
  551. current_block * BLOCK_SIZE) {
  552. bb_error_msg_and_die("seek failed during testing of blocks");
  553. }
  554. /* Try the read */
  555. got = read(DEV, buffer, try * BLOCK_SIZE);
  556. if (got < 0)
  557. got = 0;
  558. if (got & (BLOCK_SIZE - 1)) {
  559. printf("Weird values in do_check: probably bugs\n");
  560. }
  561. got /= BLOCK_SIZE;
  562. return got;
  563. }
  564. static unsigned int currently_testing;
  565. static void alarm_intr(int alnum)
  566. {
  567. if (currently_testing >= ZONES)
  568. return;
  569. signal(SIGALRM, alarm_intr);
  570. alarm(5);
  571. if (!currently_testing)
  572. return;
  573. printf("%d ...", currently_testing);
  574. fflush(stdout);
  575. }
  576. static void check_blocks(void)
  577. {
  578. int try, got;
  579. static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
  580. currently_testing = 0;
  581. signal(SIGALRM, alarm_intr);
  582. alarm(5);
  583. while (currently_testing < ZONES) {
  584. if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
  585. currently_testing * BLOCK_SIZE)
  586. bb_error_msg_and_die("seek failed in check_blocks");
  587. try = TEST_BUFFER_BLOCKS;
  588. if (currently_testing + try > ZONES)
  589. try = ZONES - currently_testing;
  590. got = do_check(buffer, try, currently_testing);
  591. currently_testing += got;
  592. if (got == try)
  593. continue;
  594. if (currently_testing < FIRSTZONE)
  595. bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
  596. mark_zone(currently_testing);
  597. badblocks++;
  598. currently_testing++;
  599. }
  600. if (badblocks > 1)
  601. printf("%d bad blocks\n", badblocks);
  602. else if (badblocks == 1)
  603. printf("one bad block\n");
  604. }
  605. static void get_list_blocks(char *filename)
  606. {
  607. FILE *listfile;
  608. unsigned long blockno;
  609. listfile = bb_xfopen(filename, "r");
  610. while (!feof(listfile)) {
  611. fscanf(listfile, "%ld\n", &blockno);
  612. mark_zone(blockno);
  613. badblocks++;
  614. }
  615. if (badblocks > 1)
  616. printf("%d bad blocks\n", badblocks);
  617. else if (badblocks == 1)
  618. printf("one bad block\n");
  619. }
  620. int mkfs_minix_main(int argc, char **argv)
  621. {
  622. int i=1;
  623. char *tmp;
  624. struct stat statbuf;
  625. char *listfile = NULL;
  626. int stopIt=FALSE;
  627. if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
  628. bb_error_msg_and_die("bad inode size");
  629. #ifdef CONFIG_FEATURE_MINIX2
  630. if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
  631. bb_error_msg_and_die("bad inode size");
  632. #endif
  633. /* Parse options */
  634. argv++;
  635. while (--argc >= 0 && *argv && **argv) {
  636. if (**argv == '-') {
  637. stopIt=FALSE;
  638. while (i > 0 && *++(*argv) && stopIt==FALSE) {
  639. switch (**argv) {
  640. case 'c':
  641. check = 1;
  642. break;
  643. case 'i':
  644. {
  645. char *cp=NULL;
  646. if (*(*argv+1) != 0) {
  647. cp = ++(*argv);
  648. } else {
  649. if (--argc == 0) {
  650. goto goodbye;
  651. }
  652. cp = *(++argv);
  653. }
  654. req_nr_inodes = strtoul(cp, &tmp, 0);
  655. if (*tmp)
  656. bb_show_usage();
  657. stopIt=TRUE;
  658. break;
  659. }
  660. case 'l':
  661. if (--argc == 0) {
  662. goto goodbye;
  663. }
  664. listfile = *(++argv);
  665. break;
  666. case 'n':
  667. {
  668. char *cp=NULL;
  669. if (*(*argv+1) != 0) {
  670. cp = ++(*argv);
  671. } else {
  672. if (--argc == 0) {
  673. goto goodbye;
  674. }
  675. cp = *(++argv);
  676. }
  677. i = strtoul(cp, &tmp, 0);
  678. if (*tmp)
  679. bb_show_usage();
  680. if (i == 14)
  681. magic = MINIX_SUPER_MAGIC;
  682. else if (i == 30)
  683. magic = MINIX_SUPER_MAGIC2;
  684. else
  685. bb_show_usage();
  686. namelen = i;
  687. dirsize = i + 2;
  688. stopIt=TRUE;
  689. break;
  690. }
  691. case 'v':
  692. #ifdef CONFIG_FEATURE_MINIX2
  693. version2 = 1;
  694. #else
  695. bb_error_msg("%s: not compiled with minix v2 support",
  696. device_name);
  697. exit(-1);
  698. #endif
  699. break;
  700. case '-':
  701. case 'h':
  702. default:
  703. goodbye:
  704. bb_show_usage();
  705. }
  706. }
  707. } else {
  708. if (device_name == NULL)
  709. device_name = *argv;
  710. else if (BLOCKS == 0)
  711. BLOCKS = strtol(*argv, &tmp, 0);
  712. else {
  713. goto goodbye;
  714. }
  715. }
  716. argv++;
  717. }
  718. if (device_name && !BLOCKS)
  719. BLOCKS = get_size(device_name) / 1024;
  720. if (!device_name || BLOCKS < 10) {
  721. bb_show_usage();
  722. }
  723. #ifdef CONFIG_FEATURE_MINIX2
  724. if (version2) {
  725. if (namelen == 14)
  726. magic = MINIX2_SUPER_MAGIC;
  727. else
  728. magic = MINIX2_SUPER_MAGIC2;
  729. } else
  730. #endif
  731. if (BLOCKS > 65535)
  732. BLOCKS = 65535;
  733. check_mount(); /* is it already mounted? */
  734. tmp = root_block;
  735. *(short *) tmp = 1;
  736. strcpy(tmp + 2, ".");
  737. tmp += dirsize;
  738. *(short *) tmp = 1;
  739. strcpy(tmp + 2, "..");
  740. tmp += dirsize;
  741. *(short *) tmp = 2;
  742. strcpy(tmp + 2, ".badblocks");
  743. DEV = open(device_name, O_RDWR);
  744. if (DEV < 0)
  745. bb_error_msg_and_die("unable to open %s", device_name);
  746. if (fstat(DEV, &statbuf) < 0)
  747. bb_error_msg_and_die("unable to stat %s", device_name);
  748. if (!S_ISBLK(statbuf.st_mode))
  749. check = 0;
  750. else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
  751. bb_error_msg_and_die("will not try to make filesystem on '%s'", device_name);
  752. setup_tables();
  753. if (check)
  754. check_blocks();
  755. else if (listfile)
  756. get_list_blocks(listfile);
  757. #ifdef CONFIG_FEATURE_MINIX2
  758. if (version2) {
  759. make_root_inode2();
  760. make_bad_inode2();
  761. } else
  762. #endif
  763. {
  764. make_root_inode();
  765. make_bad_inode();
  766. }
  767. mark_good_blocks();
  768. write_tables();
  769. return 0;
  770. }