source: MondoRescue/branches/stable/mindi-busybox/util-linux/mkfs_minix.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 18.1 KB
Line 
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#if 0
683    else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
684        /* what is this? */
685        bb_error_msg_and_die("will not try "
686            "to make filesystem on '%s'", G.device_name);
687#endif
688
689    tmp = G.root_block;
690    *(short *) tmp = 1;
691    strcpy(tmp + 2, ".");
692    tmp += G.dirsize;
693    *(short *) tmp = 1;
694    strcpy(tmp + 2, "..");
695    tmp += G.dirsize;
696    *(short *) tmp = 2;
697    strcpy(tmp + 2, ".badblocks");
698
699    setup_tables();
700
701    if (opt & 1) // -c ?
702        check_blocks();
703    else if (listfile)
704        get_list_blocks(listfile);
705
706    if (version2) {
707        make_root_inode2();
708        make_bad_inode2();
709    } else {
710        make_root_inode();
711        make_bad_inode();
712    }
713
714    mark_good_blocks();
715    write_tables();
716    return 0;
717}
Note: See TracBrowser for help on using the repository browser.