Contents of /trunk/mkinitrd-magellan/busybox/e2fsprogs/old_e2fsprogs/mke2fs.c
Parent Directory | Revision Log
Revision 984 -
(show annotations)
(download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 34576 byte(s)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 34576 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
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 tarball for details. |
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 %d %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, next_update_incr; |
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 | next_update_incr = num / 100; |
407 | if (next_update_incr < 1) |
408 | next_update_incr = 1; |
409 | for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { |
410 | count = num - j; |
411 | if (count > STRIDE_LENGTH) |
412 | count = STRIDE_LENGTH; |
413 | retval = io_channel_write_blk(fs->io, blk, count, buf); |
414 | if (retval) { |
415 | if (ret_count) |
416 | *ret_count = count; |
417 | if (ret_blk) |
418 | *ret_blk = blk; |
419 | return retval; |
420 | } |
421 | if (progress && j > next_update) { |
422 | next_update += num / 100; |
423 | progress_update(progress, blk); |
424 | } |
425 | } |
426 | return 0; |
427 | } |
428 | |
429 | static void write_inode_tables(ext2_filsys fs) |
430 | { |
431 | errcode_t retval; |
432 | blk_t blk; |
433 | dgrp_t i; |
434 | int num; |
435 | struct progress_struct progress; |
436 | |
437 | if (quiet) |
438 | memset(&progress, 0, sizeof(progress)); |
439 | else |
440 | progress_init(&progress, "Writing inode tables: ", |
441 | fs->group_desc_count); |
442 | |
443 | for (i = 0; i < fs->group_desc_count; i++) { |
444 | progress_update(&progress, i); |
445 | |
446 | blk = fs->group_desc[i].bg_inode_table; |
447 | num = fs->inode_blocks_per_group; |
448 | |
449 | retval = zero_blocks(fs, blk, num, 0, &blk, &num); |
450 | mke2fs_error_msg_and_die(retval, |
451 | "write %d blocks in inode table starting at %d.", |
452 | num, blk); |
453 | if (sync_kludge) { |
454 | if (sync_kludge == 1) |
455 | sync(); |
456 | else if ((i % sync_kludge) == 0) |
457 | sync(); |
458 | } |
459 | } |
460 | zero_blocks(0, 0, 0, 0, 0, 0); |
461 | progress_close(&progress); |
462 | } |
463 | |
464 | static void create_root_dir(ext2_filsys fs) |
465 | { |
466 | errcode_t retval; |
467 | struct ext2_inode inode; |
468 | |
469 | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); |
470 | mke2fs_error_msg_and_die(retval, "create root dir"); |
471 | if (geteuid()) { |
472 | retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode); |
473 | mke2fs_error_msg_and_die(retval, "read root inode"); |
474 | inode.i_uid = getuid(); |
475 | if (inode.i_uid) |
476 | inode.i_gid = getgid(); |
477 | retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); |
478 | mke2fs_error_msg_and_die(retval, "set root inode ownership"); |
479 | } |
480 | } |
481 | |
482 | static void create_lost_and_found(ext2_filsys fs) |
483 | { |
484 | errcode_t retval; |
485 | ext2_ino_t ino; |
486 | const char *name = "lost+found"; |
487 | int i = 1; |
488 | char *msg = "create"; |
489 | int lpf_size = 0; |
490 | |
491 | fs->umask = 077; |
492 | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name); |
493 | if (retval) { |
494 | goto CREATE_LOST_AND_FOUND_ERROR; |
495 | } |
496 | |
497 | retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino); |
498 | if (retval) { |
499 | msg = "lookup"; |
500 | goto CREATE_LOST_AND_FOUND_ERROR; |
501 | } |
502 | |
503 | for (; i < EXT2_NDIR_BLOCKS; i++) { |
504 | if ((lpf_size += fs->blocksize) >= 16*1024) |
505 | break; |
506 | retval = ext2fs_expand_dir(fs, ino); |
507 | msg = "expand"; |
508 | CREATE_LOST_AND_FOUND_ERROR: |
509 | mke2fs_error_msg_and_die(retval, "%s %s", msg, name); |
510 | } |
511 | } |
512 | |
513 | static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list) |
514 | { |
515 | errcode_t retval; |
516 | |
517 | ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO); |
518 | fs->group_desc[0].bg_free_inodes_count--; |
519 | fs->super->s_free_inodes_count--; |
520 | retval = ext2fs_update_bb_inode(fs, bb_list); |
521 | mke2fs_error_msg_and_die(retval, "set bad block inode"); |
522 | } |
523 | |
524 | static void reserve_inodes(ext2_filsys fs) |
525 | { |
526 | ext2_ino_t i; |
527 | int group; |
528 | |
529 | for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) { |
530 | ext2fs_mark_inode_bitmap(fs->inode_map, i); |
531 | group = ext2fs_group_of_ino(fs, i); |
532 | fs->group_desc[group].bg_free_inodes_count--; |
533 | fs->super->s_free_inodes_count--; |
534 | } |
535 | ext2fs_mark_ib_dirty(fs); |
536 | } |
537 | |
538 | #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ |
539 | #define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */ |
540 | #define BSD_LABEL_OFFSET 64 |
541 | |
542 | static void zap_sector(ext2_filsys fs, int sect, int nsect) |
543 | { |
544 | char *buf; |
545 | char *fmt = "could not %s %d"; |
546 | int retval; |
547 | unsigned int *magic; |
548 | |
549 | buf = xmalloc(512*nsect); |
550 | |
551 | if (sect == 0) { |
552 | /* Check for a BSD disklabel, and don't erase it if so */ |
553 | retval = io_channel_read_blk(fs->io, 0, -512, buf); |
554 | if (retval) |
555 | mke2fs_warning_msg(retval, fmt, "read block", 0); |
556 | else { |
557 | magic = (unsigned int *) (buf + BSD_LABEL_OFFSET); |
558 | if ((*magic == BSD_DISKMAGIC) || |
559 | (*magic == BSD_MAGICDISK)) |
560 | return; |
561 | } |
562 | } |
563 | |
564 | memset(buf, 0, 512*nsect); |
565 | io_channel_set_blksize(fs->io, 512); |
566 | retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf); |
567 | io_channel_set_blksize(fs->io, fs->blocksize); |
568 | free(buf); |
569 | mke2fs_warning_msg(retval, fmt, "erase sector", sect); |
570 | } |
571 | |
572 | static void create_journal_dev(ext2_filsys fs) |
573 | { |
574 | struct progress_struct progress; |
575 | errcode_t retval; |
576 | char *buf; |
577 | char *fmt = "%s journal superblock"; |
578 | blk_t blk; |
579 | int count; |
580 | |
581 | retval = ext2fs_create_journal_superblock(fs, |
582 | fs->super->s_blocks_count, 0, &buf); |
583 | mke2fs_error_msg_and_die(retval, fmt, "init"); |
584 | if (quiet) |
585 | memset(&progress, 0, sizeof(progress)); |
586 | else |
587 | progress_init(&progress, "Zeroing journal device: ", |
588 | fs->super->s_blocks_count); |
589 | |
590 | retval = zero_blocks(fs, 0, fs->super->s_blocks_count, |
591 | &progress, &blk, &count); |
592 | mke2fs_error_msg_and_die(retval, "zero journal device (block %u, count %d)", |
593 | blk, count); |
594 | zero_blocks(0, 0, 0, 0, 0, 0); |
595 | |
596 | retval = io_channel_write_blk(fs->io, |
597 | fs->super->s_first_data_block+1, |
598 | 1, buf); |
599 | mke2fs_error_msg_and_die(retval, fmt, "write"); |
600 | progress_close(&progress); |
601 | } |
602 | |
603 | static void show_stats(ext2_filsys fs) |
604 | { |
605 | struct ext2_super_block *s = fs->super; |
606 | char *os; |
607 | blk_t group_block; |
608 | dgrp_t i; |
609 | int need, col_left; |
610 | |
611 | mke2fs_warning_msg((param.s_blocks_count != s->s_blocks_count), |
612 | "%d blocks unused\n", param.s_blocks_count - s->s_blocks_count); |
613 | os = e2p_os2string(fs->super->s_creator_os); |
614 | printf( "Filesystem label=%.*s\n" |
615 | "OS type: %s\n" |
616 | "Block size=%u (log=%u)\n" |
617 | "Fragment size=%u (log=%u)\n" |
618 | "%u inodes, %u blocks\n" |
619 | "%u blocks (%2.2f%%) reserved for the super user\n" |
620 | "First data block=%u\n", |
621 | (int) sizeof(s->s_volume_name), |
622 | s->s_volume_name, |
623 | os, |
624 | fs->blocksize, s->s_log_block_size, |
625 | fs->fragsize, s->s_log_frag_size, |
626 | s->s_inodes_count, s->s_blocks_count, |
627 | s->s_r_blocks_count, 100.0 * s->s_r_blocks_count / s->s_blocks_count, |
628 | s->s_first_data_block); |
629 | free(os); |
630 | if (s->s_reserved_gdt_blocks) { |
631 | printf("Maximum filesystem blocks=%lu\n", |
632 | (s->s_reserved_gdt_blocks + fs->desc_blocks) * |
633 | (fs->blocksize / sizeof(struct ext2_group_desc)) * |
634 | s->s_blocks_per_group); |
635 | } |
636 | printf( "%u block group%s\n" |
637 | "%u blocks per group, %u fragments per group\n" |
638 | "%u inodes per group\n", |
639 | fs->group_desc_count, (fs->group_desc_count > 1) ? "s" : "", |
640 | s->s_blocks_per_group, s->s_frags_per_group, |
641 | s->s_inodes_per_group); |
642 | if (fs->group_desc_count == 1) { |
643 | bb_putchar('\n'); |
644 | return; |
645 | } |
646 | |
647 | printf("Superblock backups stored on blocks: "); |
648 | group_block = s->s_first_data_block; |
649 | col_left = 0; |
650 | for (i = 1; i < fs->group_desc_count; i++) { |
651 | group_block += s->s_blocks_per_group; |
652 | if (!ext2fs_bg_has_super(fs, i)) |
653 | continue; |
654 | if (i != 1) |
655 | printf(", "); |
656 | need = int_log10(group_block) + 2; |
657 | if (need > col_left) { |
658 | printf("\n\t"); |
659 | col_left = 72; |
660 | } |
661 | col_left -= need; |
662 | printf("%u", group_block); |
663 | } |
664 | puts("\n"); |
665 | } |
666 | |
667 | /* |
668 | * Set the S_CREATOR_OS field. Return true if OS is known, |
669 | * otherwise, 0. |
670 | */ |
671 | static int set_os(struct ext2_super_block *sb, char *os) |
672 | { |
673 | if (isdigit (*os)) { |
674 | sb->s_creator_os = atoi(os); |
675 | return 1; |
676 | } |
677 | |
678 | if ((sb->s_creator_os = e2p_string2os(os)) >= 0) { |
679 | return 1; |
680 | } else if (!strcasecmp("GNU", os)) { |
681 | sb->s_creator_os = EXT2_OS_HURD; |
682 | return 1; |
683 | } |
684 | return 0; |
685 | } |
686 | |
687 | static void parse_extended_opts(struct ext2_super_block *sb_param, |
688 | const char *opts) |
689 | { |
690 | char *buf, *token, *next, *p, *arg; |
691 | int r_usage = 0; |
692 | |
693 | buf = xstrdup(opts); |
694 | for (token = buf; token && *token; token = next) { |
695 | p = strchr(token, ','); |
696 | next = 0; |
697 | if (p) { |
698 | *p = 0; |
699 | next = p+1; |
700 | } |
701 | arg = strchr(token, '='); |
702 | if (arg) { |
703 | *arg = 0; |
704 | arg++; |
705 | } |
706 | if (strcmp(token, "stride") == 0) { |
707 | if (!arg) { |
708 | r_usage++; |
709 | continue; |
710 | } |
711 | fs_stride = strtoul(arg, &p, 0); |
712 | if (*p || (fs_stride == 0)) { |
713 | bb_error_msg("Invalid stride parameter: %s", arg); |
714 | r_usage++; |
715 | continue; |
716 | } |
717 | } else if (!strcmp(token, "resize")) { |
718 | unsigned long resize, bpg, rsv_groups; |
719 | unsigned long group_desc_count, desc_blocks; |
720 | unsigned int gdpb, blocksize; |
721 | int rsv_gdb; |
722 | |
723 | if (!arg) { |
724 | r_usage++; |
725 | continue; |
726 | } |
727 | |
728 | resize = parse_num_blocks(arg, |
729 | sb_param->s_log_block_size); |
730 | |
731 | if (resize == 0) { |
732 | bb_error_msg("Invalid resize parameter: %s", arg); |
733 | r_usage++; |
734 | continue; |
735 | } |
736 | if (resize <= sb_param->s_blocks_count) { |
737 | bb_error_msg("The resize maximum must be greater " |
738 | "than the filesystem size"); |
739 | r_usage++; |
740 | continue; |
741 | } |
742 | |
743 | blocksize = EXT2_BLOCK_SIZE(sb_param); |
744 | bpg = sb_param->s_blocks_per_group; |
745 | if (!bpg) |
746 | bpg = blocksize * 8; |
747 | gdpb = blocksize / sizeof(struct ext2_group_desc); |
748 | group_desc_count = (sb_param->s_blocks_count + |
749 | bpg - 1) / bpg; |
750 | desc_blocks = (group_desc_count + |
751 | gdpb - 1) / gdpb; |
752 | rsv_groups = (resize + bpg - 1) / bpg; |
753 | rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - |
754 | desc_blocks; |
755 | if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb_param)) |
756 | rsv_gdb = EXT2_ADDR_PER_BLOCK(sb_param); |
757 | |
758 | if (rsv_gdb > 0) { |
759 | sb_param->s_feature_compat |= |
760 | EXT2_FEATURE_COMPAT_RESIZE_INODE; |
761 | |
762 | sb_param->s_reserved_gdt_blocks = rsv_gdb; |
763 | } |
764 | } else |
765 | r_usage++; |
766 | } |
767 | if (r_usage) { |
768 | bb_error_msg_and_die( |
769 | "\nBad options specified.\n\n" |
770 | "Extended options are separated by commas, " |
771 | "and may take an argument which\n" |
772 | "\tis set off by an equals ('=') sign.\n\n" |
773 | "Valid extended options are:\n" |
774 | "\tstride=<stride length in blocks>\n" |
775 | "\tresize=<resize maximum size in blocks>\n"); |
776 | } |
777 | } |
778 | |
779 | static __u32 ok_features[3] = { |
780 | EXT3_FEATURE_COMPAT_HAS_JOURNAL | |
781 | EXT2_FEATURE_COMPAT_RESIZE_INODE | |
782 | EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ |
783 | EXT2_FEATURE_INCOMPAT_FILETYPE| /* Incompat */ |
784 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV| |
785 | EXT2_FEATURE_INCOMPAT_META_BG, |
786 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */ |
787 | }; |
788 | |
789 | static int PRS(int argc, char **argv) |
790 | { |
791 | int c; |
792 | int size; |
793 | char * tmp; |
794 | int blocksize = 0; |
795 | int inode_ratio = 0; |
796 | int inode_size = 0; |
797 | int reserved_ratio = 5; |
798 | int sector_size = 0; |
799 | int show_version_only = 0; |
800 | ext2_ino_t num_inodes = 0; |
801 | errcode_t retval; |
802 | char * extended_opts = 0; |
803 | const char * fs_type = 0; |
804 | blk_t dev_size; |
805 | long sysval; |
806 | |
807 | /* Update our PATH to include /sbin */ |
808 | e2fs_set_sbin_path(); |
809 | |
810 | tmp = getenv("MKE2FS_SYNC"); |
811 | if (tmp) |
812 | sync_kludge = atoi(tmp); |
813 | |
814 | /* Determine the system page size if possible */ |
815 | #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) |
816 | #define _SC_PAGESIZE _SC_PAGE_SIZE |
817 | #endif |
818 | #ifdef _SC_PAGESIZE |
819 | sysval = sysconf(_SC_PAGESIZE); |
820 | if (sysval > 0) |
821 | sys_page_size = sysval; |
822 | #endif /* _SC_PAGESIZE */ |
823 | |
824 | setbuf(stdout, NULL); |
825 | setbuf(stderr, NULL); |
826 | memset(¶m, 0, sizeof(struct ext2_super_block)); |
827 | param.s_rev_level = 1; /* Create revision 1 filesystems now */ |
828 | param.s_feature_incompat |= EXT2_FEATURE_INCOMPAT_FILETYPE; |
829 | param.s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
830 | |
831 | #ifdef __linux__ |
832 | linux_version_code = get_linux_version_code(); |
833 | if (linux_version_code && linux_version_code < KERNEL_VERSION(2,2,0)) { |
834 | param.s_rev_level = 0; |
835 | param.s_feature_incompat = 0; |
836 | param.s_feature_compat = 0; |
837 | param.s_feature_ro_compat = 0; |
838 | } |
839 | #endif |
840 | |
841 | /* If called as mkfs.ext3, create a journal inode */ |
842 | if (last_char_is(applet_name, '3')) |
843 | journal_size = -1; |
844 | |
845 | while ((c = getopt (argc, argv, |
846 | "b:cE:f:g:i:jl:m:no:qr:R:s:tvI:J:ST:FL:M:N:O:V")) != EOF) { |
847 | switch (c) { |
848 | case 'b': |
849 | blocksize = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE); |
850 | mke2fs_warning_msg((blocksize > 4096), |
851 | "blocksize %d not usable on most systems", |
852 | blocksize); |
853 | param.s_log_block_size = |
854 | int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); |
855 | break; |
856 | case 'c': /* Check for bad blocks */ |
857 | case 't': /* deprecated */ |
858 | cflag++; |
859 | break; |
860 | case 'f': |
861 | size = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE); |
862 | param.s_log_frag_size = |
863 | int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE); |
864 | mke2fs_warning_msg(1, "fragments not supported. Ignoring -f option"); |
865 | break; |
866 | case 'g': |
867 | param.s_blocks_per_group = xatou32(optarg); |
868 | if ((param.s_blocks_per_group % 8) != 0) { |
869 | bb_error_msg_and_die("blocks per group must be multiple of 8"); |
870 | } |
871 | break; |
872 | case 'i': |
873 | /* Huh? is "* 1024" correct? */ |
874 | inode_ratio = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE * 1024); |
875 | break; |
876 | case 'J': |
877 | parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg); |
878 | break; |
879 | case 'j': |
880 | param.s_feature_compat |= |
881 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
882 | if (!journal_size) |
883 | journal_size = -1; |
884 | break; |
885 | case 'l': |
886 | bad_blocks_filename = optarg; |
887 | break; |
888 | case 'm': |
889 | reserved_ratio = xatou_range(optarg, 0, 50); |
890 | break; |
891 | case 'n': |
892 | noaction++; |
893 | break; |
894 | case 'o': |
895 | creator_os = optarg; |
896 | break; |
897 | case 'r': |
898 | param.s_rev_level = xatoi_u(optarg); |
899 | if (param.s_rev_level == EXT2_GOOD_OLD_REV) { |
900 | param.s_feature_incompat = 0; |
901 | param.s_feature_compat = 0; |
902 | param.s_feature_ro_compat = 0; |
903 | } |
904 | break; |
905 | case 's': /* deprecated */ |
906 | if (xatou(optarg)) |
907 | param.s_feature_ro_compat |= |
908 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
909 | else |
910 | param.s_feature_ro_compat &= |
911 | ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
912 | break; |
913 | #ifdef EXT2_DYNAMIC_REV |
914 | case 'I': |
915 | inode_size = xatoi_u(optarg); |
916 | break; |
917 | #endif |
918 | case 'N': |
919 | num_inodes = xatoi_u(optarg); |
920 | break; |
921 | case 'v': |
922 | quiet = 0; |
923 | break; |
924 | case 'q': |
925 | quiet = 1; |
926 | break; |
927 | case 'F': |
928 | force = 1; |
929 | break; |
930 | case 'L': |
931 | volume_label = optarg; |
932 | break; |
933 | case 'M': |
934 | mount_dir = optarg; |
935 | break; |
936 | case 'O': |
937 | if (!strcmp(optarg, "none")) { |
938 | param.s_feature_compat = 0; |
939 | param.s_feature_incompat = 0; |
940 | param.s_feature_ro_compat = 0; |
941 | break; |
942 | } |
943 | if (e2p_edit_feature(optarg, |
944 | ¶m.s_feature_compat, |
945 | ok_features)) { |
946 | bb_error_msg_and_die("Invalid filesystem option set: %s", optarg); |
947 | } |
948 | break; |
949 | case 'E': |
950 | case 'R': |
951 | extended_opts = optarg; |
952 | break; |
953 | case 'S': |
954 | super_only = 1; |
955 | break; |
956 | case 'T': |
957 | fs_type = optarg; |
958 | break; |
959 | case 'V': |
960 | /* Print version number and exit */ |
961 | show_version_only = 1; |
962 | quiet = 0; |
963 | break; |
964 | default: |
965 | bb_show_usage(); |
966 | } |
967 | } |
968 | if ((optind == argc) /*&& !show_version_only*/) |
969 | bb_show_usage(); |
970 | device_name = argv[optind++]; |
971 | |
972 | mke2fs_verbose("mke2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
973 | |
974 | if (show_version_only) { |
975 | return 0; |
976 | } |
977 | |
978 | /* |
979 | * If there's no blocksize specified and there is a journal |
980 | * device, use it to figure out the blocksize |
981 | */ |
982 | if (blocksize <= 0 && journal_device) { |
983 | ext2_filsys jfs; |
984 | io_manager io_ptr; |
985 | |
986 | #ifdef CONFIG_TESTIO_DEBUG |
987 | io_ptr = test_io_manager; |
988 | test_io_backing_manager = unix_io_manager; |
989 | #else |
990 | io_ptr = unix_io_manager; |
991 | #endif |
992 | retval = ext2fs_open(journal_device, |
993 | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
994 | 0, io_ptr, &jfs); |
995 | mke2fs_error_msg_and_die(retval, "open journal device %s", journal_device); |
996 | if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) { |
997 | bb_error_msg_and_die( |
998 | "Journal dev blocksize (%d) smaller than " |
999 | "minimum blocksize %d\n", jfs->blocksize, |
1000 | -blocksize); |
1001 | } |
1002 | blocksize = jfs->blocksize; |
1003 | param.s_log_block_size = |
1004 | int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); |
1005 | ext2fs_close(jfs); |
1006 | } |
1007 | |
1008 | if (blocksize > sys_page_size) { |
1009 | mke2fs_warning_msg(1, "%d-byte blocks too big for system (max %d)", |
1010 | blocksize, sys_page_size); |
1011 | if (!force) { |
1012 | proceed_question(); |
1013 | } |
1014 | bb_error_msg("Forced to continue"); |
1015 | } |
1016 | mke2fs_warning_msg(((blocksize > 4096) && |
1017 | (param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)), |
1018 | "some 2.4 kernels do not support " |
1019 | "blocksizes greater than 4096 using ext3.\n" |
1020 | "Use -b 4096 if this is an issue for you\n"); |
1021 | |
1022 | if (optind < argc) { |
1023 | param.s_blocks_count = parse_num_blocks(argv[optind++], |
1024 | param.s_log_block_size); |
1025 | mke2fs_error_msg_and_die(!param.s_blocks_count, "invalid blocks count - %s", argv[optind - 1]); |
1026 | } |
1027 | if (optind < argc) |
1028 | bb_show_usage(); |
1029 | |
1030 | if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { |
1031 | if (!fs_type) |
1032 | fs_type = "journal"; |
1033 | reserved_ratio = 0; |
1034 | param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; |
1035 | param.s_feature_compat = 0; |
1036 | param.s_feature_ro_compat = 0; |
1037 | } |
1038 | if (param.s_rev_level == EXT2_GOOD_OLD_REV && |
1039 | (param.s_feature_compat || param.s_feature_ro_compat || |
1040 | param.s_feature_incompat)) |
1041 | param.s_rev_level = 1; /* Create a revision 1 filesystem */ |
1042 | |
1043 | check_plausibility(device_name , force); |
1044 | check_mount(device_name, force, "filesystem"); |
1045 | |
1046 | param.s_log_frag_size = param.s_log_block_size; |
1047 | |
1048 | if (noaction && param.s_blocks_count) { |
1049 | dev_size = param.s_blocks_count; |
1050 | retval = 0; |
1051 | } else { |
1052 | retry: |
1053 | retval = ext2fs_get_device_size(device_name, |
1054 | EXT2_BLOCK_SIZE(¶m), |
1055 | &dev_size); |
1056 | if ((retval == EFBIG) && |
1057 | (blocksize == 0) && |
1058 | (param.s_log_block_size == 0)) { |
1059 | param.s_log_block_size = 2; |
1060 | blocksize = 4096; |
1061 | goto retry; |
1062 | } |
1063 | } |
1064 | |
1065 | mke2fs_error_msg_and_die((retval && (retval != EXT2_ET_UNIMPLEMENTED)),"determine filesystem size"); |
1066 | |
1067 | if (!param.s_blocks_count) { |
1068 | if (retval == EXT2_ET_UNIMPLEMENTED) { |
1069 | mke2fs_error_msg_and_die(1, |
1070 | "determine device size; you " |
1071 | "must specify\nthe size of the " |
1072 | "filesystem"); |
1073 | } else { |
1074 | if (dev_size == 0) { |
1075 | bb_error_msg_and_die( |
1076 | "Device size reported to be zero. " |
1077 | "Invalid partition specified, or\n\t" |
1078 | "partition table wasn't reread " |
1079 | "after running fdisk, due to\n\t" |
1080 | "a modified partition being busy " |
1081 | "and in use. You may need to reboot\n\t" |
1082 | "to re-read your partition table.\n" |
1083 | ); |
1084 | } |
1085 | param.s_blocks_count = dev_size; |
1086 | if (sys_page_size > EXT2_BLOCK_SIZE(¶m)) |
1087 | param.s_blocks_count &= ~((sys_page_size / |
1088 | EXT2_BLOCK_SIZE(¶m))-1); |
1089 | } |
1090 | |
1091 | } else if (!force && (param.s_blocks_count > dev_size)) { |
1092 | bb_error_msg("Filesystem larger than apparent device size"); |
1093 | proceed_question(); |
1094 | } |
1095 | |
1096 | /* |
1097 | * If the user asked for HAS_JOURNAL, then make sure a journal |
1098 | * gets created. |
1099 | */ |
1100 | if ((param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
1101 | !journal_size) |
1102 | journal_size = -1; |
1103 | |
1104 | /* Set first meta blockgroup via an environment variable */ |
1105 | /* (this is mostly for debugging purposes) */ |
1106 | if ((param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && |
1107 | ((tmp = getenv("MKE2FS_FIRST_META_BG")))) |
1108 | param.s_first_meta_bg = atoi(tmp); |
1109 | |
1110 | /* Get the hardware sector size, if available */ |
1111 | retval = ext2fs_get_device_sectsize(device_name, §or_size); |
1112 | mke2fs_error_msg_and_die(retval, "determine hardware sector size"); |
1113 | |
1114 | if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL) |
1115 | sector_size = atoi(tmp); |
1116 | |
1117 | set_fs_defaults(fs_type, ¶m, blocksize, sector_size, &inode_ratio); |
1118 | blocksize = EXT2_BLOCK_SIZE(¶m); |
1119 | |
1120 | if (extended_opts) |
1121 | parse_extended_opts(¶m, extended_opts); |
1122 | |
1123 | /* Since sparse_super is the default, we would only have a problem |
1124 | * here if it was explicitly disabled. |
1125 | */ |
1126 | if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) && |
1127 | !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { |
1128 | bb_error_msg_and_die("reserved online resize blocks not supported " |
1129 | "on non-sparse filesystem"); |
1130 | } |
1131 | |
1132 | if (param.s_blocks_per_group) { |
1133 | if (param.s_blocks_per_group < 256 || |
1134 | param.s_blocks_per_group > 8 * (unsigned) blocksize) { |
1135 | bb_error_msg_and_die("blocks per group count out of range"); |
1136 | } |
1137 | } |
1138 | |
1139 | if (!force && param.s_blocks_count >= (1 << 31)) { |
1140 | bb_error_msg_and_die("Filesystem too large. No more than 2**31-1 blocks\n" |
1141 | "\t (8TB using a blocksize of 4k) are currently supported."); |
1142 | } |
1143 | |
1144 | if (inode_size) { |
1145 | if (inode_size < EXT2_GOOD_OLD_INODE_SIZE || |
1146 | inode_size > EXT2_BLOCK_SIZE(¶m) || |
1147 | inode_size & (inode_size - 1)) { |
1148 | bb_error_msg_and_die("invalid inode size %d (min %d/max %d)", |
1149 | inode_size, EXT2_GOOD_OLD_INODE_SIZE, |
1150 | blocksize); |
1151 | } |
1152 | mke2fs_warning_msg((inode_size != EXT2_GOOD_OLD_INODE_SIZE), |
1153 | "%d-byte inodes not usable on most systems", |
1154 | inode_size); |
1155 | param.s_inode_size = inode_size; |
1156 | } |
1157 | |
1158 | /* |
1159 | * Calculate number of inodes based on the inode ratio |
1160 | */ |
1161 | param.s_inodes_count = num_inodes ? num_inodes : |
1162 | ((__u64) param.s_blocks_count * blocksize) |
1163 | / inode_ratio; |
1164 | |
1165 | /* |
1166 | * Calculate number of blocks to reserve |
1167 | */ |
1168 | param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100; |
1169 | return 1; |
1170 | } |
1171 | |
1172 | static void mke2fs_clean_up(void) |
1173 | { |
1174 | if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device); |
1175 | } |
1176 | |
1177 | int mke2fs_main (int argc, char **argv); |
1178 | int mke2fs_main (int argc, char **argv) |
1179 | { |
1180 | errcode_t retval; |
1181 | ext2_filsys fs; |
1182 | badblocks_list bb_list = 0; |
1183 | unsigned int i; |
1184 | int val; |
1185 | io_manager io_ptr; |
1186 | |
1187 | if (ENABLE_FEATURE_CLEAN_UP) |
1188 | atexit(mke2fs_clean_up); |
1189 | if (!PRS(argc, argv)) |
1190 | return 0; |
1191 | |
1192 | #ifdef CONFIG_TESTIO_DEBUG |
1193 | io_ptr = test_io_manager; |
1194 | test_io_backing_manager = unix_io_manager; |
1195 | #else |
1196 | io_ptr = unix_io_manager; |
1197 | #endif |
1198 | |
1199 | /* |
1200 | * Initialize the superblock.... |
1201 | */ |
1202 | retval = ext2fs_initialize(device_name, 0, ¶m, |
1203 | io_ptr, &fs); |
1204 | mke2fs_error_msg_and_die(retval, "set up superblock"); |
1205 | |
1206 | /* |
1207 | * Wipe out the old on-disk superblock |
1208 | */ |
1209 | if (!noaction) |
1210 | zap_sector(fs, 2, 6); |
1211 | |
1212 | /* |
1213 | * Generate a UUID for it... |
1214 | */ |
1215 | uuid_generate(fs->super->s_uuid); |
1216 | |
1217 | /* |
1218 | * Initialize the directory index variables |
1219 | */ |
1220 | fs->super->s_def_hash_version = EXT2_HASH_TEA; |
1221 | uuid_generate((unsigned char *) fs->super->s_hash_seed); |
1222 | |
1223 | /* |
1224 | * Add "jitter" to the superblock's check interval so that we |
1225 | * don't check all the filesystems at the same time. We use a |
1226 | * kludgy hack of using the UUID to derive a random jitter value. |
1227 | */ |
1228 | for (i = 0, val = 0; i < sizeof(fs->super->s_uuid); i++) |
1229 | val += fs->super->s_uuid[i]; |
1230 | fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT; |
1231 | |
1232 | /* |
1233 | * Override the creator OS, if applicable |
1234 | */ |
1235 | if (creator_os && !set_os(fs->super, creator_os)) { |
1236 | bb_error_msg_and_die("unknown os - %s", creator_os); |
1237 | } |
1238 | |
1239 | /* |
1240 | * For the Hurd, we will turn off filetype since it doesn't |
1241 | * support it. |
1242 | */ |
1243 | if (fs->super->s_creator_os == EXT2_OS_HURD) |
1244 | fs->super->s_feature_incompat &= |
1245 | ~EXT2_FEATURE_INCOMPAT_FILETYPE; |
1246 | |
1247 | /* |
1248 | * Set the volume label... |
1249 | */ |
1250 | if (volume_label) { |
1251 | snprintf(fs->super->s_volume_name, sizeof(fs->super->s_volume_name), "%s", volume_label); |
1252 | } |
1253 | |
1254 | /* |
1255 | * Set the last mount directory |
1256 | */ |
1257 | if (mount_dir) { |
1258 | snprintf(fs->super->s_last_mounted, sizeof(fs->super->s_last_mounted), "%s", mount_dir); |
1259 | } |
1260 | |
1261 | if (!quiet || noaction) |
1262 | show_stats(fs); |
1263 | |
1264 | if (noaction) |
1265 | return 0; |
1266 | |
1267 | if (fs->super->s_feature_incompat & |
1268 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { |
1269 | create_journal_dev(fs); |
1270 | return (ext2fs_close(fs) ? 1 : 0); |
1271 | } |
1272 | |
1273 | if (bad_blocks_filename) |
1274 | read_bb_file(fs, &bb_list, bad_blocks_filename); |
1275 | if (cflag) |
1276 | test_disk(fs, &bb_list); |
1277 | |
1278 | handle_bad_blocks(fs, bb_list); |
1279 | fs->stride = fs_stride; |
1280 | retval = ext2fs_allocate_tables(fs); |
1281 | mke2fs_error_msg_and_die(retval, "allocate filesystem tables"); |
1282 | if (super_only) { |
1283 | fs->super->s_state |= EXT2_ERROR_FS; |
1284 | fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); |
1285 | } else { |
1286 | /* rsv must be a power of two (64kB is MD RAID sb alignment) */ |
1287 | unsigned int rsv = 65536 / fs->blocksize; |
1288 | unsigned long blocks = fs->super->s_blocks_count; |
1289 | unsigned long start; |
1290 | blk_t ret_blk; |
1291 | |
1292 | #ifdef ZAP_BOOTBLOCK |
1293 | zap_sector(fs, 0, 2); |
1294 | #endif |
1295 | |
1296 | /* |
1297 | * Wipe out any old MD RAID (or other) metadata at the end |
1298 | * of the device. This will also verify that the device is |
1299 | * as large as we think. Be careful with very small devices. |
1300 | */ |
1301 | start = (blocks & ~(rsv - 1)); |
1302 | if (start > rsv) |
1303 | start -= rsv; |
1304 | if (start > 0) |
1305 | retval = zero_blocks(fs, start, blocks - start, |
1306 | NULL, &ret_blk, NULL); |
1307 | |
1308 | mke2fs_warning_msg(retval, "can't zero block %u at end of filesystem", ret_blk); |
1309 | write_inode_tables(fs); |
1310 | create_root_dir(fs); |
1311 | create_lost_and_found(fs); |
1312 | reserve_inodes(fs); |
1313 | create_bad_block_inode(fs, bb_list); |
1314 | if (fs->super->s_feature_compat & |
1315 | EXT2_FEATURE_COMPAT_RESIZE_INODE) { |
1316 | retval = ext2fs_create_resize_inode(fs); |
1317 | mke2fs_error_msg_and_die(retval, "reserve blocks for online resize"); |
1318 | } |
1319 | } |
1320 | |
1321 | if (journal_device) { |
1322 | make_journal_device(journal_device, fs, quiet, force); |
1323 | } else if (journal_size) { |
1324 | make_journal_blocks(fs, journal_size, journal_flags, quiet); |
1325 | } |
1326 | |
1327 | mke2fs_verbose("Writing superblocks and filesystem accounting information: "); |
1328 | retval = ext2fs_flush(fs); |
1329 | mke2fs_warning_msg(retval, "had trouble writing out superblocks"); |
1330 | mke2fs_verbose_done(); |
1331 | if (!quiet && !getenv("MKE2FS_SKIP_CHECK_MSG")) |
1332 | print_check_message(fs); |
1333 | val = ext2fs_close(fs); |
1334 | return (retval || val) ? 1 : 0; |
1335 | } |