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