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