tune2fs.c revision 7a0516a385d87a508843b21a1932b689697d9ffa
1/* 2 * tune2fs.c - Change the file system parameters on an ext2 file system 3 * 4 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr> 5 * Laboratoire MASI, Institut Blaise Pascal 6 * Universite Pierre et Marie Curie (Paris VI) 7 * 8 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. 9 * 10 * %Begin-Header% 11 * This file may be redistributed under the terms of the GNU Public 12 * License. 13 * %End-Header% 14 */ 15 16/* 17 * History: 18 * 93/06/01 - Creation 19 * 93/10/31 - Added the -c option to change the maximal mount counts 20 * 93/12/14 - Added -l flag to list contents of superblock 21 * M.J.E. Mol (marcel@duteca.et.tudelft.nl) 22 * F.W. ten Wolde (franky@duteca.et.tudelft.nl) 23 * 93/12/29 - Added the -e option to change errors behavior 24 * 94/02/27 - Ported to use the ext2fs library 25 * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de) 26 */ 27 28#define _XOPEN_SOURCE 600 /* for inclusion of strptime() */ 29#define _BSD_SOURCE /* for inclusion of strcasecmp() */ 30#include <fcntl.h> 31#include <grp.h> 32#ifdef HAVE_GETOPT_H 33#include <getopt.h> 34#else 35extern char *optarg; 36extern int optind; 37#endif 38#include <pwd.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <time.h> 43#include <unistd.h> 44#include <sys/types.h> 45#include <libgen.h> 46#include <limits.h> 47 48#include "ext2fs/ext2_fs.h" 49#include "ext2fs/ext2fs.h" 50#include "et/com_err.h" 51#include "uuid/uuid.h" 52#include "e2p/e2p.h" 53#include "jfs_user.h" 54#include "util.h" 55#include "blkid/blkid.h" 56 57#include "../version.h" 58#include "nls-enable.h" 59 60const char * program_name = "tune2fs"; 61char * device_name; 62char * new_label, *new_last_mounted, *new_UUID; 63char * io_options; 64static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; 65static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; 66static int I_flag; 67static time_t last_check_time; 68static int print_label; 69static int max_mount_count, mount_count, mount_flags; 70static unsigned long interval, reserved_blocks; 71static double reserved_ratio; 72static unsigned long resgid, resuid; 73static unsigned short errors; 74static int open_flag; 75static char *features_cmd; 76static char *mntopts_cmd; 77static int stride, stripe_width; 78static int stride_set, stripe_width_set; 79static char *extended_cmd; 80static unsigned long new_inode_size; 81 82int journal_size, journal_flags; 83char *journal_device; 84 85static struct list_head blk_move_list; 86 87struct blk_move { 88 struct list_head list; 89 blk_t old_loc; 90 blk_t new_loc; 91}; 92 93 94static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); 95 96void do_findfs(int argc, char **argv); 97 98static void usage(void) 99{ 100 fprintf(stderr, 101 _("Usage: %s [-c max_mounts_count] [-e errors_behavior] " 102 "[-g group]\n" 103 "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n" 104 "\t[-m reserved_blocks_percent] " 105 "[-o [^]mount_options[,...]] \n" 106 "\t[-r reserved_blocks_count] [-u user] [-C mount_count] " 107 "[-L volume_label]\n" 108 "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n" 109 "\t[-E extended-option[,...]] [-T last_check_time] " 110 "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name); 111 exit (1); 112} 113 114static __u32 ok_features[3] = { 115 /* Compat */ 116 EXT3_FEATURE_COMPAT_HAS_JOURNAL | 117 EXT2_FEATURE_COMPAT_DIR_INDEX, 118 /* Incompat */ 119 EXT2_FEATURE_INCOMPAT_FILETYPE | 120 EXT3_FEATURE_INCOMPAT_EXTENTS | 121 EXT4_FEATURE_INCOMPAT_FLEX_BG, 122 /* R/O compat */ 123 EXT2_FEATURE_RO_COMPAT_LARGE_FILE | 124 EXT4_FEATURE_RO_COMPAT_HUGE_FILE| 125 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| 126 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| 127 EXT4_FEATURE_RO_COMPAT_GDT_CSUM | 128 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 129}; 130 131static __u32 clear_ok_features[3] = { 132 /* Compat */ 133 EXT3_FEATURE_COMPAT_HAS_JOURNAL | 134 EXT2_FEATURE_COMPAT_RESIZE_INODE | 135 EXT2_FEATURE_COMPAT_DIR_INDEX, 136 /* Incompat */ 137 EXT2_FEATURE_INCOMPAT_FILETYPE | 138 EXT4_FEATURE_INCOMPAT_FLEX_BG, 139 /* R/O compat */ 140 EXT2_FEATURE_RO_COMPAT_LARGE_FILE | 141 EXT4_FEATURE_RO_COMPAT_HUGE_FILE| 142 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| 143 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| 144 EXT4_FEATURE_RO_COMPAT_GDT_CSUM 145}; 146 147/* 148 * Remove an external journal from the filesystem 149 */ 150static void remove_journal_device(ext2_filsys fs) 151{ 152 char *journal_path; 153 ext2_filsys jfs; 154 char buf[1024]; 155 journal_superblock_t *jsb; 156 int i, nr_users; 157 errcode_t retval; 158 int commit_remove_journal = 0; 159 io_manager io_ptr; 160 161 if (f_flag) 162 commit_remove_journal = 1; /* force removal even if error */ 163 164 uuid_unparse(fs->super->s_journal_uuid, buf); 165 journal_path = blkid_get_devname(NULL, "UUID", buf); 166 167 if (!journal_path) { 168 journal_path = 169 ext2fs_find_block_device(fs->super->s_journal_dev); 170 if (!journal_path) 171 return; 172 } 173 174#ifdef CONFIG_TESTIO_DEBUG 175 io_ptr = test_io_manager; 176 test_io_backing_manager = unix_io_manager; 177#else 178 io_ptr = unix_io_manager; 179#endif 180 retval = ext2fs_open(journal_path, EXT2_FLAG_RW| 181 EXT2_FLAG_JOURNAL_DEV_OK, 0, 182 fs->blocksize, io_ptr, &jfs); 183 if (retval) { 184 com_err(program_name, retval, 185 _("while trying to open external journal")); 186 goto no_valid_journal; 187 } 188 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { 189 fprintf(stderr, _("%s is not a journal device.\n"), 190 journal_path); 191 goto no_valid_journal; 192 } 193 194 /* Get the journal superblock */ 195 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { 196 com_err(program_name, retval, 197 _("while reading journal superblock")); 198 goto no_valid_journal; 199 } 200 201 jsb = (journal_superblock_t *) buf; 202 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || 203 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { 204 fputs(_("Journal superblock not found!\n"), stderr); 205 goto no_valid_journal; 206 } 207 208 /* Find the filesystem UUID */ 209 nr_users = ntohl(jsb->s_nr_users); 210 for (i=0; i < nr_users; i++) { 211 if (memcmp(fs->super->s_uuid, 212 &jsb->s_users[i*16], 16) == 0) 213 break; 214 } 215 if (i >= nr_users) { 216 fputs(_("Filesystem's UUID not found on journal device.\n"), 217 stderr); 218 commit_remove_journal = 1; 219 goto no_valid_journal; 220 } 221 nr_users--; 222 for (i=0; i < nr_users; i++) 223 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); 224 jsb->s_nr_users = htonl(nr_users); 225 226 /* Write back the journal superblock */ 227 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { 228 com_err(program_name, retval, 229 "while writing journal superblock."); 230 goto no_valid_journal; 231 } 232 233 commit_remove_journal = 1; 234 235no_valid_journal: 236 if (commit_remove_journal == 0) { 237 fputs(_("Journal NOT removed\n"), stderr); 238 exit(1); 239 } 240 fs->super->s_journal_dev = 0; 241 uuid_clear(fs->super->s_journal_uuid); 242 ext2fs_mark_super_dirty(fs); 243 fputs(_("Journal removed\n"), stdout); 244 free(journal_path); 245} 246 247/* Helper function for remove_journal_inode */ 248static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, 249 int blockcnt EXT2FS_ATTR((unused)), 250 void *private EXT2FS_ATTR((unused))) 251{ 252 blk_t block; 253 int group; 254 255 block = *blocknr; 256 ext2fs_unmark_block_bitmap(fs->block_map,block); 257 group = ext2fs_group_of_blk(fs, block); 258 fs->group_desc[group].bg_free_blocks_count++; 259 ext2fs_group_desc_csum_set(fs, group); 260 fs->super->s_free_blocks_count++; 261 return 0; 262} 263 264/* 265 * Remove the journal inode from the filesystem 266 */ 267static void remove_journal_inode(ext2_filsys fs) 268{ 269 struct ext2_inode inode; 270 errcode_t retval; 271 ino_t ino = fs->super->s_journal_inum; 272 273 retval = ext2fs_read_inode(fs, ino, &inode); 274 if (retval) { 275 com_err(program_name, retval, 276 _("while reading journal inode")); 277 exit(1); 278 } 279 if (ino == EXT2_JOURNAL_INO) { 280 retval = ext2fs_read_bitmaps(fs); 281 if (retval) { 282 com_err(program_name, retval, 283 _("while reading bitmaps")); 284 exit(1); 285 } 286 retval = ext2fs_block_iterate(fs, ino, 287 BLOCK_FLAG_READ_ONLY, NULL, 288 release_blocks_proc, NULL); 289 if (retval) { 290 com_err(program_name, retval, 291 _("while clearing journal inode")); 292 exit(1); 293 } 294 memset(&inode, 0, sizeof(inode)); 295 ext2fs_mark_bb_dirty(fs); 296 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 297 } else 298 inode.i_flags &= ~EXT2_IMMUTABLE_FL; 299 retval = ext2fs_write_inode(fs, ino, &inode); 300 if (retval) { 301 com_err(program_name, retval, 302 _("while writing journal inode")); 303 exit(1); 304 } 305 fs->super->s_journal_inum = 0; 306 ext2fs_mark_super_dirty(fs); 307} 308 309/* 310 * Update the default mount options 311 */ 312static void update_mntopts(ext2_filsys fs, char *mntopts) 313{ 314 struct ext2_super_block *sb= fs->super; 315 316 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) { 317 fprintf(stderr, _("Invalid mount option set: %s\n"), 318 mntopts); 319 exit(1); 320 } 321 ext2fs_mark_super_dirty(fs); 322} 323 324/* 325 * Update the feature set as provided by the user. 326 */ 327static void update_feature_set(ext2_filsys fs, char *features) 328{ 329 struct ext2_super_block *sb= fs->super; 330 __u32 old_features[3]; 331 int type_err; 332 unsigned int mask_err; 333 334#define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \ 335 ((&sb->s_feature_compat)[(type)] & (mask))) 336#define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \ 337 !((&sb->s_feature_compat)[(type)] & (mask))) 338#define FEATURE_CHANGED(type, mask) ((mask) & \ 339 (old_features[(type)] ^ (&sb->s_feature_compat)[(type)])) 340 341 old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat; 342 old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat; 343 old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat; 344 345 if (e2p_edit_feature2(features, &sb->s_feature_compat, 346 ok_features, clear_ok_features, 347 &type_err, &mask_err)) { 348 if (!mask_err) 349 fprintf(stderr, 350 _("Invalid filesystem option set: %s\n"), 351 features); 352 else if (type_err & E2P_FEATURE_NEGATE_FLAG) 353 fprintf(stderr, _("Clearing filesystem feature '%s' " 354 "not supported.\n"), 355 e2p_feature2string(type_err & 356 E2P_FEATURE_TYPE_MASK, 357 mask_err)); 358 else 359 fprintf(stderr, _("Setting filesystem feature '%s' " 360 "not supported.\n"), 361 e2p_feature2string(type_err, mask_err)); 362 exit(1); 363 } 364 365 if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 366 if ((mount_flags & EXT2_MF_MOUNTED) && 367 !(mount_flags & EXT2_MF_READONLY)) { 368 fputs(_("The has_journal feature may only be " 369 "cleared when the filesystem is\n" 370 "unmounted or mounted " 371 "read-only.\n"), stderr); 372 exit(1); 373 } 374 if (sb->s_feature_incompat & 375 EXT3_FEATURE_INCOMPAT_RECOVER) { 376 fputs(_("The needs_recovery flag is set. " 377 "Please run e2fsck before clearing\n" 378 "the has_journal flag.\n"), stderr); 379 exit(1); 380 } 381 if (sb->s_journal_inum) { 382 remove_journal_inode(fs); 383 } 384 if (sb->s_journal_dev) { 385 remove_journal_device(fs); 386 } 387 } 388 389 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 390 /* 391 * If adding a journal flag, let the create journal 392 * code below handle setting the flag and creating the 393 * journal. We supply a default size if necessary. 394 */ 395 if (!journal_size) 396 journal_size = -1; 397 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; 398 } 399 400 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) { 401 if (!sb->s_def_hash_version) 402 sb->s_def_hash_version = EXT2_HASH_TEA; 403 if (uuid_is_null((unsigned char *) sb->s_hash_seed)) 404 uuid_generate((unsigned char *) sb->s_hash_seed); 405 } 406 407 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { 408 if (ext2fs_check_desc(fs)) { 409 fputs(_("Clearing the flex_bg flag would " 410 "cause the the filesystem to be\n" 411 "inconsistent.\n"), stderr); 412 exit(1); 413 } 414 } 415 416 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 417 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 418 if ((mount_flags & EXT2_MF_MOUNTED) && 419 !(mount_flags & EXT2_MF_READONLY)) { 420 fputs(_("The huge_file feature may only be " 421 "cleared when the filesystem is\n" 422 "unmounted or mounted " 423 "read-only.\n"), stderr); 424 exit(1); 425 } 426 } 427 428 if (sb->s_rev_level == EXT2_GOOD_OLD_REV && 429 (sb->s_feature_compat || sb->s_feature_ro_compat || 430 sb->s_feature_incompat)) 431 ext2fs_update_dynamic_rev(fs); 432 433 if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, 434 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || 435 FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, 436 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) || 437 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 438 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || 439 FEATURE_CHANGED(E2P_FEATURE_INCOMPAT, 440 EXT2_FEATURE_INCOMPAT_FILETYPE) || 441 FEATURE_CHANGED(E2P_FEATURE_COMPAT, 442 EXT2_FEATURE_COMPAT_RESIZE_INODE) || 443 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 444 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { 445 sb->s_state &= ~EXT2_VALID_FS; 446 printf("\n%s\n", _(please_fsck)); 447 if (mount_flags & EXT2_MF_READONLY) 448 printf(_("(and reboot afterwards!)\n")); 449 } 450 451 if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) || 452 (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) || 453 (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat)) 454 ext2fs_mark_super_dirty(fs); 455} 456 457/* 458 * Add a journal to the filesystem. 459 */ 460static void add_journal(ext2_filsys fs) 461{ 462 unsigned long journal_blocks; 463 errcode_t retval; 464 ext2_filsys jfs; 465 io_manager io_ptr; 466 467 if (fs->super->s_feature_compat & 468 EXT3_FEATURE_COMPAT_HAS_JOURNAL) { 469 fputs(_("The filesystem already has a journal.\n"), stderr); 470 goto err; 471 } 472 if (journal_device) { 473 check_plausibility(journal_device); 474 check_mount(journal_device, 0, _("journal")); 475#ifdef CONFIG_TESTIO_DEBUG 476 io_ptr = test_io_manager; 477 test_io_backing_manager = unix_io_manager; 478#else 479 io_ptr = unix_io_manager; 480#endif 481 retval = ext2fs_open(journal_device, EXT2_FLAG_RW| 482 EXT2_FLAG_JOURNAL_DEV_OK, 0, 483 fs->blocksize, io_ptr, &jfs); 484 if (retval) { 485 com_err(program_name, retval, 486 _("\n\twhile trying to open journal on %s\n"), 487 journal_device); 488 goto err; 489 } 490 printf(_("Creating journal on device %s: "), 491 journal_device); 492 fflush(stdout); 493 494 retval = ext2fs_add_journal_device(fs, jfs); 495 ext2fs_close(jfs); 496 if (retval) { 497 com_err (program_name, retval, 498 _("while adding filesystem to journal on %s"), 499 journal_device); 500 goto err; 501 } 502 fputs(_("done\n"), stdout); 503 } else if (journal_size) { 504 fputs(_("Creating journal inode: "), stdout); 505 fflush(stdout); 506 journal_blocks = figure_journal_size(journal_size, fs); 507 508 retval = ext2fs_add_journal_inode(fs, journal_blocks, 509 journal_flags); 510 if (retval) { 511 fprintf(stderr, "\n"); 512 com_err(program_name, retval, 513 _("\n\twhile trying to create journal file")); 514 exit(1); 515 } else 516 fputs(_("done\n"), stdout); 517 /* 518 * If the filesystem wasn't mounted, we need to force 519 * the block group descriptors out. 520 */ 521 if ((mount_flags & EXT2_MF_MOUNTED) == 0) 522 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 523 } 524 print_check_message(fs); 525 return; 526 527err: 528 if (journal_device) 529 free(journal_device); 530 exit(1); 531} 532 533 534static void parse_e2label_options(int argc, char ** argv) 535{ 536 if ((argc < 2) || (argc > 3)) { 537 fputs(_("Usage: e2label device [newlabel]\n"), stderr); 538 exit(1); 539 } 540 io_options = strchr(argv[1], '?'); 541 if (io_options) 542 *io_options++ = 0; 543 device_name = blkid_get_devname(NULL, argv[1], NULL); 544 if (!device_name) { 545 com_err("e2label", 0, _("Unable to resolve '%s'"), 546 argv[1]); 547 exit(1); 548 } 549 open_flag = EXT2_FLAG_JOURNAL_DEV_OK; 550 if (argc == 3) { 551 open_flag |= EXT2_FLAG_RW; 552 L_flag = 1; 553 new_label = argv[2]; 554 } else 555 print_label++; 556} 557 558static time_t parse_time(char *str) 559{ 560 struct tm ts; 561 562 if (strcmp(str, "now") == 0) { 563 return (time(0)); 564 } 565 memset(&ts, 0, sizeof(ts)); 566#ifdef HAVE_STRPTIME 567 strptime(str, "%Y%m%d%H%M%S", &ts); 568#else 569 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, 570 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); 571 ts.tm_year -= 1900; 572 ts.tm_mon -= 1; 573 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || 574 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || 575 ts.tm_min > 59 || ts.tm_sec > 61) 576 ts.tm_mday = 0; 577#endif 578 if (ts.tm_mday == 0) { 579 com_err(program_name, 0, 580 _("Couldn't parse date/time specifier: %s"), 581 str); 582 usage(); 583 } 584 ts.tm_isdst = -1; 585 return (mktime(&ts)); 586} 587 588static void parse_tune2fs_options(int argc, char **argv) 589{ 590 int c; 591 char * tmp; 592 struct group * gr; 593 struct passwd * pw; 594 595 open_flag = 0; 596 597 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); 598 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:")) != EOF) 599 switch (c) 600 { 601 case 'c': 602 max_mount_count = strtol (optarg, &tmp, 0); 603 if (*tmp || max_mount_count > 16000) { 604 com_err (program_name, 0, 605 _("bad mounts count - %s"), 606 optarg); 607 usage(); 608 } 609 if (max_mount_count == 0) 610 max_mount_count = -1; 611 c_flag = 1; 612 open_flag = EXT2_FLAG_RW; 613 break; 614 case 'C': 615 mount_count = strtoul (optarg, &tmp, 0); 616 if (*tmp || mount_count > 16000) { 617 com_err (program_name, 0, 618 _("bad mounts count - %s"), 619 optarg); 620 usage(); 621 } 622 C_flag = 1; 623 open_flag = EXT2_FLAG_RW; 624 break; 625 case 'e': 626 if (strcmp (optarg, "continue") == 0) 627 errors = EXT2_ERRORS_CONTINUE; 628 else if (strcmp (optarg, "remount-ro") == 0) 629 errors = EXT2_ERRORS_RO; 630 else if (strcmp (optarg, "panic") == 0) 631 errors = EXT2_ERRORS_PANIC; 632 else { 633 com_err (program_name, 0, 634 _("bad error behavior - %s"), 635 optarg); 636 usage(); 637 } 638 e_flag = 1; 639 open_flag = EXT2_FLAG_RW; 640 break; 641 case 'E': 642 extended_cmd = optarg; 643 open_flag |= EXT2_FLAG_RW; 644 break; 645 case 'f': /* Force */ 646 f_flag = 1; 647 break; 648 case 'g': 649 resgid = strtoul (optarg, &tmp, 0); 650 if (*tmp) { 651 gr = getgrnam (optarg); 652 if (gr == NULL) 653 tmp = optarg; 654 else { 655 resgid = gr->gr_gid; 656 *tmp =0; 657 } 658 } 659 if (*tmp) { 660 com_err (program_name, 0, 661 _("bad gid/group name - %s"), 662 optarg); 663 usage(); 664 } 665 g_flag = 1; 666 open_flag = EXT2_FLAG_RW; 667 break; 668 case 'i': 669 interval = strtoul (optarg, &tmp, 0); 670 switch (*tmp) { 671 case 's': 672 tmp++; 673 break; 674 case '\0': 675 case 'd': 676 case 'D': /* days */ 677 interval *= 86400; 678 if (*tmp != '\0') 679 tmp++; 680 break; 681 case 'm': 682 case 'M': /* months! */ 683 interval *= 86400 * 30; 684 tmp++; 685 break; 686 case 'w': 687 case 'W': /* weeks */ 688 interval *= 86400 * 7; 689 tmp++; 690 break; 691 } 692 if (*tmp) { 693 com_err (program_name, 0, 694 _("bad interval - %s"), optarg); 695 usage(); 696 } 697 i_flag = 1; 698 open_flag = EXT2_FLAG_RW; 699 break; 700 case 'j': 701 if (!journal_size) 702 journal_size = -1; 703 open_flag = EXT2_FLAG_RW; 704 break; 705 case 'J': 706 parse_journal_opts(optarg); 707 open_flag = EXT2_FLAG_RW; 708 break; 709 case 'l': 710 l_flag = 1; 711 break; 712 case 'L': 713 new_label = optarg; 714 L_flag = 1; 715 open_flag |= EXT2_FLAG_RW | 716 EXT2_FLAG_JOURNAL_DEV_OK; 717 break; 718 case 'm': 719 reserved_ratio = strtod(optarg, &tmp); 720 if (*tmp || reserved_ratio > 50) { 721 com_err (program_name, 0, 722 _("bad reserved block ratio - %s"), 723 optarg); 724 usage(); 725 } 726 m_flag = 1; 727 open_flag = EXT2_FLAG_RW; 728 break; 729 case 'M': 730 new_last_mounted = optarg; 731 M_flag = 1; 732 open_flag = EXT2_FLAG_RW; 733 break; 734 case 'o': 735 if (mntopts_cmd) { 736 com_err (program_name, 0, 737 _("-o may only be specified once")); 738 usage(); 739 } 740 mntopts_cmd = optarg; 741 open_flag = EXT2_FLAG_RW; 742 break; 743 744 case 'O': 745 if (features_cmd) { 746 com_err (program_name, 0, 747 _("-O may only be specified once")); 748 usage(); 749 } 750 features_cmd = optarg; 751 open_flag = EXT2_FLAG_RW; 752 break; 753 case 'r': 754 reserved_blocks = strtoul (optarg, &tmp, 0); 755 if (*tmp) { 756 com_err (program_name, 0, 757 _("bad reserved blocks count - %s"), 758 optarg); 759 usage(); 760 } 761 r_flag = 1; 762 open_flag = EXT2_FLAG_RW; 763 break; 764 case 's': /* Deprecated */ 765 s_flag = atoi(optarg); 766 open_flag = EXT2_FLAG_RW; 767 break; 768 case 'T': 769 T_flag = 1; 770 last_check_time = parse_time(optarg); 771 open_flag = EXT2_FLAG_RW; 772 break; 773 case 'u': 774 resuid = strtoul (optarg, &tmp, 0); 775 if (*tmp) { 776 pw = getpwnam (optarg); 777 if (pw == NULL) 778 tmp = optarg; 779 else { 780 resuid = pw->pw_uid; 781 *tmp = 0; 782 } 783 } 784 if (*tmp) { 785 com_err (program_name, 0, 786 _("bad uid/user name - %s"), 787 optarg); 788 usage(); 789 } 790 u_flag = 1; 791 open_flag = EXT2_FLAG_RW; 792 break; 793 case 'U': 794 new_UUID = optarg; 795 U_flag = 1; 796 open_flag = EXT2_FLAG_RW | 797 EXT2_FLAG_JOURNAL_DEV_OK; 798 break; 799 case 'I': 800 new_inode_size = strtoul (optarg, &tmp, 0); 801 if (*tmp) { 802 com_err (program_name, 0, 803 _("bad inode size - %s"), 804 optarg); 805 usage(); 806 } 807 if (!((new_inode_size & 808 (new_inode_size - 1)) == 0)) { 809 com_err (program_name, 0, 810 _("Inode size must be a " 811 "power of two- %s"), 812 optarg); 813 usage(); 814 } 815 open_flag = EXT2_FLAG_RW; 816 I_flag = 1; 817 break; 818 default: 819 usage(); 820 } 821 if (optind < argc - 1 || optind == argc) 822 usage(); 823 if (!open_flag && !l_flag) 824 usage(); 825 io_options = strchr(argv[optind], '?'); 826 if (io_options) 827 *io_options++ = 0; 828 device_name = blkid_get_devname(NULL, argv[optind], NULL); 829 if (!device_name) { 830 com_err("tune2fs", 0, _("Unable to resolve '%s'"), 831 argv[optind]); 832 exit(1); 833 } 834} 835 836void do_findfs(int argc, char **argv) 837{ 838 char *dev; 839 840 if ((argc != 2) || 841 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { 842 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n"); 843 exit(2); 844 } 845 dev = blkid_get_devname(NULL, argv[1], NULL); 846 if (!dev) { 847 com_err("findfs", 0, _("Unable to resolve '%s'"), 848 argv[1]); 849 exit(1); 850 } 851 puts(dev); 852 exit(0); 853} 854 855static void parse_extended_opts(ext2_filsys fs, const char *opts) 856{ 857 char *buf, *token, *next, *p, *arg; 858 int len; 859 int r_usage = 0; 860 861 len = strlen(opts); 862 buf = malloc(len+1); 863 if (!buf) { 864 fprintf(stderr, 865 _("Couldn't allocate memory to parse options!\n")); 866 exit(1); 867 } 868 strcpy(buf, opts); 869 for (token = buf; token && *token; token = next) { 870 p = strchr(token, ','); 871 next = 0; 872 if (p) { 873 *p = 0; 874 next = p+1; 875 } 876 arg = strchr(token, '='); 877 if (arg) { 878 *arg = 0; 879 arg++; 880 } 881 if (!strcmp(token, "test_fs")) { 882 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; 883 printf("Setting test filesystem flag\n"); 884 ext2fs_mark_super_dirty(fs); 885 } else if (!strcmp(token, "^test_fs")) { 886 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS; 887 printf("Clearing test filesystem flag\n"); 888 ext2fs_mark_super_dirty(fs); 889 } else if (strcmp(token, "stride") == 0) { 890 if (!arg) { 891 r_usage++; 892 continue; 893 } 894 stride = strtoul(arg, &p, 0); 895 if (*p || (stride == 0)) { 896 fprintf(stderr, 897 _("Invalid RAID stride: %s\n"), 898 arg); 899 r_usage++; 900 continue; 901 } 902 stride_set = 1; 903 } else if (strcmp(token, "stripe-width") == 0 || 904 strcmp(token, "stripe_width") == 0) { 905 if (!arg) { 906 r_usage++; 907 continue; 908 } 909 stripe_width = strtoul(arg, &p, 0); 910 if (*p || (stripe_width == 0)) { 911 fprintf(stderr, 912 _("Invalid RAID stripe-width: %s\n"), 913 arg); 914 r_usage++; 915 continue; 916 } 917 stripe_width_set = 1; 918 } else 919 r_usage++; 920 } 921 if (r_usage) { 922 fprintf(stderr, _("\nBad options specified.\n\n" 923 "Extended options are separated by commas, " 924 "and may take an argument which\n" 925 "\tis set off by an equals ('=') sign.\n\n" 926 "Valid extended options are:\n" 927 "\tstride=<RAID per-disk chunk size in blocks>\n" 928 "\tstripe-width=<RAID stride*data disks in blocks>\n" 929 "\ttest_fs\n" 930 "\t^test_fs\n")); 931 free(buf); 932 exit(1); 933 } 934 free(buf); 935} 936 937static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp, 938 ext2fs_block_bitmap bmap) 939{ 940 dgrp_t i; 941 blk_t j, needed_blocks = 0; 942 blk_t start_blk, end_blk; 943 944 for (i = 0; i < fs->group_desc_count; i++) { 945 946 start_blk = fs->group_desc[i].bg_inode_table + 947 fs->inode_blocks_per_group; 948 949 end_blk = fs->group_desc[i].bg_inode_table + 950 new_ino_blks_per_grp; 951 952 for (j = start_blk; j < end_blk; j++) { 953 954 if (ext2fs_test_block_bitmap(fs->block_map, j)) { 955 /* FIXME!! 956 * What happens if the block is marked 957 * as a bad block 958 */ 959 ext2fs_mark_block_bitmap(bmap, j); 960 needed_blocks++; 961 } else { 962 /* 963 * We are going to use this block for 964 * inode table. So mark them used. 965 */ 966 ext2fs_mark_block_bitmap(fs->block_map, j); 967 } 968 } 969 } 970 971 if (needed_blocks > fs->super->s_free_blocks_count ) { 972 return ENOSPC; 973 } 974 975 return 0; 976} 977 978static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap) 979{ 980 char *buf; 981 errcode_t retval; 982 blk_t blk, new_blk; 983 struct blk_move *bmv; 984 985 986 retval = ext2fs_get_mem(fs->blocksize, &buf); 987 if (retval) 988 return retval; 989 990 for (blk = fs->super->s_first_data_block; 991 blk < fs->super->s_blocks_count; blk++) { 992 993 if (!ext2fs_test_block_bitmap(bmap, blk)) 994 continue; 995 996 retval = ext2fs_new_block(fs, blk, NULL, &new_blk); 997 if (retval) 998 goto err_out; 999 1000 /* Mark this block as allocated */ 1001 ext2fs_mark_block_bitmap(fs->block_map, new_blk); 1002 1003 /* Add it to block move list */ 1004 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv); 1005 if (retval) 1006 goto err_out; 1007 1008 bmv->old_loc = blk; 1009 bmv->new_loc = new_blk; 1010 1011 list_add(&(bmv->list), &blk_move_list); 1012 1013 retval = io_channel_read_blk(fs->io, blk, 1, buf); 1014 if (retval) 1015 goto err_out; 1016 1017 retval = io_channel_write_blk(fs->io, new_blk, 1, buf); 1018 if (retval) 1019 goto err_out; 1020 } 1021 1022err_out: 1023 ext2fs_free_mem(&buf); 1024 return retval; 1025} 1026 1027static blk_t transalate_block(blk_t blk) 1028{ 1029 struct list_head *entry; 1030 struct blk_move *bmv; 1031 1032 list_for_each(entry, &blk_move_list) { 1033 1034 bmv = list_entry(entry, struct blk_move, list); 1035 if (bmv->old_loc == blk) 1036 return bmv->new_loc; 1037 } 1038 1039 return 0; 1040} 1041 1042static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)), 1043 blk_t *block_nr, 1044 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1045 blk_t ref_block EXT2FS_ATTR((unused)), 1046 int ref_offset EXT2FS_ATTR((unused)), 1047 void *priv_data EXT2FS_ATTR((unused))) 1048{ 1049 int ret = 0; 1050 blk_t new_blk; 1051 1052 1053 new_blk = transalate_block(*block_nr); 1054 if (new_blk) { 1055 *block_nr = new_blk; 1056 /* 1057 * This will force the ext2fs_write_inode in the iterator 1058 */ 1059 ret |= BLOCK_CHANGED; 1060 } 1061 1062 return ret; 1063} 1064 1065static int inode_scan_and_fix(ext2_filsys fs) 1066{ 1067 errcode_t retval = 0; 1068 ext2_ino_t ino; 1069 blk_t blk; 1070 char *block_buf = 0; 1071 struct ext2_inode inode; 1072 ext2_inode_scan scan = NULL; 1073 1074 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf); 1075 if (retval) 1076 return retval; 1077 1078 retval = ext2fs_open_inode_scan(fs, 0, &scan); 1079 if (retval) 1080 goto err_out; 1081 1082 while (1) { 1083 1084 retval = ext2fs_get_next_inode(scan, &ino, &inode); 1085 if (retval) 1086 goto err_out; 1087 1088 if (!ino) 1089 break; 1090 1091 if (inode.i_links_count == 0) 1092 continue; /* inode not in use */ 1093 1094 /* FIXME!! 1095 * If we end up modifying the journal inode 1096 * the sb->s_jnl_blocks will differ. But a 1097 * subsequent e2fsck fixes that. 1098 * Do we need to fix this ?? 1099 */ 1100 1101 if (inode.i_file_acl) { 1102 1103 blk = transalate_block(inode.i_file_acl); 1104 if (!blk) 1105 continue; 1106 1107 inode.i_file_acl = blk; 1108 1109 /* 1110 * Write the inode to disk so that inode table 1111 * resizing can work 1112 */ 1113 retval = ext2fs_write_inode(fs, ino, &inode); 1114 if (retval) 1115 goto err_out; 1116 } 1117 1118 if (!ext2fs_inode_has_valid_blocks(&inode)) 1119 continue; 1120 1121 retval = ext2fs_block_iterate2(fs, ino, 0, 1122 block_buf, process_block, 1123 0); 1124 if (retval) 1125 goto err_out; 1126 1127 } 1128 1129err_out: 1130 ext2fs_free_mem(&block_buf); 1131 1132 return retval; 1133 1134} 1135 1136static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size) 1137{ 1138 dgrp_t i; 1139 blk_t blk; 1140 errcode_t retval; 1141 int new_ino_blks_per_grp; 1142 unsigned int j; 1143 char *old_itable = NULL, *new_itable = NULL; 1144 char *tmp_old_itable = NULL, *tmp_new_itable = NULL; 1145 unsigned long old_ino_size; 1146 int old_itable_size, new_itable_size; 1147 1148 old_itable_size = fs->inode_blocks_per_group * fs->blocksize; 1149 old_ino_size = EXT2_INODE_SIZE(fs->super); 1150 1151 new_ino_blks_per_grp = ext2fs_div_ceil( 1152 EXT2_INODES_PER_GROUP(fs->super) * 1153 new_ino_size, 1154 fs->blocksize); 1155 1156 new_itable_size = new_ino_blks_per_grp * fs->blocksize; 1157 1158 retval = ext2fs_get_mem(old_itable_size, &old_itable); 1159 if (retval) 1160 return retval; 1161 1162 retval = ext2fs_get_mem(new_itable_size, &new_itable); 1163 if (retval) 1164 goto err_out; 1165 1166 tmp_old_itable = old_itable; 1167 tmp_new_itable = new_itable; 1168 1169 for (i = 0; i < fs->group_desc_count; i++) { 1170 1171 blk = fs->group_desc[i].bg_inode_table; 1172 retval = io_channel_read_blk(fs->io, blk, 1173 fs->inode_blocks_per_group, old_itable); 1174 if (retval) 1175 goto err_out; 1176 1177 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) { 1178 1179 memcpy(new_itable, old_itable, old_ino_size); 1180 1181 memset(new_itable+old_ino_size, 0, 1182 new_ino_size - old_ino_size); 1183 1184 new_itable += new_ino_size; 1185 old_itable += old_ino_size; 1186 } 1187 1188 /* reset the pointer */ 1189 old_itable = tmp_old_itable; 1190 new_itable = tmp_new_itable; 1191 1192 retval = io_channel_write_blk(fs->io, blk, 1193 new_ino_blks_per_grp, new_itable); 1194 if (retval) 1195 goto err_out; 1196 } 1197 1198 /* Update the meta data */ 1199 fs->inode_blocks_per_group = new_ino_blks_per_grp; 1200 fs->super->s_inode_size = new_ino_size; 1201 1202err_out: 1203 if (old_itable) 1204 ext2fs_free_mem(&old_itable); 1205 1206 if (new_itable) 1207 ext2fs_free_mem(&new_itable); 1208 1209 return retval; 1210} 1211 1212static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs) 1213{ 1214 blk_t blk; 1215 ext2_ino_t ino; 1216 unsigned int group = 0; 1217 unsigned int count = 0; 1218 int total_free = 0; 1219 int group_free = 0; 1220 1221 /* 1222 * First calculate the block statistics 1223 */ 1224 for (blk = fs->super->s_first_data_block; 1225 blk < fs->super->s_blocks_count; blk++) { 1226 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) { 1227 group_free++; 1228 total_free++; 1229 } 1230 count++; 1231 if ((count == fs->super->s_blocks_per_group) || 1232 (blk == fs->super->s_blocks_count-1)) { 1233 fs->group_desc[group++].bg_free_blocks_count = 1234 group_free; 1235 count = 0; 1236 group_free = 0; 1237 } 1238 } 1239 fs->super->s_free_blocks_count = total_free; 1240 1241 /* 1242 * Next, calculate the inode statistics 1243 */ 1244 group_free = 0; 1245 total_free = 0; 1246 count = 0; 1247 group = 0; 1248 1249 /* Protect loop from wrap-around if s_inodes_count maxed */ 1250 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) { 1251 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) { 1252 group_free++; 1253 total_free++; 1254 } 1255 count++; 1256 if ((count == fs->super->s_inodes_per_group) || 1257 (ino == fs->super->s_inodes_count)) { 1258 fs->group_desc[group++].bg_free_inodes_count = 1259 group_free; 1260 count = 0; 1261 group_free = 0; 1262 } 1263 } 1264 fs->super->s_free_inodes_count = total_free; 1265 ext2fs_mark_super_dirty(fs); 1266 return 0; 1267} 1268 1269#define list_for_each_safe(pos, pnext, head) \ 1270 for (pos = (head)->next, pnext = pos->next; pos != (head); \ 1271 pos = pnext, pnext = pos->next) 1272 1273static void free_blk_move_list(void) 1274{ 1275 struct list_head *entry, *tmp; 1276 struct blk_move *bmv; 1277 1278 list_for_each_safe(entry, tmp, &blk_move_list) { 1279 1280 bmv = list_entry(entry, struct blk_move, list); 1281 list_del(entry); 1282 ext2fs_free_mem(&bmv); 1283 } 1284 1285 return ; 1286} 1287 1288static int resize_inode(ext2_filsys fs, unsigned long new_size) 1289{ 1290 errcode_t retval; 1291 int new_ino_blks_per_grp; 1292 ext2fs_block_bitmap bmap; 1293 1294 if (new_size <= EXT2_INODE_SIZE(fs->super)) { 1295 fprintf(stderr, _("New inode size too small\n")); 1296 return EXT2_ET_INVALID_ARGUMENT; 1297 } 1298 1299 ext2fs_read_inode_bitmap(fs); 1300 ext2fs_read_block_bitmap(fs); 1301 INIT_LIST_HEAD(&blk_move_list); 1302 1303 1304 new_ino_blks_per_grp = ext2fs_div_ceil( 1305 EXT2_INODES_PER_GROUP(fs->super)* 1306 new_size, 1307 fs->blocksize); 1308 1309 /* We may change the file system. 1310 * Mark the file system as invalid so that 1311 * the user is prompted to run fsck. 1312 */ 1313 fs->super->s_state &= ~EXT2_VALID_FS; 1314 1315 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"), 1316 &bmap); 1317 if (retval) 1318 return retval; 1319 1320 retval = get_move_bitmap(fs, new_ino_blks_per_grp, bmap); 1321 if (retval) 1322 goto err_out; 1323 1324 retval = move_block(fs, bmap); 1325 if (retval) 1326 goto err_out; 1327 1328 retval = inode_scan_and_fix(fs); 1329 if (retval) 1330 goto err_out; 1331 1332 retval = expand_inode_table(fs, new_size); 1333 if (retval) 1334 goto err_out; 1335 1336 ext2fs_calculate_summary_stats(fs); 1337 1338 fs->super->s_state |= EXT2_VALID_FS; 1339 /* mark super block and block bitmap as dirty */ 1340 ext2fs_mark_super_dirty(fs); 1341 ext2fs_mark_bb_dirty(fs); 1342 1343err_out: 1344 free_blk_move_list(); 1345 ext2fs_free_block_bitmap(bmap); 1346 1347 return retval; 1348} 1349 1350static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) 1351{ 1352 errcode_t retval = 0; 1353 const char *tdb_dir; 1354 char tdb_file[PATH_MAX]; 1355 char *dev_name, *tmp_name; 1356 1357#if 0 /* FIXME!! */ 1358 /* 1359 * Configuration via a conf file would be 1360 * nice 1361 */ 1362 profile_get_string(profile, "scratch_files", 1363 "directory", 0, 0, 1364 &tdb_dir); 1365#endif 1366 tmp_name = strdup(name); 1367 dev_name = basename(tmp_name); 1368 1369 tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); 1370 if (!tdb_dir) 1371 tdb_dir="/var/lib/e2fsprogs"; 1372 1373 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || 1374 access(tdb_dir, W_OK)) 1375 return 0; 1376 1377 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); 1378 1379 if (!access(tdb_file, F_OK)) { 1380 if (unlink(tdb_file) < 0) { 1381 retval = errno; 1382 com_err(program_name, retval, 1383 _("while trying to delete %s"), 1384 tdb_file); 1385 return retval; 1386 } 1387 } 1388 1389 set_undo_io_backing_manager(*io_ptr); 1390 *io_ptr = undo_io_manager; 1391 set_undo_io_backup_file(tdb_file); 1392 printf(_("To undo the tune2fs operations please run " 1393 "the command\n e2undo %s %s\n\n"), 1394 tdb_file, name); 1395 free(tmp_name); 1396 return retval; 1397} 1398 1399int main (int argc, char ** argv) 1400{ 1401 errcode_t retval; 1402 ext2_filsys fs; 1403 struct ext2_super_block *sb; 1404 io_manager io_ptr; 1405 1406#ifdef ENABLE_NLS 1407 setlocale(LC_MESSAGES, ""); 1408 setlocale(LC_CTYPE, ""); 1409 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1410 textdomain(NLS_CAT_NAME); 1411#endif 1412 if (argc && *argv) 1413 program_name = *argv; 1414 add_error_table(&et_ext2_error_table); 1415 1416 if (strcmp(get_progname(argv[0]), "findfs") == 0) 1417 do_findfs(argc, argv); 1418 if (strcmp(get_progname(argv[0]), "e2label") == 0) 1419 parse_e2label_options(argc, argv); 1420 else 1421 parse_tune2fs_options(argc, argv); 1422 1423#ifdef CONFIG_TESTIO_DEBUG 1424 io_ptr = test_io_manager; 1425 test_io_backing_manager = unix_io_manager; 1426#else 1427 io_ptr = unix_io_manager; 1428#endif 1429 1430 if (I_flag) { 1431 /* 1432 * If inode resize is requested use the 1433 * Undo I/O manager 1434 */ 1435 retval = tune2fs_setup_tdb(device_name, &io_ptr); 1436 if (retval) 1437 exit(1); 1438 } 1439 1440 retval = ext2fs_open2(device_name, io_options, open_flag, 1441 0, 0, io_ptr, &fs); 1442 if (retval) { 1443 com_err (program_name, retval, _("while trying to open %s"), 1444 device_name); 1445 fprintf(stderr, 1446 _("Couldn't find valid filesystem superblock.\n")); 1447 exit(1); 1448 } 1449 sb = fs->super; 1450 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1451 1452 if (print_label) { 1453 /* For e2label emulation */ 1454 printf("%.*s\n", (int) sizeof(sb->s_volume_name), 1455 sb->s_volume_name); 1456 remove_error_table(&et_ext2_error_table); 1457 exit(0); 1458 } 1459 1460 retval = ext2fs_check_if_mounted(device_name, &mount_flags); 1461 if (retval) { 1462 com_err("ext2fs_check_if_mount", retval, 1463 _("while determining whether %s is mounted."), 1464 device_name); 1465 exit(1); 1466 } 1467 /* Normally we only need to write out the superblock */ 1468 fs->flags |= EXT2_FLAG_SUPER_ONLY; 1469 1470 if (c_flag) { 1471 sb->s_max_mnt_count = max_mount_count; 1472 ext2fs_mark_super_dirty(fs); 1473 printf (_("Setting maximal mount count to %d\n"), 1474 max_mount_count); 1475 } 1476 if (C_flag) { 1477 sb->s_mnt_count = mount_count; 1478 ext2fs_mark_super_dirty(fs); 1479 printf (_("Setting current mount count to %d\n"), mount_count); 1480 } 1481 if (e_flag) { 1482 sb->s_errors = errors; 1483 ext2fs_mark_super_dirty(fs); 1484 printf (_("Setting error behavior to %d\n"), errors); 1485 } 1486 if (g_flag) { 1487 sb->s_def_resgid = resgid; 1488 ext2fs_mark_super_dirty(fs); 1489 printf (_("Setting reserved blocks gid to %lu\n"), resgid); 1490 } 1491 if (i_flag) { 1492 sb->s_checkinterval = interval; 1493 ext2fs_mark_super_dirty(fs); 1494 printf (_("Setting interval between checks to %lu seconds\n"), interval); 1495 } 1496 if (m_flag) { 1497 sb->s_r_blocks_count = (unsigned int) (reserved_ratio * 1498 sb->s_blocks_count / 100.0); 1499 ext2fs_mark_super_dirty(fs); 1500 printf (_("Setting reserved blocks percentage to %g%% (%u blocks)\n"), 1501 reserved_ratio, sb->s_r_blocks_count); 1502 } 1503 if (r_flag) { 1504 if (reserved_blocks >= sb->s_blocks_count/2) { 1505 com_err (program_name, 0, 1506 _("reserved blocks count is too big (%lu)"), 1507 reserved_blocks); 1508 exit (1); 1509 } 1510 sb->s_r_blocks_count = reserved_blocks; 1511 ext2fs_mark_super_dirty(fs); 1512 printf (_("Setting reserved blocks count to %lu\n"), 1513 reserved_blocks); 1514 } 1515 if (s_flag == 1) { 1516 if (sb->s_feature_ro_compat & 1517 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) 1518 fputs(_("\nThe filesystem already has sparse " 1519 "superblocks.\n"), stderr); 1520 else { 1521 sb->s_feature_ro_compat |= 1522 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; 1523 sb->s_state &= ~EXT2_VALID_FS; 1524 ext2fs_mark_super_dirty(fs); 1525 printf(_("\nSparse superblock flag set. %s"), 1526 _(please_fsck)); 1527 } 1528 } 1529 if (s_flag == 0) { 1530 fputs(_("\nClearing the sparse superflag not supported.\n"), 1531 stderr); 1532 exit(1); 1533 } 1534 if (T_flag) { 1535 sb->s_lastcheck = last_check_time; 1536 ext2fs_mark_super_dirty(fs); 1537 printf(_("Setting time filesystem last checked to %s\n"), 1538 ctime(&last_check_time)); 1539 } 1540 if (u_flag) { 1541 sb->s_def_resuid = resuid; 1542 ext2fs_mark_super_dirty(fs); 1543 printf (_("Setting reserved blocks uid to %lu\n"), resuid); 1544 } 1545 if (L_flag) { 1546 if (strlen(new_label) > sizeof(sb->s_volume_name)) 1547 fputs(_("Warning: label too long, truncating.\n"), 1548 stderr); 1549 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); 1550 strncpy(sb->s_volume_name, new_label, 1551 sizeof(sb->s_volume_name)); 1552 ext2fs_mark_super_dirty(fs); 1553 } 1554 if (M_flag) { 1555 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); 1556 strncpy(sb->s_last_mounted, new_last_mounted, 1557 sizeof(sb->s_last_mounted)); 1558 ext2fs_mark_super_dirty(fs); 1559 } 1560 if (mntopts_cmd) 1561 update_mntopts(fs, mntopts_cmd); 1562 if (features_cmd) 1563 update_feature_set(fs, features_cmd); 1564 if (extended_cmd) 1565 parse_extended_opts(fs, extended_cmd); 1566 if (journal_size || journal_device) 1567 add_journal(fs); 1568 1569 if (U_flag) { 1570 if ((strcasecmp(new_UUID, "null") == 0) || 1571 (strcasecmp(new_UUID, "clear") == 0)) { 1572 uuid_clear(sb->s_uuid); 1573 } else if (strcasecmp(new_UUID, "time") == 0) { 1574 uuid_generate_time(sb->s_uuid); 1575 } else if (strcasecmp(new_UUID, "random") == 0) { 1576 uuid_generate(sb->s_uuid); 1577 } else if (uuid_parse(new_UUID, sb->s_uuid)) { 1578 com_err(program_name, 0, _("Invalid UUID format\n")); 1579 exit(1); 1580 } 1581 ext2fs_mark_super_dirty(fs); 1582 } 1583 if (I_flag) { 1584 if (mount_flags & EXT2_MF_MOUNTED) { 1585 fputs(_("The inode size may only be " 1586 "changed when the filesystem is " 1587 "unmounted.\n"), stderr); 1588 exit(1); 1589 } 1590 /* 1591 * We want to update group descriptor also 1592 * with the new free inode count 1593 */ 1594 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 1595 if (resize_inode(fs, new_inode_size)) { 1596 fputs(_("Error in resizing the inode size.\n" 1597 "Run e2undo to undo the " 1598 "file system changes. \n"), stderr); 1599 } else { 1600 printf (_("Setting inode size %lu\n"), 1601 new_inode_size); 1602 } 1603 } 1604 1605 if (l_flag) 1606 list_super (sb); 1607 if (stride_set) { 1608 sb->s_raid_stride = stride; 1609 ext2fs_mark_super_dirty(fs); 1610 printf(_("Setting stride size to %d\n"), stride); 1611 } 1612 if (stripe_width_set) { 1613 sb->s_raid_stripe_width = stripe_width; 1614 ext2fs_mark_super_dirty(fs); 1615 printf(_("Setting stripe width to %d\n"), stripe_width); 1616 } 1617 remove_error_table(&et_ext2_error_table); 1618 return (ext2fs_close (fs) ? 1 : 0); 1619} 1620