]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * mke2fs.c - Make a ext2fs filesystem. | |
3 | * | |
19c78dc0 TT |
4 | * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. |
5 | * | |
6 | * %Begin-Header% | |
7 | * This file may be redistributed under the terms of the GNU Public | |
8 | * License. | |
9 | * %End-Header% | |
3839e657 TT |
10 | */ |
11 | ||
12 | /* Usage: mke2fs [options] device | |
13 | * | |
14 | * The device may be a block device or a image of one, but this isn't | |
15 | * enforced (but it's not much fun on a character device :-). | |
16 | */ | |
17 | ||
a418d3ad | 18 | #include <stdio.h> |
3839e657 TT |
19 | #include <string.h> |
20 | #include <fcntl.h> | |
21 | #include <ctype.h> | |
22 | #include <termios.h> | |
23 | #include <time.h> | |
a418d3ad | 24 | #ifdef HAVE_GETOPT_H |
3839e657 | 25 | #include <getopt.h> |
a418d3ad TT |
26 | #endif |
27 | #ifdef HAVE_UNISTD_H | |
3839e657 | 28 | #include <unistd.h> |
a418d3ad TT |
29 | #endif |
30 | #ifdef HAVE_STDLIB_H | |
3839e657 | 31 | #include <stdlib.h> |
a418d3ad TT |
32 | #endif |
33 | #ifdef HAVE_ERRNO_H | |
34 | #include <errno.h> | |
35 | #endif | |
36 | #ifdef HAVE_MNTENT_H | |
3839e657 | 37 | #include <mntent.h> |
a418d3ad | 38 | #endif |
3839e657 | 39 | #include <sys/ioctl.h> |
f3db3566 | 40 | #include <sys/types.h> |
74becf3c | 41 | #include <sys/stat.h> |
f3db3566 | 42 | |
a418d3ad | 43 | #ifdef HAVE_LINUX_FS_H |
3839e657 | 44 | #include <linux/fs.h> |
a418d3ad | 45 | #endif |
f3db3566 | 46 | #include <linux/ext2_fs.h> |
74becf3c TT |
47 | #ifdef HAVE_LINUX_MAJOR_H |
48 | #include <linux/major.h> | |
49 | #endif | |
3839e657 TT |
50 | |
51 | #include "et/com_err.h" | |
1e3472c5 | 52 | #include "uuid/uuid.h" |
3839e657 TT |
53 | #include "ext2fs/ext2fs.h" |
54 | #include "../version.h" | |
55 | ||
bbfa3aa9 TT |
56 | /* Everything is STDC, these days */ |
57 | #define NOARGS void | |
58 | ||
3839e657 TT |
59 | #define STRIDE_LENGTH 8 |
60 | ||
1e3472c5 TT |
61 | #ifndef sparc |
62 | #define ZAP_BOOTBLOCK | |
63 | #endif | |
64 | ||
3839e657 | 65 | extern int isatty(int); |
f3db3566 | 66 | extern FILE *fpopen(const char *cmd, const char *mode); |
3839e657 TT |
67 | |
68 | const char * program_name = "mke2fs"; | |
69 | const char * device_name = NULL; | |
70 | ||
71 | /* Command line options */ | |
72 | int cflag = 0; | |
73 | int verbose = 0; | |
74 | int quiet = 0; | |
f3db3566 | 75 | int super_only = 0; |
74becf3c | 76 | int force = 0; |
3839e657 | 77 | char *bad_blocks_filename = 0; |
a29f4d30 | 78 | __u32 fs_stride = 0; |
3839e657 TT |
79 | |
80 | struct ext2_super_block param; | |
1e3472c5 TT |
81 | char *creator_os = NULL; |
82 | char *volume_label = NULL; | |
83 | char *mount_dir = NULL; | |
3839e657 | 84 | |
bbfa3aa9 TT |
85 | static void usage(NOARGS), check_plausibility(NOARGS), check_mount(NOARGS); |
86 | ||
3839e657 TT |
87 | static void usage(NOARGS) |
88 | { | |
1e3472c5 TT |
89 | fprintf(stderr, "Usage: %s [-c|-t|-l filename] [-b block-size] " |
90 | "[-f fragment-size]\n\t[-i bytes-per-inode] " | |
818180cd | 91 | "[-m reserved-blocks-percentage] [-qvSV]\n\t" |
1e3472c5 | 92 | "[-o creator-os] [-g blocks-per-group] [-L volume-label]\n\t" |
a29f4d30 TT |
93 | "[-M last-mounted-directory] [-r fs-revision] [-R raid_opts]\n\t" |
94 | "device [blocks-count]\n", | |
3839e657 TT |
95 | program_name); |
96 | exit(1); | |
97 | } | |
98 | ||
99 | static int log2(int arg) | |
100 | { | |
101 | int l = 0; | |
102 | ||
103 | arg >>= 1; | |
104 | while (arg) { | |
105 | l++; | |
106 | arg >>= 1; | |
107 | } | |
108 | return l; | |
109 | } | |
110 | ||
a789d840 TT |
111 | static void proceed_question(NOARGS) |
112 | { | |
113 | fflush(stdout); | |
114 | fflush(stderr); | |
115 | printf("Proceed anyway? (y,n) "); | |
116 | if (getchar() != 'y') | |
117 | exit(1); | |
118 | } | |
119 | ||
74becf3c TT |
120 | static void check_plausibility(NOARGS) |
121 | { | |
122 | #ifdef HAVE_LINUX_MAJOR_H | |
123 | int val; | |
124 | struct stat s; | |
125 | ||
126 | val = stat(device_name, &s); | |
127 | ||
128 | if(val == -1) { | |
a789d840 TT |
129 | fprintf(stderr, "Could not stat %s --- %s\n", |
130 | device_name, error_message(errno)); | |
19c78dc0 | 131 | if (errno == ENOENT) |
a789d840 TT |
132 | fprintf(stderr, "\nThe device apparently does " |
133 | "not exist; did you specify it correctly?\n"); | |
74becf3c TT |
134 | exit(1); |
135 | } | |
136 | if(!S_ISBLK(s.st_mode)) { | |
137 | printf("%s is not a block special device.\n", device_name); | |
a789d840 | 138 | proceed_question(); |
74becf3c | 139 | return; |
a789d840 TT |
140 | } else if ((MAJOR(s.st_rdev) == HD_MAJOR && |
141 | MINOR(s.st_rdev)%64 == 0) || | |
142 | (MAJOR(s.st_rdev) == SCSI_DISK_MAJOR && | |
143 | MINOR(s.st_rdev)%16 == 0)) { | |
74becf3c TT |
144 | printf("%s is entire device, not just one partition!\n", |
145 | device_name); | |
a789d840 | 146 | proceed_question(); |
74becf3c TT |
147 | } |
148 | #endif | |
149 | } | |
150 | ||
3839e657 TT |
151 | static void check_mount(NOARGS) |
152 | { | |
a418d3ad TT |
153 | errcode_t retval; |
154 | int mount_flags; | |
3839e657 | 155 | |
a418d3ad TT |
156 | retval = ext2fs_check_if_mounted(device_name, &mount_flags); |
157 | if (retval) { | |
158 | com_err("ext2fs_check_if_mount", retval, | |
159 | "while determining whether %s is mounted.", | |
160 | device_name); | |
3839e657 | 161 | return; |
a418d3ad TT |
162 | } |
163 | if (!(mount_flags & EXT2_MF_MOUNTED)) | |
3839e657 | 164 | return; |
a418d3ad | 165 | |
3839e657 TT |
166 | fprintf(stderr, "%s is mounted; will not make a filesystem here!\n", |
167 | device_name); | |
168 | exit(1); | |
169 | } | |
170 | ||
171 | /* | |
172 | * Helper function for read_bb_file and test_disk | |
173 | */ | |
174 | static void invalid_block(ext2_filsys fs, blk_t blk) | |
175 | { | |
a418d3ad | 176 | printf("Bad block %u out of range; ignored.\n", blk); |
3839e657 TT |
177 | return; |
178 | } | |
179 | ||
180 | /* | |
181 | * Reads the bad blocks list from a file | |
182 | */ | |
183 | static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list, | |
184 | const char *bad_blocks_file) | |
185 | { | |
186 | FILE *f; | |
187 | errcode_t retval; | |
188 | ||
189 | f = fopen(bad_blocks_file, "r"); | |
190 | if (!f) { | |
191 | com_err("read_bad_blocks_file", errno, | |
192 | "while trying to open %s", bad_blocks_file); | |
193 | exit(1); | |
194 | } | |
195 | retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block); | |
196 | fclose (f); | |
197 | if (retval) { | |
198 | com_err("ext2fs_read_bb_FILE", retval, | |
199 | "while reading in list of bad blocks from file"); | |
200 | exit(1); | |
201 | } | |
202 | } | |
203 | ||
204 | /* | |
205 | * Runs the badblocks program to test the disk | |
206 | */ | |
207 | static void test_disk(ext2_filsys fs, badblocks_list *bb_list) | |
208 | { | |
209 | FILE *f; | |
210 | errcode_t retval; | |
211 | char buf[1024]; | |
212 | ||
f635d7f6 TT |
213 | sprintf(buf, "badblocks -b %d %s%s %d", fs->blocksize, |
214 | quiet ? "" : "-s ", fs->device_name, | |
3839e657 TT |
215 | fs->super->s_blocks_count); |
216 | if (verbose) | |
217 | printf("Running command: %s\n", buf); | |
218 | f = popen(buf, "r"); | |
219 | if (!f) { | |
220 | com_err("popen", errno, | |
221 | "while trying run '%s'", buf); | |
222 | exit(1); | |
223 | } | |
224 | retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block); | |
f3db3566 | 225 | pclose(f); |
3839e657 TT |
226 | if (retval) { |
227 | com_err("ext2fs_read_bb_FILE", retval, | |
228 | "while processing list of bad blocks from program"); | |
229 | exit(1); | |
230 | } | |
231 | } | |
232 | ||
233 | static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list) | |
234 | { | |
f3db3566 | 235 | int i, j; |
3839e657 TT |
236 | int must_be_good; |
237 | blk_t blk; | |
238 | badblocks_iterate bb_iter; | |
239 | errcode_t retval; | |
f3db3566 TT |
240 | blk_t group_block; |
241 | int group; | |
242 | int group_bad; | |
3839e657 TT |
243 | |
244 | if (!bb_list) | |
245 | return; | |
246 | ||
247 | /* | |
248 | * The primary superblock and group descriptors *must* be | |
249 | * good; if not, abort. | |
250 | */ | |
251 | must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks; | |
252 | for (i = fs->super->s_first_data_block; i <= must_be_good; i++) { | |
253 | if (badblocks_list_test(bb_list, i)) { | |
254 | fprintf(stderr, "Block %d in primary superblock/group " | |
255 | "descriptor area bad.\n", i); | |
a418d3ad | 256 | fprintf(stderr, "Blocks %d through %d must be good " |
3839e657 TT |
257 | "in order to build a filesystem.\n", |
258 | fs->super->s_first_data_block, must_be_good); | |
259 | fprintf(stderr, "Aborting....\n"); | |
260 | exit(1); | |
261 | } | |
262 | } | |
f3db3566 TT |
263 | |
264 | /* | |
265 | * See if any of the bad blocks are showing up in the backup | |
266 | * superblocks and/or group descriptors. If so, issue a | |
267 | * warning and adjust the block counts appropriately. | |
268 | */ | |
269 | group_block = fs->super->s_first_data_block + | |
270 | fs->super->s_blocks_per_group; | |
f3db3566 TT |
271 | |
272 | for (i = 1; i < fs->group_desc_count; i++) { | |
92bcc595 | 273 | group_bad = 0; |
f3db3566 TT |
274 | for (j=0; j < fs->desc_blocks+1; j++) { |
275 | if (badblocks_list_test(bb_list, group_block + | |
276 | j)) { | |
277 | if (!group_bad) | |
278 | fprintf(stderr, | |
a418d3ad | 279 | "Warning: the backup superblock/group descriptors at block %d contain\n" |
f3db3566 TT |
280 | " bad blocks.\n\n", |
281 | group_block); | |
282 | group_bad++; | |
283 | group = ext2fs_group_of_blk(fs, group_block+j); | |
284 | fs->group_desc[group].bg_free_blocks_count++; | |
285 | fs->super->s_free_blocks_count++; | |
286 | } | |
287 | } | |
288 | group_block += fs->super->s_blocks_per_group; | |
289 | } | |
3839e657 TT |
290 | |
291 | /* | |
292 | * Mark all the bad blocks as used... | |
293 | */ | |
294 | retval = badblocks_list_iterate_begin(bb_list, &bb_iter); | |
295 | if (retval) { | |
296 | com_err("badblocks_list_iterate_begin", retval, | |
297 | "while marking bad blocks as used"); | |
298 | exit(1); | |
299 | } | |
300 | while (badblocks_list_iterate(bb_iter, &blk)) | |
f3db3566 | 301 | ext2fs_mark_block_bitmap(fs->block_map, blk); |
3839e657 TT |
302 | badblocks_list_iterate_end(bb_iter); |
303 | } | |
304 | ||
19c78dc0 | 305 | static void write_inode_tables(ext2_filsys fs) |
3839e657 TT |
306 | { |
307 | errcode_t retval; | |
308 | blk_t blk; | |
19c78dc0 TT |
309 | int i, j, num, count; |
310 | char *buf; | |
3839e657 TT |
311 | |
312 | buf = malloc(fs->blocksize * STRIDE_LENGTH); | |
313 | if (!buf) { | |
314 | com_err("malloc", ENOMEM, "while allocating zeroizing buffer"); | |
315 | exit(1); | |
316 | } | |
317 | memset(buf, 0, fs->blocksize * STRIDE_LENGTH); | |
318 | ||
3839e657 TT |
319 | if (!quiet) |
320 | printf("Writing inode tables: "); | |
321 | for (i = 0; i < fs->group_desc_count; i++) { | |
322 | if (!quiet) | |
323 | printf("%4d/%4ld", i, fs->group_desc_count); | |
3839e657 | 324 | |
19c78dc0 TT |
325 | blk = fs->group_desc[i].bg_inode_table; |
326 | num = fs->inode_blocks_per_group; | |
327 | ||
328 | for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { | |
329 | if (num-j > STRIDE_LENGTH) | |
330 | count = STRIDE_LENGTH; | |
331 | else | |
332 | count = num - j; | |
333 | retval = io_channel_write_blk(fs->io, blk, count, buf); | |
334 | if (retval) | |
335 | printf("Warning: could not write %d blocks " | |
336 | "in inode table starting at %d: %s\n", | |
337 | count, blk, error_message(retval)); | |
338 | } | |
3839e657 TT |
339 | if (!quiet) |
340 | printf("\b\b\b\b\b\b\b\b\b"); | |
341 | } | |
19c78dc0 | 342 | free(buf); |
3839e657 TT |
343 | if (!quiet) |
344 | printf("done \n"); | |
345 | } | |
346 | ||
347 | static void create_root_dir(ext2_filsys fs) | |
348 | { | |
349 | errcode_t retval; | |
f3db3566 | 350 | struct ext2_inode inode; |
3839e657 TT |
351 | |
352 | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); | |
353 | if (retval) { | |
354 | com_err("ext2fs_mkdir", retval, "while creating root dir"); | |
355 | exit(1); | |
356 | } | |
f3db3566 TT |
357 | if (geteuid()) { |
358 | retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode); | |
359 | if (retval) { | |
360 | com_err("ext2fs_read_inode", retval, | |
361 | "while reading root inode"); | |
362 | exit(1); | |
363 | } | |
19c78dc0 TT |
364 | inode.i_uid = getuid(); |
365 | if (inode.i_uid) | |
366 | inode.i_gid = getgid(); | |
f3db3566 TT |
367 | retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode); |
368 | if (retval) { | |
369 | com_err("ext2fs_write_inode", retval, | |
370 | "while setting root inode ownership"); | |
371 | exit(1); | |
372 | } | |
373 | } | |
3839e657 TT |
374 | } |
375 | ||
376 | static void create_lost_and_found(ext2_filsys fs) | |
377 | { | |
378 | errcode_t retval; | |
379 | ino_t ino; | |
380 | const char *name = "lost+found"; | |
381 | int i; | |
382 | ||
383 | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name); | |
384 | if (retval) { | |
385 | com_err("ext2fs_mkdir", retval, "while creating /lost+found"); | |
386 | exit(1); | |
387 | } | |
388 | ||
389 | retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino); | |
390 | if (retval) { | |
391 | com_err("ext2_lookup", retval, "while looking up /lost+found"); | |
392 | exit(1); | |
393 | } | |
394 | ||
395 | for (i=1; i < EXT2_NDIR_BLOCKS; i++) { | |
396 | retval = ext2fs_expand_dir(fs, ino); | |
397 | if (retval) { | |
398 | com_err("ext2fs_expand_dir", retval, | |
399 | "while expanding /lost+found"); | |
400 | exit(1); | |
401 | } | |
402 | } | |
403 | } | |
404 | ||
405 | static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list) | |
406 | { | |
407 | errcode_t retval; | |
408 | ||
f3db3566 | 409 | ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO); |
3839e657 TT |
410 | fs->group_desc[0].bg_free_inodes_count--; |
411 | fs->super->s_free_inodes_count--; | |
412 | retval = ext2fs_update_bb_inode(fs, bb_list); | |
413 | if (retval) { | |
414 | com_err("ext2fs_update_bb_inode", retval, | |
415 | "while setting bad block inode"); | |
416 | exit(1); | |
417 | } | |
418 | ||
419 | } | |
420 | ||
421 | static void reserve_inodes(ext2_filsys fs) | |
422 | { | |
423 | ino_t i; | |
424 | int group; | |
425 | ||
7f88b043 | 426 | for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) { |
f3db3566 | 427 | ext2fs_mark_inode_bitmap(fs->inode_map, i); |
3839e657 TT |
428 | group = ext2fs_group_of_ino(fs, i); |
429 | fs->group_desc[group].bg_free_inodes_count--; | |
430 | fs->super->s_free_inodes_count--; | |
431 | } | |
432 | ext2fs_mark_ib_dirty(fs); | |
433 | } | |
434 | ||
1e3472c5 | 435 | #ifdef ZAP_BOOTBLOCK |
f3db3566 TT |
436 | static void zap_bootblock(ext2_filsys fs) |
437 | { | |
438 | char buf[512]; | |
439 | int retval; | |
440 | ||
441 | memset(buf, 0, 512); | |
442 | ||
443 | retval = io_channel_write_blk(fs->io, 0, -512, buf); | |
444 | if (retval) | |
445 | printf("Warning: could not erase block 0: %s\n", | |
446 | error_message(retval)); | |
447 | } | |
1e3472c5 | 448 | #endif |
f3db3566 TT |
449 | |
450 | ||
3839e657 TT |
451 | static void show_stats(ext2_filsys fs) |
452 | { | |
1e3472c5 TT |
453 | struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super; |
454 | char buf[80]; | |
3839e657 TT |
455 | blk_t group_block; |
456 | int i, col_left; | |
457 | ||
458 | if (param.s_blocks_count != s->s_blocks_count) | |
a418d3ad | 459 | printf("warning: %d blocks unused.\n\n", |
3839e657 TT |
460 | param.s_blocks_count - s->s_blocks_count); |
461 | ||
1e3472c5 TT |
462 | switch (fs->super->s_creator_os) { |
463 | case EXT2_OS_LINUX: printf ("Linux"); break; | |
464 | case EXT2_OS_HURD: printf ("GNU/hurd"); break; | |
465 | case EXT2_OS_MASIX: printf ("Masix"); break; | |
466 | default: printf ("(unknown os)"); | |
467 | } | |
468 | printf (" ext2 filesystem format\n"); | |
469 | memset(buf, 0, sizeof(buf)); | |
470 | strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name)); | |
471 | printf("Filesystem label=%s\n", buf); | |
a418d3ad | 472 | printf("%u inodes, %u blocks\n", s->s_inodes_count, |
3839e657 | 473 | s->s_blocks_count); |
a418d3ad | 474 | printf("%u blocks (%2.2f%%) reserved for the super user\n", |
3839e657 TT |
475 | s->s_r_blocks_count, |
476 | 100.0 * s->s_r_blocks_count / s->s_blocks_count); | |
a418d3ad TT |
477 | printf("First data block=%u\n", s->s_first_data_block); |
478 | printf("Block size=%u (log=%u)\n", fs->blocksize, | |
3839e657 | 479 | s->s_log_block_size); |
a418d3ad | 480 | printf("Fragment size=%u (log=%u)\n", fs->fragsize, |
3839e657 TT |
481 | s->s_log_frag_size); |
482 | printf("%lu block group%s\n", fs->group_desc_count, | |
483 | (fs->group_desc_count > 1) ? "s" : ""); | |
a418d3ad | 484 | printf("%u blocks per group, %u fragments per group\n", |
3839e657 | 485 | s->s_blocks_per_group, s->s_frags_per_group); |
a418d3ad | 486 | printf("%u inodes per group\n", s->s_inodes_per_group); |
3839e657 TT |
487 | |
488 | if (fs->group_desc_count == 1) { | |
489 | printf("\n"); | |
490 | return; | |
491 | } | |
492 | ||
493 | printf("Superblock backups stored on blocks: "); | |
494 | group_block = s->s_first_data_block; | |
495 | col_left = 0; | |
496 | for (i = 1; i < fs->group_desc_count; i++) { | |
497 | group_block += s->s_blocks_per_group; | |
521e3685 TT |
498 | if (!ext2fs_bg_has_super(fs, i)) |
499 | continue; | |
3839e657 TT |
500 | if (!col_left--) { |
501 | printf("\n\t"); | |
e22d4616 | 502 | col_left = 6; |
3839e657 | 503 | } |
a418d3ad | 504 | printf("%u", group_block); |
3839e657 TT |
505 | if (i != fs->group_desc_count - 1) |
506 | printf(", "); | |
507 | } | |
508 | printf("\n\n"); | |
509 | } | |
510 | ||
1e3472c5 TT |
511 | #ifndef HAVE_STRCASECMP |
512 | static int strcasecmp (char *s1, char *s2) | |
513 | { | |
514 | while (*s1 && *s2) { | |
515 | int ch1 = *s1++, ch2 = *s2++; | |
516 | if (isupper (ch1)) | |
517 | ch1 = tolower (ch1); | |
518 | if (isupper (ch2)) | |
519 | ch2 = tolower (ch2); | |
520 | if (ch1 != ch2) | |
521 | return ch1 - ch2; | |
522 | } | |
523 | return *s1 ? 1 : *s2 ? -1 : 0; | |
524 | } | |
525 | #endif | |
526 | ||
527 | /* | |
528 | * Set the S_CREATOR_OS field. Return true if OS is known, | |
529 | * otherwise, 0. | |
530 | */ | |
531 | static int set_os(struct ext2_super_block *sb, char *os) | |
532 | { | |
533 | if (isdigit (*os)) | |
534 | sb->s_creator_os = atoi (os); | |
535 | else if (strcasecmp(os, "linux") == 0) | |
536 | sb->s_creator_os = EXT2_OS_LINUX; | |
537 | else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0) | |
538 | sb->s_creator_os = EXT2_OS_HURD; | |
539 | else if (strcasecmp(os, "masix") == 0) | |
540 | sb->s_creator_os = EXT2_OS_MASIX; | |
541 | else | |
542 | return 0; | |
543 | return 1; | |
544 | } | |
545 | ||
a418d3ad TT |
546 | #define PATH_SET "PATH=/sbin" |
547 | ||
d163b094 | 548 | static void parse_raid_opts(const char *opts) |
a29f4d30 TT |
549 | { |
550 | char *buf, *token, *next, *p, *arg; | |
551 | int len; | |
552 | int raid_usage = 0; | |
553 | ||
554 | len = strlen(opts); | |
555 | buf = malloc(len+1); | |
556 | if (!buf) { | |
557 | fprintf(stderr, "Couldn't allocate memory to parse " | |
558 | "raid options!\n"); | |
559 | exit(1); | |
560 | } | |
561 | strcpy(buf, opts); | |
562 | for (token = buf; token && *token; token = next) { | |
563 | p = strchr(token, ','); | |
564 | next = 0; | |
565 | if (p) { | |
566 | *p = 0; | |
567 | next = p+1; | |
568 | } | |
569 | arg = strchr(token, '='); | |
570 | if (arg) { | |
571 | *arg = 0; | |
572 | arg++; | |
573 | } | |
574 | if (strcmp(token, "stride") == 0) { | |
575 | if (!arg) { | |
576 | raid_usage++; | |
577 | continue; | |
578 | } | |
579 | fs_stride = strtoul(arg, &p, 0); | |
580 | if (*p || (fs_stride == 0)) { | |
581 | fprintf(stderr, "Invalid stride parameter.\n"); | |
582 | raid_usage++; | |
583 | continue; | |
584 | } | |
585 | } else | |
586 | raid_usage++; | |
587 | } | |
588 | if (raid_usage) { | |
589 | fprintf(stderr, "\nBad raid options specified.\n\n" | |
590 | "Raid options are separated by commas, " | |
591 | "and may take an argument which\n" | |
592 | "\tis set off by an equals ('=') sign.\n\n" | |
593 | "Valid raid options are:\n" | |
594 | "\tstride=<stride length in blocks>\n\n"); | |
595 | exit(1); | |
596 | } | |
597 | } | |
598 | ||
599 | ||
600 | ||
3839e657 TT |
601 | static void PRS(int argc, char *argv[]) |
602 | { | |
519149fb | 603 | int c; |
3839e657 TT |
604 | int size; |
605 | char * tmp; | |
521e3685 | 606 | blk_t max = 8192; |
3839e657 TT |
607 | int inode_ratio = 4096; |
608 | int reserved_ratio = 5; | |
a418d3ad | 609 | errcode_t retval; |
521e3685 | 610 | int sparse_option = -1; |
a418d3ad | 611 | char *oldpath = getenv("PATH"); |
521e3685 | 612 | struct ext2fs_sb *param_ext2 = (struct ext2fs_sb *) ¶m; |
a29f4d30 | 613 | char *raid_opts = 0; |
a789d840 | 614 | blk_t dev_size; |
521e3685 | 615 | |
3839e657 | 616 | /* Update our PATH to include /sbin */ |
a418d3ad TT |
617 | if (oldpath) { |
618 | char *newpath; | |
619 | ||
620 | newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath)); | |
621 | strcpy (newpath, PATH_SET); | |
622 | strcat (newpath, ":"); | |
623 | strcat (newpath, oldpath); | |
624 | putenv (newpath); | |
625 | } else | |
626 | putenv (PATH_SET); | |
3839e657 TT |
627 | |
628 | setbuf(stdout, NULL); | |
629 | setbuf(stderr, NULL); | |
630 | initialize_ext2_error_table(); | |
631 | memset(¶m, 0, sizeof(struct ext2_super_block)); | |
632 | ||
633 | fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n", | |
634 | E2FSPROGS_VERSION, E2FSPROGS_DATE, | |
635 | EXT2FS_VERSION, EXT2FS_DATE); | |
636 | if (argc && *argv) | |
637 | program_name = *argv; | |
1e3472c5 | 638 | while ((c = getopt (argc, argv, |
818180cd | 639 | "b:cf:g:i:l:m:o:qr:R:s:tvI:SFL:M:V")) != EOF) |
3839e657 TT |
640 | switch (c) { |
641 | case 'b': | |
642 | size = strtoul(optarg, &tmp, 0); | |
643 | if (size < 1024 || size > 4096 || *tmp) { | |
644 | com_err(program_name, 0, "bad block size - %s", | |
645 | optarg); | |
646 | exit(1); | |
647 | } | |
648 | param.s_log_block_size = | |
649 | log2(size >> EXT2_MIN_BLOCK_LOG_SIZE); | |
521e3685 | 650 | max = size * 8; |
3839e657 TT |
651 | break; |
652 | case 'c': | |
653 | case 't': /* Check for bad blocks */ | |
654 | cflag = 1; | |
655 | break; | |
656 | case 'f': | |
657 | size = strtoul(optarg, &tmp, 0); | |
658 | if (size < 1024 || size > 4096 || *tmp) { | |
659 | com_err(program_name, 0, "bad fragment size - %s", | |
660 | optarg); | |
661 | exit(1); | |
662 | } | |
663 | param.s_log_frag_size = | |
664 | log2(size >> EXT2_MIN_BLOCK_LOG_SIZE); | |
665 | printf("Warning: fragments not supported. " | |
666 | "Ignoring -f option\n"); | |
667 | break; | |
668 | case 'g': | |
669 | param.s_blocks_per_group = strtoul(optarg, &tmp, 0); | |
f3db3566 TT |
670 | if (*tmp) { |
671 | com_err(program_name, 0, | |
672 | "Illegal number for blocks per group"); | |
673 | exit(1); | |
674 | } | |
f3db3566 TT |
675 | if ((param.s_blocks_per_group % 8) != 0) { |
676 | com_err(program_name, 0, | |
677 | "blocks per group must be multiple of 8"); | |
3839e657 TT |
678 | exit(1); |
679 | } | |
680 | break; | |
681 | case 'i': | |
682 | inode_ratio = strtoul(optarg, &tmp, 0); | |
683 | if (inode_ratio < 1024 || inode_ratio > 256 * 1024 || | |
684 | *tmp) { | |
685 | com_err(program_name, 0, "bad inode ratio - %s", | |
686 | optarg); | |
687 | exit(1); | |
688 | } | |
689 | break; | |
690 | case 'l': | |
f3db3566 TT |
691 | bad_blocks_filename = malloc(strlen(optarg)+1); |
692 | if (!bad_blocks_filename) { | |
693 | com_err(program_name, ENOMEM, | |
694 | "in malloc for bad_blocks_filename"); | |
695 | exit(1); | |
696 | } | |
697 | strcpy(bad_blocks_filename, optarg); | |
3839e657 TT |
698 | break; |
699 | case 'm': | |
700 | reserved_ratio = strtoul(optarg, &tmp, 0); | |
701 | if (reserved_ratio > 50 || *tmp) { | |
702 | com_err(program_name, 0, | |
703 | "bad reserved blocks percent - %s", | |
704 | optarg); | |
705 | exit(1); | |
706 | } | |
707 | break; | |
1e3472c5 TT |
708 | case 'o': |
709 | creator_os = optarg; | |
710 | break; | |
7f88b043 TT |
711 | case 'r': |
712 | param.s_rev_level = atoi(optarg); | |
713 | break; | |
521e3685 TT |
714 | case 's': |
715 | sparse_option = atoi(optarg); | |
716 | break; | |
7f88b043 TT |
717 | #ifdef EXT2_DYNAMIC_REV |
718 | case 'I': | |
719 | param.s_inode_size = atoi(optarg); | |
720 | break; | |
721 | #endif | |
3839e657 TT |
722 | case 'v': |
723 | verbose = 1; | |
724 | break; | |
725 | case 'q': | |
726 | quiet = 1; | |
727 | break; | |
74becf3c TT |
728 | case 'F': |
729 | force = 1; | |
730 | break; | |
1e3472c5 TT |
731 | case 'L': |
732 | volume_label = optarg; | |
733 | break; | |
734 | case 'M': | |
735 | mount_dir = optarg; | |
736 | break; | |
a29f4d30 TT |
737 | case 'R': |
738 | raid_opts = optarg; | |
739 | break; | |
f3db3566 TT |
740 | case 'S': |
741 | super_only = 1; | |
742 | break; | |
818180cd TT |
743 | case 'V': |
744 | /* Print version number and exit */ | |
745 | fprintf(stderr, "\tUsing %s\n", | |
746 | error_message(EXT2_ET_BASE)); | |
747 | exit(0); | |
3839e657 TT |
748 | default: |
749 | usage(); | |
750 | } | |
751 | if (optind == argc) | |
752 | usage(); | |
753 | device_name = argv[optind]; | |
754 | optind++; | |
755 | if (optind < argc) { | |
756 | param.s_blocks_count = strtoul(argv[optind++], &tmp, 0); | |
757 | if (*tmp) { | |
758 | com_err(program_name, 0, "bad blocks count - %s", | |
759 | argv[optind - 1]); | |
760 | exit(1); | |
761 | } | |
762 | } | |
763 | if (optind < argc) | |
764 | usage(); | |
a418d3ad | 765 | |
a29f4d30 TT |
766 | if (raid_opts) |
767 | parse_raid_opts(raid_opts); | |
768 | ||
74becf3c TT |
769 | if (!force) |
770 | check_plausibility(); | |
a418d3ad TT |
771 | check_mount(); |
772 | ||
3839e657 TT |
773 | param.s_log_frag_size = param.s_log_block_size; |
774 | ||
a789d840 TT |
775 | retval = ext2fs_get_device_size(device_name, |
776 | EXT2_BLOCK_SIZE(¶m), | |
777 | &dev_size); | |
778 | if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) { | |
779 | com_err(program_name, retval, | |
780 | "while trying to determine filesystem size"); | |
781 | exit(1); | |
782 | } | |
a418d3ad | 783 | if (!param.s_blocks_count) { |
a789d840 TT |
784 | if (retval == EXT2_ET_UNIMPLEMENTED) { |
785 | com_err(program_name, 0, | |
786 | "Couldn't determine device size; you " | |
787 | "must specify\nthe size of the " | |
788 | "filesystem\n"); | |
a418d3ad | 789 | exit(1); |
a789d840 TT |
790 | } else |
791 | param.s_blocks_count = dev_size; | |
792 | } else if (!force && (param.s_blocks_count > dev_size)) { | |
793 | com_err(program_name, 0, | |
794 | "Filesystem larger than apparent filesystem size."); | |
795 | proceed_question(); | |
a418d3ad | 796 | } |
3839e657 | 797 | |
521e3685 TT |
798 | if (param.s_blocks_per_group) { |
799 | if (param.s_blocks_per_group < 256 || | |
800 | param.s_blocks_per_group > max || *tmp) { | |
801 | com_err(program_name, 0, | |
802 | "blocks per group count out of range"); | |
803 | exit(1); | |
804 | } | |
805 | } | |
806 | ||
3839e657 TT |
807 | /* |
808 | * Calculate number of inodes based on the inode ratio | |
809 | */ | |
810 | param.s_inodes_count = | |
f3db3566 TT |
811 | ((long long) param.s_blocks_count * EXT2_BLOCK_SIZE(¶m)) |
812 | / inode_ratio; | |
3839e657 TT |
813 | |
814 | /* | |
815 | * Calculate number of blocks to reserve | |
816 | */ | |
817 | param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100; | |
521e3685 TT |
818 | |
819 | /* | |
820 | * If we are using revision #1, use the sparse super feature | |
821 | * by default | |
822 | */ | |
823 | #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | |
824 | if ((sparse_option == 1) | |
825 | #ifdef EXT2_DYNAMIC_REV | |
bbfa3aa9 | 826 | || ((param.s_rev_level >= EXT2_DYNAMIC_REV) && (!sparse_option)) |
521e3685 TT |
827 | #endif |
828 | ) | |
829 | param_ext2->s_feature_ro_compat |= | |
830 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
831 | #endif | |
3839e657 TT |
832 | } |
833 | ||
834 | int main (int argc, char *argv[]) | |
835 | { | |
836 | errcode_t retval = 0; | |
837 | ext2_filsys fs; | |
838 | badblocks_list bb_list = 0; | |
1e3472c5 | 839 | struct ext2fs_sb *s; |
3839e657 TT |
840 | |
841 | PRS(argc, argv); | |
842 | ||
3839e657 TT |
843 | /* |
844 | * Initialize the superblock.... | |
845 | */ | |
846 | retval = ext2fs_initialize(device_name, 0, ¶m, | |
847 | unix_io_manager, &fs); | |
848 | if (retval) { | |
849 | com_err(device_name, retval, "while setting up superblock"); | |
850 | exit(1); | |
851 | } | |
852 | ||
1e3472c5 TT |
853 | /* |
854 | * Generate a UUID for it... | |
855 | */ | |
856 | s = (struct ext2fs_sb *) fs->super; | |
857 | uuid_generate(s->s_uuid); | |
858 | ||
859 | /* | |
860 | * Override the creator OS, if applicable | |
861 | */ | |
862 | if (creator_os && !set_os(fs->super, creator_os)) { | |
863 | com_err (program_name, 0, "unknown os - %s", creator_os); | |
864 | exit(1); | |
865 | } | |
866 | ||
867 | /* | |
868 | * Set the volume label... | |
869 | */ | |
870 | if (volume_label) { | |
871 | memset(s->s_volume_name, 0, sizeof(s->s_volume_name)); | |
872 | strncpy(s->s_volume_name, volume_label, | |
873 | sizeof(s->s_volume_name)); | |
874 | } | |
875 | ||
876 | /* | |
877 | * Set the last mount directory | |
878 | */ | |
879 | if (mount_dir) { | |
880 | memset(s->s_last_mounted, 0, sizeof(s->s_last_mounted)); | |
881 | strncpy(s->s_last_mounted, mount_dir, | |
882 | sizeof(s->s_last_mounted)); | |
883 | } | |
884 | ||
3839e657 TT |
885 | if (!quiet) |
886 | show_stats(fs); | |
887 | ||
888 | if (bad_blocks_filename) | |
889 | read_bb_file(fs, &bb_list, bad_blocks_filename); | |
890 | if (cflag) | |
891 | test_disk(fs, &bb_list); | |
892 | ||
893 | handle_bad_blocks(fs, bb_list); | |
a29f4d30 | 894 | fs->stride = fs_stride; |
19c78dc0 TT |
895 | retval = ext2fs_allocate_tables(fs); |
896 | if (retval) { | |
897 | com_err(program_name, retval, | |
898 | "while trying to allocate filesystem tables"); | |
899 | exit(1); | |
900 | } | |
f3db3566 TT |
901 | if (super_only) { |
902 | fs->super->s_state |= EXT2_ERROR_FS; | |
903 | fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); | |
904 | } else { | |
19c78dc0 | 905 | write_inode_tables(fs); |
f3db3566 TT |
906 | create_root_dir(fs); |
907 | create_lost_and_found(fs); | |
908 | reserve_inodes(fs); | |
909 | create_bad_block_inode(fs, bb_list); | |
1e3472c5 | 910 | #ifdef ZAP_BOOTBLOCK |
f3db3566 | 911 | zap_bootblock(fs); |
1e3472c5 | 912 | #endif |
f3db3566 | 913 | } |
3839e657 TT |
914 | |
915 | if (!quiet) | |
916 | printf("Writing superblocks and " | |
917 | "filesystem accounting information: "); | |
918 | ext2fs_close(fs); | |
919 | if (!quiet) | |
920 | printf("done\n"); | |
921 | return 0; | |
922 | } |