applying:
[oweals/busybox.git] / e2fsprogs / mke2fs.c
1 /*
2  * mke2fs.c - Make a ext2fs filesystem.
3  * 
4  * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5  *      2003, 2004, 2005 by Theodore Ts'o.
6  *
7  * %Begin-Header%
8  * This file may be redistributed under the terms of the GNU Public
9  * License.
10  * %End-Header%
11  */
12
13 /* Usage: mke2fs [options] device
14  * 
15  * The device may be a block device or a image of one, but this isn't
16  * enforced (but it's not much fun on a character device :-). 
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <time.h>
24 #include <getopt.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <mntent.h>
29 #include <sys/ioctl.h>
30 #include <sys/types.h>
31
32 #include "e2fsbb.h"
33 #include "ext2fs/ext2_fs.h"
34 #include "uuid/uuid.h"
35 #include "e2p/e2p.h"
36 #include "ext2fs/ext2fs.h"
37 #include "util.h"
38
39 #define STRIDE_LENGTH 8
40
41 #ifndef __sparc__
42 #define ZAP_BOOTBLOCK
43 #endif
44
45 static const char * device_name /* = NULL */;
46
47 /* Command line options */
48 static int      cflag;
49 static int      quiet;
50 static int      super_only;
51 static int      force;
52 static int      noaction;
53 static int      journal_size;
54 static int      journal_flags;
55 static char     *bad_blocks_filename;
56 static __u32    fs_stride;
57
58 static struct ext2_super_block param;
59 static char *creator_os;
60 static char *volume_label;
61 static char *mount_dir;
62 static char *journal_device;
63 static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */
64
65 static int sys_page_size = 4096;
66 static int linux_version_code = 0;
67
68 static int int_log2(int arg)
69 {
70         int     l = 0;
71
72         arg >>= 1;
73         while (arg) {
74                 l++;
75                 arg >>= 1;
76         }
77         return l;
78 }
79
80 static int int_log10(unsigned int arg)
81 {
82         int     l;
83
84         for (l=0; arg ; l++)
85                 arg = arg / 10;
86         return l;
87 }
88
89 static int parse_version_number(const char *s)
90 {
91         int     major, minor, rev;
92         char    *endptr;
93         const char *cp = s;
94
95         if (!s)
96                 return 0;
97         major = strtol(cp, &endptr, 10);
98         if (cp == endptr || *endptr != '.')
99                 return 0;
100         cp = endptr + 1;
101         minor = strtol(cp, &endptr, 10);
102         if (cp == endptr || *endptr != '.')
103                 return 0;
104         cp = endptr + 1;
105         rev = strtol(cp, &endptr, 10);
106         if (cp == endptr)
107                 return 0;
108         return ((((major * 256) + minor) * 256) + rev);
109 }
110
111
112
113 /*
114  * This function sets the default parameters for a filesystem
115  *
116  * The type is specified by the user.  The size is the maximum size
117  * (in megabytes) for which a set of parameters applies, with a size
118  * of zero meaning that it is the default parameter for the type.
119  * Note that order is important in the table below.
120  */
121 #define DEF_MAX_BLOCKSIZE -1
122 static char default_str[] = "default";
123 struct mke2fs_defaults {
124         const char      *type;
125         int             size;
126         int             blocksize;
127         int             inode_ratio;
128 } settings[] = {
129         { default_str, 0, 4096, 8192 },
130         { default_str, 512, 1024, 4096 },
131         { default_str, 3, 1024, 8192 },
132         { "journal", 0, 4096, 8192 },
133         { "news", 0, 4096, 4096 },
134         { "largefile", 0, 4096, 1024 * 1024 },
135         { "largefile4", 0, 4096, 4096 * 1024 },
136         { 0, 0, 0, 0},
137 };
138
139 static void set_fs_defaults(const char *fs_type,
140                             struct ext2_super_block *super,
141                             int blocksize, int sector_size,
142                             int *inode_ratio)
143 {
144         int     megs;
145         int     ratio = 0;
146         struct mke2fs_defaults *p;
147         int     use_bsize = 1024;
148
149         megs = super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024;
150         if (inode_ratio)
151                 ratio = *inode_ratio;
152         if (!fs_type)
153                 fs_type = default_str;
154         for (p = settings; p->type; p++) {
155                 if ((strcmp(p->type, fs_type) != 0) &&
156                     (strcmp(p->type, default_str) != 0))
157                         continue;
158                 if ((p->size != 0) && (megs > p->size))
159                         continue;
160                 if (ratio == 0)
161                         *inode_ratio = p->inode_ratio < blocksize ?
162                                 blocksize : p->inode_ratio;
163                 use_bsize = p->blocksize;
164         }
165         if (blocksize <= 0) {
166                 if (use_bsize == DEF_MAX_BLOCKSIZE) {
167                         use_bsize = sys_page_size;
168                         if ((linux_version_code < (2*65536 + 6*256)) &&
169                             (use_bsize > 4096))
170                                 use_bsize = 4096;
171                 }
172                 if (sector_size && use_bsize < sector_size)
173                         use_bsize = sector_size;
174                 if ((blocksize < 0) && (use_bsize < (-blocksize)))
175                         use_bsize = -blocksize;
176                 blocksize = use_bsize;
177                 super->s_blocks_count /= blocksize / 1024;
178         }
179         super->s_log_frag_size = super->s_log_block_size =
180                 int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
181 }
182
183
184 /*
185  * Helper function for read_bb_file and test_disk
186  */
187 static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
188 {
189         bb_error_msg("Bad block %u out of range; ignored", blk);
190         return;
191 }
192
193 /*
194  * Reads the bad blocks list from a file
195  */
196 static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
197                          const char *bad_blocks_file)
198 {
199         FILE            *f;
200         errcode_t       retval;
201
202         f = fopen(bad_blocks_file, "r");
203         if (!f) {
204                 bb_perror_msg_and_die("Could not read bad blocks file %s", bad_blocks_file);
205         }
206         retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
207         fclose (f);
208         if (retval) {
209                 bb_error_msg_and_die("Could not read bad blocks list");
210         }
211 }
212
213 /*
214  * Runs the badblocks program to test the disk
215  */
216 static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
217 {
218         FILE            *f;
219         errcode_t       retval;
220         char            buf[1024];
221
222         sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
223                 quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
224                 fs->device_name, fs->super->s_blocks_count);
225         if (!quiet)
226                 printf(_("Running command: %s\n"), buf);
227         f = popen(buf, "r");
228         if (!f) {
229                 bb_perror_msg_and_die("Could not run '%s'", buf);
230         }
231         retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
232         pclose(f);
233         if (retval) {
234                 bb_error_msg_and_die(
235                         "Could not get list of bad blocks from program");
236         }
237 }
238
239 static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
240 {
241         dgrp_t                  i;
242         blk_t                   j;
243         unsigned                must_be_good;
244         blk_t                   blk;
245         badblocks_iterate       bb_iter;
246         errcode_t               retval;
247         blk_t                   group_block;
248         int                     group;
249         int                     group_bad;
250
251         if (!bb_list)
252                 return;
253         
254         /*
255          * The primary superblock and group descriptors *must* be
256          * good; if not, abort.
257          */
258         must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
259         for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
260                 if (ext2fs_badblocks_list_test(bb_list, i)) {
261                         bb_error_msg_and_die(
262                                 "Block %d in primary superblock/group descriptor area bad\n"
263                                 "Blocks %d through %d must be good in order to build a filesystem\n"
264                                 "Aborting ...", i, fs->super->s_first_data_block, must_be_good);
265                 }
266         }
267
268         /*
269          * See if any of the bad blocks are showing up in the backup
270          * superblocks and/or group descriptors.  If so, issue a
271          * warning and adjust the block counts appropriately.
272          */
273         group_block = fs->super->s_first_data_block +
274                 fs->super->s_blocks_per_group;
275         
276         for (i = 1; i < fs->group_desc_count; i++) {
277                 group_bad = 0;
278                 for (j=0; j < fs->desc_blocks+1; j++) {
279                         if (ext2fs_badblocks_list_test(bb_list,
280                                                        group_block + j)) {
281                                 if (!group_bad) 
282                                         bb_error_msg(
283                                                 "Warning: the backup superblock/group descriptors at block %d contain\n"
284                                                 "       bad blocks\n", group_block);
285                                 group_bad++;
286                                 group = ext2fs_group_of_blk(fs, group_block+j);
287                                 fs->group_desc[group].bg_free_blocks_count++;
288                                 fs->super->s_free_blocks_count++;
289                         }
290                 }
291                 group_block += fs->super->s_blocks_per_group;
292         }
293         
294         /*
295          * Mark all the bad blocks as used...
296          */
297         retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
298         if (retval) {
299                 bb_error_msg_and_die("while marking bad blocks as used");
300         }
301         while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) 
302                 ext2fs_mark_block_bitmap(fs->block_map, blk);
303         ext2fs_badblocks_list_iterate_end(bb_iter);
304 }
305
306 /*
307  * These functions implement a generalized progress meter.
308  */
309 struct progress_struct {
310         char            format[20];
311         char            backup[80];
312         __u32           max;
313         int             skip_progress;
314 };
315
316 static void progress_init(struct progress_struct *progress,
317                           const char *label,__u32 max)
318 {
319         int     i;
320
321         memset(progress, 0, sizeof(struct progress_struct));
322         if (quiet)
323                 return;
324
325         /*
326          * Figure out how many digits we need
327          */
328         i = int_log10(max);
329         sprintf(progress->format, "%%%dd/%%%dld", i, i);
330         memset(progress->backup, '\b', sizeof(progress->backup)-1);
331         progress->backup[sizeof(progress->backup)-1] = 0;
332         if ((2*i)+1 < (int) sizeof(progress->backup))
333                 progress->backup[(2*i)+1] = 0;
334         progress->max = max;
335
336         progress->skip_progress = 0;
337         if (getenv("MKE2FS_SKIP_PROGRESS"))
338                 progress->skip_progress++;
339
340         fputs(label, stdout);
341         fflush(stdout);
342 }
343
344 static void progress_update(struct progress_struct *progress, __u32 val)
345 {
346         if ((progress->format[0] == 0) || progress->skip_progress)
347                 return;
348         printf(progress->format, val, progress->max);
349         fputs(progress->backup, stdout);
350 }
351
352 static void progress_close(struct progress_struct *progress)
353 {
354         if (progress->format[0] == 0)
355                 return;
356         fputs(_("done                            \n"), stdout);
357 }
358
359
360 /*
361  * Helper function which zeros out _num_ blocks starting at _blk_.  In
362  * case of an error, the details of the error is returned via _ret_blk_
363  * and _ret_count_ if they are non-NULL pointers.  Returns 0 on
364  * success, and an error code on an error.
365  *
366  * As a special case, if the first argument is NULL, then it will
367  * attempt to free the static zeroizing buffer.  (This is to keep
368  * programs that check for memory leaks happy.)
369  */
370 static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
371                              struct progress_struct *progress,
372                              blk_t *ret_blk, int *ret_count)
373 {
374         int             j, count, next_update, next_update_incr;
375         static char     *buf;
376         errcode_t       retval;
377
378         /* If fs is null, clean up the static buffer and return */
379         if (!fs) {
380                 if (buf) {
381                         free(buf);
382                         buf = 0;
383                 }
384                 return 0;
385         }
386         /* Allocate the zeroizing buffer if necessary */
387         if (!buf) {
388                 buf = xmalloc(fs->blocksize * STRIDE_LENGTH);
389                 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
390         }
391         /* OK, do the write loop */
392         next_update = 0;
393         next_update_incr = num / 100;
394         if (next_update_incr < 1)
395                 next_update_incr = 1;
396         for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
397                 count = num - j;
398                 if (count > STRIDE_LENGTH)
399                         count = STRIDE_LENGTH;
400                 retval = io_channel_write_blk(fs->io, blk, count, buf);
401                 if (retval) {
402                         if (ret_count)
403                                 *ret_count = count;
404                         if (ret_blk)
405                                 *ret_blk = blk;
406                         return retval;
407                 }
408                 if (progress && j > next_update) {
409                         next_update += num / 100;
410                         progress_update(progress, blk);
411                 }
412         }
413         return 0;
414 }       
415
416 static void write_inode_tables(ext2_filsys fs)
417 {
418         errcode_t       retval;
419         blk_t           blk;
420         dgrp_t          i;
421         int             num;
422         struct progress_struct progress;
423
424         if (quiet)
425                 memset(&progress, 0, sizeof(progress));
426         else
427                 progress_init(&progress, _("Writing inode tables: "),
428                               fs->group_desc_count);
429
430         for (i = 0; i < fs->group_desc_count; i++) {
431                 progress_update(&progress, i);
432                 
433                 blk = fs->group_desc[i].bg_inode_table;
434                 num = fs->inode_blocks_per_group;
435
436                 retval = zero_blocks(fs, blk, num, 0, &blk, &num);
437                 if (retval) {
438                         bb_error_msg_and_die(
439                                 "\nCould not write %d blocks "
440                                 "in inode table starting at %d.",
441                                 num, blk);
442                 }
443                 if (sync_kludge) {
444                         if (sync_kludge == 1)
445                                 sync();
446                         else if ((i % sync_kludge) == 0)
447                                 sync();
448                 }
449         }
450         zero_blocks(0, 0, 0, 0, 0, 0);
451         progress_close(&progress);
452 }
453
454 static void create_root_dir(ext2_filsys fs)
455 {
456         errcode_t       retval;
457         struct ext2_inode       inode;
458
459         retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
460         if (retval) {
461                 bb_error_msg_and_die("Could not create root dir");
462         }
463         if (geteuid()) {
464                 retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
465                 if (retval) {
466                         bb_error_msg_and_die("Could not read root inode");
467                 }
468                 inode.i_uid = getuid();
469                 if (inode.i_uid)
470                         inode.i_gid = getgid();
471                 retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
472                 if (retval) {
473                         bb_error_msg_and_die("Could not set root inode ownership");
474                 }
475         }
476 }
477
478 static void create_lost_and_found(ext2_filsys fs)
479 {
480         errcode_t               retval;
481         ext2_ino_t              ino;
482         const char              *name = "lost+found";
483         int                     i;
484         int                     lpf_size = 0;
485
486         fs->umask = 077;
487         retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
488         if (retval) {
489                 bb_error_msg_and_die("Could not create lost+found");
490         }
491
492         retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
493         if (retval) {
494                 bb_error_msg_and_die("Could not look up lost+found");
495         }
496         
497         for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
498                 if ((lpf_size += fs->blocksize) >= 16*1024)
499                         break;
500                 retval = ext2fs_expand_dir(fs, ino);
501                 if (retval) {
502                         bb_error_msg_and_die("Could not expand lost+found");
503                 }
504         }
505 }
506
507 static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
508 {
509         errcode_t       retval;
510         
511         ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
512         fs->group_desc[0].bg_free_inodes_count--;
513         fs->super->s_free_inodes_count--;
514         retval = ext2fs_update_bb_inode(fs, bb_list);
515         if (retval) {
516                 bb_error_msg_and_die("Could not set bad block inode");
517         }
518
519 }
520
521 static void reserve_inodes(ext2_filsys fs)
522 {
523         ext2_ino_t      i;
524         int             group;
525
526         for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
527                 ext2fs_mark_inode_bitmap(fs->inode_map, i);
528                 group = ext2fs_group_of_ino(fs, i);
529                 fs->group_desc[group].bg_free_inodes_count--;
530                 fs->super->s_free_inodes_count--;
531         }
532         ext2fs_mark_ib_dirty(fs);
533 }
534
535 #define BSD_DISKMAGIC   (0x82564557UL)  /* The disk magic number */
536 #define BSD_MAGICDISK   (0x57455682UL)  /* The disk magic number reversed */
537 #define BSD_LABEL_OFFSET        64
538
539 static void zap_sector(ext2_filsys fs, int sect, int nsect)
540 {
541         char *buf;
542         int retval;
543         unsigned int *magic;
544
545         buf = xmalloc(512*nsect);
546
547         if (sect == 0) {
548                 /* Check for a BSD disklabel, and don't erase it if so */
549                 retval = io_channel_read_blk(fs->io, 0, -512, buf);
550                 if (retval)
551                         bb_error_msg("Warning: could not read block 0");
552                 else {
553                         magic = (unsigned int *) (buf + BSD_LABEL_OFFSET);
554                         if ((*magic == BSD_DISKMAGIC) ||
555                             (*magic == BSD_MAGICDISK))
556                                 return;
557                 }
558         }
559
560         memset(buf, 0, 512*nsect);
561         io_channel_set_blksize(fs->io, 512);
562         retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf);
563         io_channel_set_blksize(fs->io, fs->blocksize);
564         free(buf);
565         if (retval)
566                 bb_error_msg("Warning: could not erase sector %d", sect);
567 }
568
569 static void create_journal_dev(ext2_filsys fs)
570 {
571         struct progress_struct progress;
572         errcode_t               retval;
573         char                    *buf;
574         blk_t                   blk;
575         int                     count;
576
577         retval = ext2fs_create_journal_superblock(fs,
578                                   fs->super->s_blocks_count, 0, &buf);
579         if (retval) {
580                 bb_error_msg_and_die("Could not init journal superblock");
581         }
582         if (quiet)
583                 memset(&progress, 0, sizeof(progress));
584         else
585                 progress_init(&progress, _("Zeroing journal device: "),
586                               fs->super->s_blocks_count);
587
588         retval = zero_blocks(fs, 0, fs->super->s_blocks_count,
589                              &progress, &blk, &count);
590         if (retval) {
591                 bb_error_msg_and_die("Could not zero journal device (block %u, count %d)",
592                         blk, count);
593         }
594         zero_blocks(0, 0, 0, 0, 0, 0);
595
596         retval = io_channel_write_blk(fs->io,
597                                       fs->super->s_first_data_block+1,
598                                       1, buf);
599         if (retval) {
600                 bb_error_msg_and_die("Could not write journal superblock");
601         }
602         progress_close(&progress);
603 }
604
605 static void show_stats(ext2_filsys fs)
606 {
607         struct ext2_super_block *s = fs->super;
608         char                    buf[80];
609         char                    *os;
610         blk_t                   group_block;
611         dgrp_t                  i;
612         int                     need, col_left;
613         
614         if (param.s_blocks_count != s->s_blocks_count)
615                 bb_error_msg("warning: %d blocks unused\n",
616                        param.s_blocks_count - s->s_blocks_count);
617
618         memset(buf, 0, sizeof(buf));
619         strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name));
620         printf("Filesystem label=%s\n", buf);
621         fputs(_("OS type: "), stdout);
622         os = e2p_os2string(fs->super->s_creator_os);
623         fputs(os, stdout);
624         free(os);
625         printf("\n");
626         printf(_("Block size=%u (log=%u)\n"), fs->blocksize,
627                 s->s_log_block_size);
628         printf(_("Fragment size=%u (log=%u)\n"), fs->fragsize,
629                 s->s_log_frag_size);
630         printf(_("%u inodes, %u blocks\n"), s->s_inodes_count,
631                s->s_blocks_count);
632         printf(_("%u blocks (%2.2f%%) reserved for the super user\n"),
633                 s->s_r_blocks_count,
634                100.0 * s->s_r_blocks_count / s->s_blocks_count);
635         printf(_("First data block=%u\n"), s->s_first_data_block);
636         if (s->s_reserved_gdt_blocks)
637                 printf(_("Maximum filesystem blocks=%lu\n"),
638                        (s->s_reserved_gdt_blocks + fs->desc_blocks) *
639                        (fs->blocksize / sizeof(struct ext2_group_desc)) *
640                        s->s_blocks_per_group);
641         if (fs->group_desc_count > 1)
642                 printf(_("%u block groups\n"), fs->group_desc_count);
643         else
644                 printf(_("%u block group\n"), fs->group_desc_count);
645         printf(_("%u blocks per group, %u fragments per group\n"),
646                s->s_blocks_per_group, s->s_frags_per_group);
647         printf(_("%u inodes per group\n"), s->s_inodes_per_group);
648
649         if (fs->group_desc_count == 1) {
650                 printf("\n");
651                 return;
652         }
653
654         printf(_("Superblock backups stored on blocks: "));
655         group_block = s->s_first_data_block;
656         col_left = 0;
657         for (i = 1; i < fs->group_desc_count; i++) {
658                 group_block += s->s_blocks_per_group;
659                 if (!ext2fs_bg_has_super(fs, i))
660                         continue;
661                 if (i != 1)
662                         printf(", ");
663                 need = int_log10(group_block) + 2;
664                 if (need > col_left) {
665                         printf("\n\t");
666                         col_left = 72;
667                 }
668                 col_left -= need;
669                 printf("%u", group_block);
670         }
671         printf("\n\n");
672 }
673
674 /*
675  * Set the S_CREATOR_OS field.  Return true if OS is known,
676  * otherwise, 0.
677  */
678 static int set_os(struct ext2_super_block *sb, char *os)
679 {
680         if (isdigit (*os))
681                 sb->s_creator_os = atoi (os);
682         else if (strcasecmp(os, "linux") == 0)
683                 sb->s_creator_os = EXT2_OS_LINUX;
684         else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0)
685                 sb->s_creator_os = EXT2_OS_HURD;
686         else if (strcasecmp(os, "masix") == 0)
687                 sb->s_creator_os = EXT2_OS_MASIX;
688         else if (strcasecmp(os, "freebsd") == 0)
689                 sb->s_creator_os = EXT2_OS_FREEBSD;
690         else if (strcasecmp(os, "lites") == 0)
691                 sb->s_creator_os = EXT2_OS_LITES;
692         else
693                 return 0;
694
695         return 1;
696 }
697
698 #define PATH_SET "PATH=/sbin"
699
700 static void parse_extended_opts(struct ext2_super_block *sb_param, 
701                                 const char *opts)
702 {
703         char    *buf, *token, *next, *p, *arg;
704         int     len;
705         int     r_usage = 0;
706
707         len = strlen(opts);
708         buf = xmalloc(len+1);
709         strcpy(buf, opts);
710         for (token = buf; token && *token; token = next) {
711                 p = strchr(token, ',');
712                 next = 0;
713                 if (p) {
714                         *p = 0;
715                         next = p+1;
716                 }
717                 arg = strchr(token, '=');
718                 if (arg) {
719                         *arg = 0;
720                         arg++;
721                 }
722                 if (strcmp(token, "stride") == 0) {
723                         if (!arg) {
724                                 r_usage++;
725                                 continue;
726                         }
727                         fs_stride = strtoul(arg, &p, 0);
728                         if (*p || (fs_stride == 0)) {
729                                 bb_error_msg("Invalid stride parameter");
730                                 r_usage++;
731                                 continue;
732                         }
733                 } else if (!strcmp(token, "resize")) {
734                         unsigned long resize, bpg, rsv_groups;
735                         unsigned long group_desc_count, desc_blocks;
736                         unsigned int gdpb, blocksize;
737                         int rsv_gdb;
738
739                         if (!arg) {
740                                 r_usage++;
741                                 continue;
742                         }
743
744                         resize = parse_num_blocks(arg, 
745                                                   sb_param->s_log_block_size);
746
747                         if (resize == 0) {
748                                 bb_error_msg("Invalid resize parameter: %s", arg);
749                                 r_usage++;
750                                 continue;
751                         }
752                         if (resize <= sb_param->s_blocks_count) {
753                                 bb_error_msg("The resize maximum must be greater than the filesystem size");
754                                 r_usage++;
755                                 continue;
756                         }
757
758                         blocksize = EXT2_BLOCK_SIZE(sb_param);
759                         bpg = sb_param->s_blocks_per_group;
760                         if (!bpg)
761                                 bpg = blocksize * 8;
762                         gdpb = blocksize / sizeof(struct ext2_group_desc);
763                         group_desc_count = (sb_param->s_blocks_count +
764                                             bpg - 1) / bpg;
765                         desc_blocks = (group_desc_count +
766                                        gdpb - 1) / gdpb;
767                         rsv_groups = (resize + bpg - 1) / bpg;
768                         rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - 
769                                 desc_blocks;
770                         if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb_param))
771                                 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb_param);
772
773                         if (rsv_gdb > 0) {
774                                 sb_param->s_feature_compat |=
775                                         EXT2_FEATURE_COMPAT_RESIZE_INODE;
776
777                                 sb_param->s_reserved_gdt_blocks = rsv_gdb;
778                         }
779                 } else
780                         r_usage++;
781         }
782         if (r_usage) {
783                 bb_error_msg_and_die(
784                         "\nBad options specified.\n\n"
785                         "Options are separated by commas, "
786                         "and may take an argument which\n"
787                         "\tis set off by an equals ('=') sign.\n\n"
788                         "Valid raid options are:\n"
789                         "\tstride=<stride length in blocks>\n"
790                         "\tresize=<resize maximum size in blocks>\n");
791         }
792 }       
793
794 static __u32 ok_features[3] = {
795         EXT3_FEATURE_COMPAT_HAS_JOURNAL |
796                 EXT2_FEATURE_COMPAT_RESIZE_INODE |
797                 EXT2_FEATURE_COMPAT_DIR_INDEX,  /* Compat */
798         EXT2_FEATURE_INCOMPAT_FILETYPE|         /* Incompat */
799                 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
800                 EXT2_FEATURE_INCOMPAT_META_BG,
801         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     /* R/O compat */
802 };
803
804
805 static void PRS(int argc, char *argv[])
806 {
807         int             b, c;
808         int             size;
809         char *          tmp;
810         int             blocksize = 0;
811         int             inode_ratio = 0;
812         int             inode_size = 0;
813         int             reserved_ratio = 5;
814         int             sector_size = 0;
815         int             show_version_only = 0;
816         ext2_ino_t      num_inodes = 0;
817         errcode_t       retval;
818         char *          oldpath = getenv("PATH");
819         char *          extended_opts = 0;
820         const char *    fs_type = 0;
821         blk_t           dev_size;
822         long            sysval;
823
824         /* Update our PATH to include /sbin  */
825         if (oldpath) {
826                 char *newpath;
827                 
828                 newpath = xmalloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
829                 strcpy (newpath, PATH_SET);
830                 strcat (newpath, ":");
831                 strcat (newpath, oldpath);
832                 putenv (newpath);
833         } else
834                 putenv (PATH_SET);
835
836         tmp = getenv("MKE2FS_SYNC");
837         if (tmp)
838                 sync_kludge = atoi(tmp);
839
840         /* Determine the system page size if possible */
841 #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
842 #define _SC_PAGESIZE _SC_PAGE_SIZE
843 #endif
844 #ifdef _SC_PAGESIZE
845         sysval = sysconf(_SC_PAGESIZE);
846         if (sysval > 0)
847                 sys_page_size = sysval;
848 #endif /* _SC_PAGESIZE */
849         
850         setbuf(stdout, NULL);
851         setbuf(stderr, NULL);
852         memset(&param, 0, sizeof(struct ext2_super_block));
853         param.s_rev_level = 1;  /* Create revision 1 filesystems now */
854         param.s_feature_incompat |= EXT2_FEATURE_INCOMPAT_FILETYPE;
855         param.s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
856 #if 0
857         param.s_feature_compat |= EXT2_FEATURE_COMPAT_DIR_INDEX;
858 #endif
859
860 #ifdef __linux__
861         linux_version_code = get_kernel_revision();
862         if (linux_version_code && linux_version_code < (2*65536 + 2*256)) {
863                 param.s_rev_level = 0;
864                 param.s_feature_incompat = 0;
865                 param.s_feature_compat = 0;
866                 param.s_feature_ro_compat = 0;
867         }
868 #endif
869
870         if (argc && *argv) {
871                 /* If called as mkfs.ext3, create a journal inode */
872                 if (!strcmp(*argv + strlen(*argv) - 9, "mkfs.ext3"))
873                         journal_size = -1;
874         }
875
876         while ((c = getopt (argc, argv,
877                     "b:cE:f:g:i:jl:m:no:qr:R:s:tvI:J:ST:FL:M:N:O:V")) != EOF) {
878                 switch (c) {
879                 case 'b':
880                         blocksize = strtol(optarg, &tmp, 0);
881                         b = (blocksize > 0) ? blocksize : -blocksize;
882                         if (b < EXT2_MIN_BLOCK_SIZE ||
883                             b > EXT2_MAX_BLOCK_SIZE || *tmp) {
884                                 bb_error_msg_and_die("bad block size - %s", optarg);
885                         }
886                         if (blocksize > 4096)
887                                 bb_error_msg(
888                                         "Warning: blocksize %d not usable on most systems",
889                                         blocksize);
890                         if (blocksize > 0) 
891                                 param.s_log_block_size =
892                                         int_log2(blocksize >>
893                                                  EXT2_MIN_BLOCK_LOG_SIZE);
894                         break;
895                 case 'c':       /* Check for bad blocks */
896                 case 't':       /* deprecated */
897                         cflag++;
898                         break;
899                 case 'f':
900                         size = strtoul(optarg, &tmp, 0);
901                         if (size < EXT2_MIN_BLOCK_SIZE ||
902                             size > EXT2_MAX_BLOCK_SIZE || *tmp) {
903                                 bb_error_msg_and_die("bad fragment size - %s", optarg);
904                         }
905                         param.s_log_frag_size =
906                                 int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
907                         bb_error_msg(
908                                 "Warning: fragments not supported.  "
909                                 "Ignoring -f option");
910                         break;
911                 case 'g':
912                         param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
913                         if (*tmp) {
914                                 bb_error_msg_and_die("Illegal number for blocks per group");
915                         }
916                         if ((param.s_blocks_per_group % 8) != 0) {
917                                 bb_error_msg_and_die("blocks per group must be multiple of 8");
918                         }
919                         break;
920                 case 'i':
921                         inode_ratio = strtoul(optarg, &tmp, 0);
922                         if (inode_ratio < EXT2_MIN_BLOCK_SIZE ||
923                             inode_ratio > EXT2_MAX_BLOCK_SIZE * 1024 ||
924                             *tmp) {
925                                 bb_error_msg_and_die("bad inode ratio %s (min %d/max %d",
926                                         optarg, EXT2_MIN_BLOCK_SIZE,
927                                         EXT2_MAX_BLOCK_SIZE);
928                         }
929                         break;
930                 case 'J':
931                         parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg);
932                         break;
933                 case 'j':
934                         param.s_feature_compat |=
935                                 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
936                         if (!journal_size)
937                                 journal_size = -1;
938                         break;
939                 case 'l':
940                         bad_blocks_filename = xmalloc(strlen(optarg)+1);
941                         strcpy(bad_blocks_filename, optarg);
942                         break;
943                 case 'm':
944                         reserved_ratio = strtoul(optarg, &tmp, 0);
945                         if (reserved_ratio > 50 || *tmp) {
946                                 bb_error_msg_and_die("bad reserved blocks percent - %s", optarg);
947                         }
948                         break;
949                 case 'n':
950                         noaction++;
951                         break;
952                 case 'o':
953                         creator_os = optarg;
954                         break;
955                 case 'r':
956                         param.s_rev_level = atoi(optarg);
957                         if (param.s_rev_level == EXT2_GOOD_OLD_REV) {
958                                 param.s_feature_incompat = 0;
959                                 param.s_feature_compat = 0;
960                                 param.s_feature_ro_compat = 0;
961                         }
962                         break;
963                 case 's':       /* deprecated */
964                         if (atoi(optarg))
965                                 param.s_feature_ro_compat |=
966                                         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
967                         else 
968                                 param.s_feature_ro_compat &=
969                                         ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
970                         break;
971 #ifdef EXT2_DYNAMIC_REV
972                 case 'I':
973                         inode_size = strtoul(optarg, &tmp, 0);
974                         if (*tmp) {
975                                 bb_error_msg_and_die("bad inode size - %s", optarg);
976                         }
977                         break;
978 #endif
979                 case 'N':
980                         num_inodes = atoi(optarg);
981                         break;
982                 case 'v':
983                         quiet = 0;
984                         break;
985                 case 'q':
986                         quiet = 1;
987                         break;
988                 case 'F':
989                         force = 1;
990                         break;
991                 case 'L':
992                         volume_label = optarg;
993                         break;
994                 case 'M':
995                         mount_dir = optarg;
996                         break;
997                 case 'O':
998                         if (!strcmp(optarg, "none")) {
999                                 param.s_feature_compat = 0;
1000                                 param.s_feature_incompat = 0;
1001                                 param.s_feature_ro_compat = 0;
1002                                 break;
1003                         }
1004                         if (e2p_edit_feature(optarg,
1005                                             &param.s_feature_compat,
1006                                             ok_features)) {
1007                                 bb_error_msg_and_die("Invalid filesystem option set: %s", optarg);
1008                         }
1009                         break;
1010                 case 'E':
1011                 case 'R':
1012                         extended_opts = optarg;
1013                         break;
1014                 case 'S':
1015                         super_only = 1;
1016                         break;
1017                 case 'T':
1018                         fs_type = optarg;
1019                         break;
1020                 case 'V':
1021                         /* Print version number and exit */
1022                         show_version_only++;
1023                         break;
1024                 default:
1025                         bb_show_usage();
1026                 }
1027         }
1028         if ((optind == argc) && !show_version_only)
1029                 bb_show_usage();
1030         device_name = argv[optind++];
1031
1032         if (!quiet || show_version_only)
1033                 bb_error_msg("mke2fs %s (%s)", E2FSPROGS_VERSION, 
1034                          E2FSPROGS_DATE);
1035
1036         if (show_version_only) {
1037                 exit(0);
1038         }
1039
1040         /*
1041          * If there's no blocksize specified and there is a journal
1042          * device, use it to figure out the blocksize
1043          */
1044         if (blocksize <= 0 && journal_device) {
1045                 ext2_filsys     jfs;
1046                 io_manager      io_ptr;
1047
1048 #ifdef CONFIG_TESTIO_DEBUG
1049                 io_ptr = test_io_manager;
1050                 test_io_backing_manager = unix_io_manager;
1051 #else
1052                 io_ptr = unix_io_manager;
1053 #endif
1054                 retval = ext2fs_open(journal_device,
1055                                      EXT2_FLAG_JOURNAL_DEV_OK, 0,
1056                                      0, io_ptr, &jfs);
1057                 if (retval) {
1058                         bb_error_msg_and_die("Could not open journal device %s", journal_device);
1059                 }
1060                 if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) {
1061                         bb_error_msg_and_die(
1062                                 "Journal dev blocksize (%d) smaller than "
1063                                 "minimum blocksize %d\n", jfs->blocksize,
1064                                 -blocksize);
1065                 }
1066                 blocksize = jfs->blocksize;
1067                 param.s_log_block_size =
1068                         int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
1069                 ext2fs_close(jfs);
1070         }
1071
1072         if (blocksize > sys_page_size) {
1073                 if (!force) {
1074                         bb_error_msg("%d-byte blocks too big for system (max %d)",
1075                                 blocksize, sys_page_size);
1076                         proceed_question();
1077                 }
1078                 bb_error_msg(
1079                         "Warning: %d-byte blocks too big for system "
1080                         "(max %d), forced to continue",
1081                         blocksize, sys_page_size);
1082         }
1083         if ((blocksize > 4096) &&
1084             (param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
1085                 bb_error_msg(
1086                         "\nWarning: some 2.4 kernels do not support "
1087                         "blocksizes greater than 4096 \n\tusing ext3."
1088                         "  Use -b 4096 if this is an issue for you\n");
1089
1090         if (optind < argc) {
1091                 param.s_blocks_count = parse_num_blocks(argv[optind++], 
1092                                 param.s_log_block_size);
1093                 if (!param.s_blocks_count) {
1094                         bb_error_msg_and_die("bad blocks count - %s", argv[optind - 1]);
1095                 }
1096         }
1097         if (optind < argc)
1098                 bb_show_usage();
1099
1100         if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1101                 if (!fs_type)
1102                         fs_type = "journal";
1103                 reserved_ratio = 0;
1104                 param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
1105                 param.s_feature_compat = 0;
1106                 param.s_feature_ro_compat = 0;
1107         }
1108         if (param.s_rev_level == EXT2_GOOD_OLD_REV &&
1109             (param.s_feature_compat || param.s_feature_ro_compat ||
1110              param.s_feature_incompat))
1111                 param.s_rev_level = 1;  /* Create a revision 1 filesystem */
1112
1113         if (!force)
1114                 check_plausibility(device_name);
1115         check_mount(device_name, force, _("filesystem"));
1116
1117         param.s_log_frag_size = param.s_log_block_size;
1118
1119         if (noaction && param.s_blocks_count) {
1120                 dev_size = param.s_blocks_count;
1121                 retval = 0;
1122         } else {
1123         retry:
1124                 retval = ext2fs_get_device_size(device_name,
1125                                                 EXT2_BLOCK_SIZE(&param),
1126                                                 &dev_size);
1127                 if ((retval == EFBIG) &&
1128                     (blocksize == 0) && 
1129                     (param.s_log_block_size == 0)) {
1130                         param.s_log_block_size = 2;
1131                         blocksize = 4096;
1132                         goto retry;
1133                 }
1134         }
1135                         
1136         if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) {
1137                 bb_error_msg_and_die("Could not determine filesystem size");
1138         }
1139         if (!param.s_blocks_count) {
1140                 if (retval == EXT2_ET_UNIMPLEMENTED) {
1141                         bb_error_msg_and_die(
1142                                 "Couldn't determine device size; you "
1143                                 "must specify\nthe size of the "
1144                                 "filesystem");
1145                 } else {
1146                         if (dev_size == 0) {
1147                                 bb_error_msg_and_die(
1148                                         "Device size reported to be zero.  "
1149                                         "Invalid partition specified, or\n\t"
1150                                         "partition table wasn't reread "
1151                                         "after running fdisk, due to\n\t"
1152                                         "a modified partition being busy "
1153                                         "and in use.  You may need to reboot\n\t"
1154                                         "to re-read your partition table.\n"
1155                                 );
1156                         }
1157                         param.s_blocks_count = dev_size;
1158                         if (sys_page_size > EXT2_BLOCK_SIZE(&param))
1159                                 param.s_blocks_count &= ~((sys_page_size /
1160                                                            EXT2_BLOCK_SIZE(&param))-1);
1161                 }
1162                 
1163         } else if (!force && (param.s_blocks_count > dev_size)) {
1164                 bb_error_msg("Filesystem larger than apparent device size");
1165                 proceed_question();
1166         }
1167
1168         /*
1169          * If the user asked for HAS_JOURNAL, then make sure a journal
1170          * gets created.
1171          */
1172         if ((param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
1173             !journal_size)
1174                 journal_size = -1;
1175
1176         /* Set first meta blockgroup via an environment variable */
1177         /* (this is mostly for debugging purposes) */
1178         if ((param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
1179             ((tmp = getenv("MKE2FS_FIRST_META_BG"))))
1180                 param.s_first_meta_bg = atoi(tmp);
1181
1182         /* Get the hardware sector size, if available */
1183         retval = ext2fs_get_device_sectsize(device_name, &sector_size);
1184         if (retval) {
1185                 bb_error_msg_and_die("Could not determine hardware sector size");
1186         }
1187
1188         if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL)
1189                 sector_size = atoi(tmp);
1190         
1191         set_fs_defaults(fs_type, &param, blocksize, sector_size, &inode_ratio);
1192         blocksize = EXT2_BLOCK_SIZE(&param);
1193         
1194         if (extended_opts)
1195                 parse_extended_opts(&param, extended_opts);
1196
1197         /* Since sparse_super is the default, we would only have a problem
1198          * here if it was explicitly disabled.
1199          */
1200         if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
1201             !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1202                 bb_error_msg_and_die("reserved online resize blocks not supported "
1203                           "on non-sparse filesystem");
1204         }
1205
1206         if (param.s_blocks_per_group) {
1207                 if (param.s_blocks_per_group < 256 ||
1208                     param.s_blocks_per_group > 8 * (unsigned) blocksize) {
1209                         bb_error_msg_and_die("blocks per group count out of range");
1210                 }
1211         }
1212
1213         if (inode_size) {
1214                 if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
1215                     inode_size > EXT2_BLOCK_SIZE(&param) ||
1216                     inode_size & (inode_size - 1)) {
1217                         bb_error_msg_and_die("bad inode size %d (min %d/max %d)",
1218                                 inode_size, EXT2_GOOD_OLD_INODE_SIZE,
1219                                 blocksize);
1220                 }
1221                 if (inode_size != EXT2_GOOD_OLD_INODE_SIZE)
1222                         bb_error_msg(
1223                                 "Warning: %d-byte inodes not usable on most systems",
1224                                 inode_size);
1225                 param.s_inode_size = inode_size;
1226         }
1227
1228         /*
1229          * Calculate number of inodes based on the inode ratio
1230          */
1231         param.s_inodes_count = num_inodes ? num_inodes : 
1232                 ((__u64) param.s_blocks_count * blocksize)
1233                         / inode_ratio;
1234
1235         /*
1236          * Calculate number of blocks to reserve
1237          */
1238         param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
1239 }
1240
1241 int mke2fs_main (int argc, char *argv[])
1242 {
1243         errcode_t       retval = 0;
1244         ext2_filsys     fs;
1245         badblocks_list  bb_list = 0;
1246         int             journal_blocks;
1247         unsigned int    i;
1248         int             val;
1249         io_manager      io_ptr;
1250
1251 #ifdef ENABLE_NLS
1252         setlocale(LC_MESSAGES, "");
1253         setlocale(LC_CTYPE, "");
1254         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1255         textdomain(NLS_CAT_NAME);
1256 #endif
1257         PRS(argc, argv);
1258
1259 #ifdef CONFIG_TESTIO_DEBUG
1260         io_ptr = test_io_manager;
1261         test_io_backing_manager = unix_io_manager;
1262 #else
1263         io_ptr = unix_io_manager;
1264 #endif
1265
1266         /*
1267          * Initialize the superblock....
1268          */
1269         retval = ext2fs_initialize(device_name, 0, &param,
1270                                    io_ptr, &fs);
1271         if (retval) {
1272                 bb_error_msg_and_die("Could not set up superblock");
1273         }
1274
1275         /*
1276          * Wipe out the old on-disk superblock
1277          */
1278         if (!noaction)
1279                 zap_sector(fs, 2, 6);
1280
1281         /*
1282          * Generate a UUID for it...
1283          */
1284         uuid_generate(fs->super->s_uuid);
1285
1286         /*
1287          * Initialize the directory index variables
1288          */
1289         fs->super->s_def_hash_version = EXT2_HASH_TEA;
1290         uuid_generate((unsigned char *) fs->super->s_hash_seed);
1291
1292         /*
1293          * Add "jitter" to the superblock's check interval so that we
1294          * don't check all the filesystems at the same time.  We use a
1295          * kludgy hack of using the UUID to derive a random jitter value.
1296          */
1297         for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
1298                 val += fs->super->s_uuid[i];
1299         fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
1300
1301         /*
1302          * Override the creator OS, if applicable
1303          */
1304         if (creator_os && !set_os(fs->super, creator_os)) {
1305                 bb_error_msg_and_die("unknown os - %s", creator_os);
1306         }
1307
1308         /*
1309          * For the Hurd, we will turn off filetype since it doesn't
1310          * support it.
1311          */
1312         if (fs->super->s_creator_os == EXT2_OS_HURD)
1313                 fs->super->s_feature_incompat &=
1314                         ~EXT2_FEATURE_INCOMPAT_FILETYPE;
1315
1316         /*
1317          * Set the volume label...
1318          */
1319         if (volume_label) {
1320                 memset(fs->super->s_volume_name, 0,
1321                        sizeof(fs->super->s_volume_name));
1322                 strncpy(fs->super->s_volume_name, volume_label,
1323                         sizeof(fs->super->s_volume_name));
1324         }
1325
1326         /*
1327          * Set the last mount directory
1328          */
1329         if (mount_dir) {
1330                 memset(fs->super->s_last_mounted, 0,
1331                        sizeof(fs->super->s_last_mounted));
1332                 strncpy(fs->super->s_last_mounted, mount_dir,
1333                         sizeof(fs->super->s_last_mounted));
1334         }
1335         
1336         if (!quiet || noaction)
1337                 show_stats(fs);
1338
1339         if (noaction)
1340                 exit(0);
1341
1342         if (fs->super->s_feature_incompat &
1343             EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1344                 create_journal_dev(fs);
1345                 exit(ext2fs_close(fs) ? 1 : 0);
1346         }
1347
1348         if (bad_blocks_filename)
1349                 read_bb_file(fs, &bb_list, bad_blocks_filename);
1350         if (cflag)
1351                 test_disk(fs, &bb_list);
1352
1353         handle_bad_blocks(fs, bb_list);
1354         fs->stride = fs_stride;
1355         retval = ext2fs_allocate_tables(fs);
1356         if (retval) {
1357                 bb_error_msg_and_die("Could not allocate filesystem tables");
1358         }
1359         if (super_only) {
1360                 fs->super->s_state |= EXT2_ERROR_FS;
1361                 fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
1362         } else {
1363                 /* rsv must be a power of two (64kB is MD RAID sb alignment) */
1364                 unsigned int rsv = 65536 / fs->blocksize;
1365                 unsigned long blocks = fs->super->s_blocks_count;
1366                 unsigned long start;
1367                 blk_t ret_blk;
1368
1369 #ifdef ZAP_BOOTBLOCK
1370                 zap_sector(fs, 0, 2);
1371 #endif
1372
1373                 /*
1374                  * Wipe out any old MD RAID (or other) metadata at the end
1375                  * of the device.  This will also verify that the device is
1376                  * as large as we think.  Be careful with very small devices.
1377                  */
1378                 start = (blocks & ~(rsv - 1));
1379                 if (start > rsv)
1380                         start -= rsv;
1381                 if (start > 0)
1382                         retval = zero_blocks(fs, start, blocks - start,
1383                                              NULL, &ret_blk, NULL);
1384
1385                 if (retval) {
1386                         bb_error_msg("Could not zero block %u at end of filesystem", ret_blk);
1387                 }
1388                 write_inode_tables(fs);
1389                 create_root_dir(fs);
1390                 create_lost_and_found(fs);
1391                 reserve_inodes(fs);
1392                 create_bad_block_inode(fs, bb_list);
1393                 if (fs->super->s_feature_compat & 
1394                     EXT2_FEATURE_COMPAT_RESIZE_INODE) {
1395                         retval = ext2fs_create_resize_inode(fs);
1396                         if (retval) {
1397                                 bb_error_msg_and_die("Could not reserve blocks for online resize");
1398                         }
1399                 }
1400         }
1401
1402         if (journal_device) {
1403                 ext2_filsys     jfs;
1404                 
1405                 if (!force)
1406                         check_plausibility(journal_device); 
1407                 check_mount(journal_device, force, _("journal"));
1408
1409                 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
1410                                      EXT2_FLAG_JOURNAL_DEV_OK, 0,
1411                                      fs->blocksize, unix_io_manager, &jfs);
1412                 if (retval) {
1413                         bb_error_msg_and_die("Could not open journal device %s", journal_device);
1414                 }
1415                 if (!quiet) {
1416                         printf("Adding journal to device %s: ", journal_device);
1417                         fflush(stdout);
1418                 }
1419                 retval = ext2fs_add_journal_device(fs, jfs);
1420                 if(retval) {
1421                         bb_error_msg_and_die("Could not add journal to device %s", journal_device);
1422                 }
1423                 if (!quiet)
1424                         printf("done\n");
1425                 ext2fs_close(jfs);
1426                 free(journal_device);
1427         } else if (journal_size) {
1428                 journal_blocks = figure_journal_size(journal_size, fs);
1429
1430                 if (!journal_blocks) {
1431                         fs->super->s_feature_compat &=
1432                                 ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1433                         goto no_journal;
1434                 }
1435                 if (!quiet) {
1436                         printf("Creating journal (%d blocks): ",
1437                                journal_blocks);
1438                         fflush(stdout);
1439                 }
1440                 retval = ext2fs_add_journal_inode(fs, journal_blocks,
1441                                                   journal_flags);
1442                 if (retval) {
1443                         bb_error_msg_and_die("Could not create journal");
1444                 }
1445                 if (!quiet)
1446                         printf("done\n");
1447         }
1448 no_journal:
1449
1450         if (!quiet)
1451                 printf("Writing superblocks and "
1452                        "filesystem accounting information: ");
1453         retval = ext2fs_flush(fs);
1454         if (retval) {
1455                 bb_error_msg("\nWarning, had trouble writing out superblocks");
1456         }
1457         if (!quiet) {
1458                 printf("done\n\n");
1459                 if (!getenv("MKE2FS_SKIP_CHECK_MSG"))
1460                         print_check_message(fs);
1461         }
1462         val = ext2fs_close(fs);
1463         return (retval || val) ? 1 : 0;
1464 }