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