blob: 687deba65a0b824b069854fd83f8e00a025c4fd1 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * mke2fs.c - Make a ext2fs filesystem.
3 *
4 * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8/* Usage: mke2fs [options] device
9 *
10 * The device may be a block device or a image of one, but this isn't
11 * enforced (but it's not much fun on a character device :-).
12 */
13
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000014#include <stdio.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <string.h>
16#include <fcntl.h>
17#include <ctype.h>
18#include <termios.h>
19#include <time.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000020#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000021#include <getopt.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000022#endif
23#ifdef HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000024#include <unistd.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000025#endif
26#ifdef HAVE_STDLIB_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000027#include <stdlib.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000028#endif
29#ifdef HAVE_ERRNO_H
30#include <errno.h>
31#endif
32#ifdef HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000033#include <mntent.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000034#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000035#include <malloc.h>
36#include <sys/ioctl.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000037#include <sys/types.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000038#include <stdio.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000039
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000040#ifdef HAVE_LINUX_FS_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000041#include <linux/fs.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000042#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000043#include <linux/ext2_fs.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000044
45#include "et/com_err.h"
46#include "ext2fs/ext2fs.h"
47#include "../version.h"
48
49#define STRIDE_LENGTH 8
50
51extern int isatty(int);
Theodore Ts'of3db3561997-04-26 13:34:30 +000052extern FILE *fpopen(const char *cmd, const char *mode);
Theodore Ts'o3839e651997-04-26 13:21:57 +000053
54const char * program_name = "mke2fs";
55const char * device_name = NULL;
56
57/* Command line options */
58int cflag = 0;
59int verbose = 0;
60int quiet = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000061int super_only = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000062char *bad_blocks_filename = 0;
63
64struct ext2_super_block param;
65
66static void usage(NOARGS)
67{
68 fprintf(stderr,
69 "Usage: %s [-c|-t|-l filename] [-b block-size] "
70 "[-f fragment-size]\n\t[-i bytes-per-inode] "
Theodore Ts'of3db3561997-04-26 13:34:30 +000071 "[-m reserved-blocks-percentage] [-qvS]\n"
72 "\t[-g blocks-per-group] device [blocks-count]\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +000073 program_name);
74 exit(1);
75}
76
77static int log2(int arg)
78{
79 int l = 0;
80
81 arg >>= 1;
82 while (arg) {
83 l++;
84 arg >>= 1;
85 }
86 return l;
87}
88
Theodore Ts'o3839e651997-04-26 13:21:57 +000089static void check_mount(NOARGS)
90{
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000091 errcode_t retval;
92 int mount_flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +000093
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000094 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
95 if (retval) {
96 com_err("ext2fs_check_if_mount", retval,
97 "while determining whether %s is mounted.",
98 device_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +000099 return;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000100 }
101 if (!(mount_flags & EXT2_MF_MOUNTED))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102 return;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000103
Theodore Ts'o3839e651997-04-26 13:21:57 +0000104 fprintf(stderr, "%s is mounted; will not make a filesystem here!\n",
105 device_name);
106 exit(1);
107}
108
109/*
110 * Helper function for read_bb_file and test_disk
111 */
112static void invalid_block(ext2_filsys fs, blk_t blk)
113{
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000114 printf("Bad block %u out of range; ignored.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000115 return;
116}
117
118/*
119 * Reads the bad blocks list from a file
120 */
121static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
122 const char *bad_blocks_file)
123{
124 FILE *f;
125 errcode_t retval;
126
127 f = fopen(bad_blocks_file, "r");
128 if (!f) {
129 com_err("read_bad_blocks_file", errno,
130 "while trying to open %s", bad_blocks_file);
131 exit(1);
132 }
133 retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
134 fclose (f);
135 if (retval) {
136 com_err("ext2fs_read_bb_FILE", retval,
137 "while reading in list of bad blocks from file");
138 exit(1);
139 }
140}
141
142/*
143 * Runs the badblocks program to test the disk
144 */
145static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
146{
147 FILE *f;
148 errcode_t retval;
149 char buf[1024];
150
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000151 sprintf(buf, "badblocks %s%s %d", quiet ? "" : "-s ",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000152 fs->device_name,
153 fs->super->s_blocks_count);
154 if (verbose)
155 printf("Running command: %s\n", buf);
156 f = popen(buf, "r");
157 if (!f) {
158 com_err("popen", errno,
159 "while trying run '%s'", buf);
160 exit(1);
161 }
162 retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000163 pclose(f);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000164 if (retval) {
165 com_err("ext2fs_read_bb_FILE", retval,
166 "while processing list of bad blocks from program");
167 exit(1);
168 }
169}
170
171static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
172{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000173 int i, j;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000174 int must_be_good;
175 blk_t blk;
176 badblocks_iterate bb_iter;
177 errcode_t retval;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000178 blk_t group_block;
179 int group;
180 int group_bad;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000181
182 if (!bb_list)
183 return;
184
185 /*
186 * The primary superblock and group descriptors *must* be
187 * good; if not, abort.
188 */
189 must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
190 for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
191 if (badblocks_list_test(bb_list, i)) {
192 fprintf(stderr, "Block %d in primary superblock/group "
193 "descriptor area bad.\n", i);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000194 fprintf(stderr, "Blocks %d through %d must be good "
Theodore Ts'o3839e651997-04-26 13:21:57 +0000195 "in order to build a filesystem.\n",
196 fs->super->s_first_data_block, must_be_good);
197 fprintf(stderr, "Aborting....\n");
198 exit(1);
199 }
200 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000201
202 /*
203 * See if any of the bad blocks are showing up in the backup
204 * superblocks and/or group descriptors. If so, issue a
205 * warning and adjust the block counts appropriately.
206 */
207 group_block = fs->super->s_first_data_block +
208 fs->super->s_blocks_per_group;
209 group_bad = 0;
210
211 for (i = 1; i < fs->group_desc_count; i++) {
212 for (j=0; j < fs->desc_blocks+1; j++) {
213 if (badblocks_list_test(bb_list, group_block +
214 j)) {
215 if (!group_bad)
216 fprintf(stderr,
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000217"Warning: the backup superblock/group descriptors at block %d contain\n"
Theodore Ts'of3db3561997-04-26 13:34:30 +0000218" bad blocks.\n\n",
219 group_block);
220 group_bad++;
221 group = ext2fs_group_of_blk(fs, group_block+j);
222 fs->group_desc[group].bg_free_blocks_count++;
223 fs->super->s_free_blocks_count++;
224 }
225 }
226 group_block += fs->super->s_blocks_per_group;
227 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000228
229 /*
230 * Mark all the bad blocks as used...
231 */
232 retval = badblocks_list_iterate_begin(bb_list, &bb_iter);
233 if (retval) {
234 com_err("badblocks_list_iterate_begin", retval,
235 "while marking bad blocks as used");
236 exit(1);
237 }
238 while (badblocks_list_iterate(bb_iter, &blk))
Theodore Ts'of3db3561997-04-26 13:34:30 +0000239 ext2fs_mark_block_bitmap(fs->block_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000240 badblocks_list_iterate_end(bb_iter);
241}
242
243static void new_table_block(ext2_filsys fs, blk_t first_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000244 const char *name, int num, int initialize,
245 const char *buf, blk_t *new_block)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000246{
247 errcode_t retval;
248 blk_t blk;
249 int i;
250 int count;
251
252 retval = ext2fs_get_free_blocks(fs, first_block,
253 first_block + fs->super->s_blocks_per_group,
254 num, fs->block_map, new_block);
255 if (retval) {
256 printf("Could not allocate %d block(s) for %s: %s\n",
257 num, name, error_message(retval));
258 ext2fs_unmark_valid(fs);
259 return;
260 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000261 if (initialize) {
262 blk = *new_block;
263 for (i=0; i < num; i += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
264 if (num-i > STRIDE_LENGTH)
265 count = STRIDE_LENGTH;
266 else
267 count = num - i;
268 retval = io_channel_write_blk(fs->io, blk, count, buf);
269 if (retval)
270 printf("Warning: could not write %d blocks "
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000271 "starting at %d for %s: %s\n",
Theodore Ts'of3db3561997-04-26 13:34:30 +0000272 count, blk, name,
273 error_message(retval));
274 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000275 }
276 blk = *new_block;
277 for (i = 0; i < num; i++, blk++)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000278 ext2fs_mark_block_bitmap(fs->block_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000279}
280
281static void alloc_tables(ext2_filsys fs)
282{
283 blk_t group_blk;
284 int i;
285 char *buf;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000286
287 buf = malloc(fs->blocksize * STRIDE_LENGTH);
288 if (!buf) {
289 com_err("malloc", ENOMEM, "while allocating zeroizing buffer");
290 exit(1);
291 }
292 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
293
294 group_blk = fs->super->s_first_data_block;
295 if (!quiet)
296 printf("Writing inode tables: ");
297 for (i = 0; i < fs->group_desc_count; i++) {
298 if (!quiet)
299 printf("%4d/%4ld", i, fs->group_desc_count);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000300 new_table_block(fs, group_blk, "block bitmap", 1, 0, buf,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000301 &fs->group_desc[i].bg_block_bitmap);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000302 new_table_block(fs, group_blk, "inode bitmap", 1, 0, buf,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000303 &fs->group_desc[i].bg_inode_bitmap);
304 new_table_block(fs, group_blk, "inode table",
Theodore Ts'of3db3561997-04-26 13:34:30 +0000305 fs->inode_blocks_per_group,
306 !super_only, buf,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000307 &fs->group_desc[i].bg_inode_table);
308
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309 group_blk += fs->super->s_blocks_per_group;
310 if (!quiet)
311 printf("\b\b\b\b\b\b\b\b\b");
312 }
313 if (!quiet)
314 printf("done \n");
315}
316
317static void create_root_dir(ext2_filsys fs)
318{
319 errcode_t retval;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000320 struct ext2_inode inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000321
322 retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
323 if (retval) {
324 com_err("ext2fs_mkdir", retval, "while creating root dir");
325 exit(1);
326 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000327 if (geteuid()) {
328 retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
329 if (retval) {
330 com_err("ext2fs_read_inode", retval,
331 "while reading root inode");
332 exit(1);
333 }
334 inode.i_uid = geteuid();
335 retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
336 if (retval) {
337 com_err("ext2fs_write_inode", retval,
338 "while setting root inode ownership");
339 exit(1);
340 }
341 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000342}
343
344static void create_lost_and_found(ext2_filsys fs)
345{
346 errcode_t retval;
347 ino_t ino;
348 const char *name = "lost+found";
349 int i;
350
351 retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
352 if (retval) {
353 com_err("ext2fs_mkdir", retval, "while creating /lost+found");
354 exit(1);
355 }
356
357 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
358 if (retval) {
359 com_err("ext2_lookup", retval, "while looking up /lost+found");
360 exit(1);
361 }
362
363 for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
364 retval = ext2fs_expand_dir(fs, ino);
365 if (retval) {
366 com_err("ext2fs_expand_dir", retval,
367 "while expanding /lost+found");
368 exit(1);
369 }
370 }
371}
372
373static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
374{
375 errcode_t retval;
376
Theodore Ts'of3db3561997-04-26 13:34:30 +0000377 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000378 fs->group_desc[0].bg_free_inodes_count--;
379 fs->super->s_free_inodes_count--;
380 retval = ext2fs_update_bb_inode(fs, bb_list);
381 if (retval) {
382 com_err("ext2fs_update_bb_inode", retval,
383 "while setting bad block inode");
384 exit(1);
385 }
386
387}
388
389static void reserve_inodes(ext2_filsys fs)
390{
391 ino_t i;
392 int group;
393
394 for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INO; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000395 ext2fs_mark_inode_bitmap(fs->inode_map, i);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000396 group = ext2fs_group_of_ino(fs, i);
397 fs->group_desc[group].bg_free_inodes_count--;
398 fs->super->s_free_inodes_count--;
399 }
400 ext2fs_mark_ib_dirty(fs);
401}
402
Theodore Ts'of3db3561997-04-26 13:34:30 +0000403static void zap_bootblock(ext2_filsys fs)
404{
405 char buf[512];
406 int retval;
407
408 memset(buf, 0, 512);
409
410 retval = io_channel_write_blk(fs->io, 0, -512, buf);
411 if (retval)
412 printf("Warning: could not erase block 0: %s\n",
413 error_message(retval));
414}
415
416
Theodore Ts'o3839e651997-04-26 13:21:57 +0000417static void show_stats(ext2_filsys fs)
418{
419 struct ext2_super_block *s = fs->super;
420 blk_t group_block;
421 int i, col_left;
422
423 if (param.s_blocks_count != s->s_blocks_count)
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000424 printf("warning: %d blocks unused.\n\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000425 param.s_blocks_count - s->s_blocks_count);
426
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000427 printf("%u inodes, %u blocks\n", s->s_inodes_count,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000428 s->s_blocks_count);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000429 printf("%u blocks (%2.2f%%) reserved for the super user\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000430 s->s_r_blocks_count,
431 100.0 * s->s_r_blocks_count / s->s_blocks_count);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000432 printf("First data block=%u\n", s->s_first_data_block);
433 printf("Block size=%u (log=%u)\n", fs->blocksize,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000434 s->s_log_block_size);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000435 printf("Fragment size=%u (log=%u)\n", fs->fragsize,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000436 s->s_log_frag_size);
437 printf("%lu block group%s\n", fs->group_desc_count,
438 (fs->group_desc_count > 1) ? "s" : "");
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000439 printf("%u blocks per group, %u fragments per group\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440 s->s_blocks_per_group, s->s_frags_per_group);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000441 printf("%u inodes per group\n", s->s_inodes_per_group);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000442
443 if (fs->group_desc_count == 1) {
444 printf("\n");
445 return;
446 }
447
448 printf("Superblock backups stored on blocks: ");
449 group_block = s->s_first_data_block;
450 col_left = 0;
451 for (i = 1; i < fs->group_desc_count; i++) {
452 group_block += s->s_blocks_per_group;
453 if (!col_left--) {
454 printf("\n\t");
455 col_left = 8;
456 }
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000457 printf("%u", group_block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000458 if (i != fs->group_desc_count - 1)
459 printf(", ");
460 }
461 printf("\n\n");
462}
463
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000464#define PATH_SET "PATH=/sbin"
465
Theodore Ts'o3839e651997-04-26 13:21:57 +0000466static void PRS(int argc, char *argv[])
467{
468 char c;
469 int size;
470 char * tmp;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000471 int inode_ratio = 4096;
472 int reserved_ratio = 5;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000473 errcode_t retval;
474 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000475
476 /* Update our PATH to include /sbin */
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000477 if (oldpath) {
478 char *newpath;
479
480 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
481 strcpy (newpath, PATH_SET);
482 strcat (newpath, ":");
483 strcat (newpath, oldpath);
484 putenv (newpath);
485 } else
486 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000487
488 setbuf(stdout, NULL);
489 setbuf(stderr, NULL);
490 initialize_ext2_error_table();
491 memset(&param, 0, sizeof(struct ext2_super_block));
492
493 fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n",
494 E2FSPROGS_VERSION, E2FSPROGS_DATE,
495 EXT2FS_VERSION, EXT2FS_DATE);
496 if (argc && *argv)
497 program_name = *argv;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000498 while ((c = getopt (argc, argv, "b:cf:g:i:l:m:qtvS")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000499 switch (c) {
500 case 'b':
501 size = strtoul(optarg, &tmp, 0);
502 if (size < 1024 || size > 4096 || *tmp) {
503 com_err(program_name, 0, "bad block size - %s",
504 optarg);
505 exit(1);
506 }
507 param.s_log_block_size =
508 log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
509 break;
510 case 'c':
511 case 't': /* Check for bad blocks */
512 cflag = 1;
513 break;
514 case 'f':
515 size = strtoul(optarg, &tmp, 0);
516 if (size < 1024 || size > 4096 || *tmp) {
517 com_err(program_name, 0, "bad fragment size - %s",
518 optarg);
519 exit(1);
520 }
521 param.s_log_frag_size =
522 log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
523 printf("Warning: fragments not supported. "
524 "Ignoring -f option\n");
525 break;
526 case 'g':
527 param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000528 if (*tmp) {
529 com_err(program_name, 0,
530 "Illegal number for blocks per group");
531 exit(1);
532 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000533 if (param.s_blocks_per_group < 256 ||
534 param.s_blocks_per_group > 8192 || *tmp) {
535 com_err(program_name, 0,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000536 "blocks per group count out of range");
537 exit(1);
538 }
539 if ((param.s_blocks_per_group % 8) != 0) {
540 com_err(program_name, 0,
541 "blocks per group must be multiple of 8");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000542 exit(1);
543 }
544 break;
545 case 'i':
546 inode_ratio = strtoul(optarg, &tmp, 0);
547 if (inode_ratio < 1024 || inode_ratio > 256 * 1024 ||
548 *tmp) {
549 com_err(program_name, 0, "bad inode ratio - %s",
550 optarg);
551 exit(1);
552 }
553 break;
554 case 'l':
Theodore Ts'of3db3561997-04-26 13:34:30 +0000555 bad_blocks_filename = malloc(strlen(optarg)+1);
556 if (!bad_blocks_filename) {
557 com_err(program_name, ENOMEM,
558 "in malloc for bad_blocks_filename");
559 exit(1);
560 }
561 strcpy(bad_blocks_filename, optarg);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000562 break;
563 case 'm':
564 reserved_ratio = strtoul(optarg, &tmp, 0);
565 if (reserved_ratio > 50 || *tmp) {
566 com_err(program_name, 0,
567 "bad reserved blocks percent - %s",
568 optarg);
569 exit(1);
570 }
571 break;
572 case 'v':
573 verbose = 1;
574 break;
575 case 'q':
576 quiet = 1;
577 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000578 case 'S':
579 super_only = 1;
580 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000581 default:
582 usage();
583 }
584 if (optind == argc)
585 usage();
586 device_name = argv[optind];
587 optind++;
588 if (optind < argc) {
589 param.s_blocks_count = strtoul(argv[optind++], &tmp, 0);
590 if (*tmp) {
591 com_err(program_name, 0, "bad blocks count - %s",
592 argv[optind - 1]);
593 exit(1);
594 }
595 }
596 if (optind < argc)
597 usage();
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000598
599 check_mount();
600
Theodore Ts'o3839e651997-04-26 13:21:57 +0000601 param.s_log_frag_size = param.s_log_block_size;
602
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000603 if (!param.s_blocks_count) {
604 retval = ext2fs_get_device_size(device_name,
605 EXT2_BLOCK_SIZE(&param),
606 &param.s_blocks_count);
607 if (retval) {
608 com_err(program_name, 0,
609 "while trying to determine filesystem size");
610 exit(1);
611 }
612 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613
614 /*
615 * Calculate number of inodes based on the inode ratio
616 */
617 param.s_inodes_count =
Theodore Ts'of3db3561997-04-26 13:34:30 +0000618 ((long long) param.s_blocks_count * EXT2_BLOCK_SIZE(&param))
619 / inode_ratio;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000620
621 /*
622 * Calculate number of blocks to reserve
623 */
624 param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
625}
626
627int main (int argc, char *argv[])
628{
629 errcode_t retval = 0;
630 ext2_filsys fs;
631 badblocks_list bb_list = 0;
632
633 PRS(argc, argv);
634
Theodore Ts'o3839e651997-04-26 13:21:57 +0000635 /*
636 * Initialize the superblock....
637 */
638 retval = ext2fs_initialize(device_name, 0, &param,
639 unix_io_manager, &fs);
640 if (retval) {
641 com_err(device_name, retval, "while setting up superblock");
642 exit(1);
643 }
644
645 if (!quiet)
646 show_stats(fs);
647
648 if (bad_blocks_filename)
649 read_bb_file(fs, &bb_list, bad_blocks_filename);
650 if (cflag)
651 test_disk(fs, &bb_list);
652
653 handle_bad_blocks(fs, bb_list);
654 alloc_tables(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000655 if (super_only) {
656 fs->super->s_state |= EXT2_ERROR_FS;
657 fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
658 } else {
659 create_root_dir(fs);
660 create_lost_and_found(fs);
661 reserve_inodes(fs);
662 create_bad_block_inode(fs, bb_list);
663 zap_bootblock(fs);
664 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000665
666 if (!quiet)
667 printf("Writing superblocks and "
668 "filesystem accounting information: ");
669 ext2fs_close(fs);
670 if (!quiet)
671 printf("done\n");
672 return 0;
673}