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