tune2fs.c revision 2be8fe43976537b75a6ee154ff3ba47e538b55fb
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 500 /* 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 creating setting the flag and 393 * creating the journal. We supply a default size if 394 * necessary. 395 */ 396 if (!journal_size) 397 journal_size = -1; 398 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; 399 } 400 401 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) { 402 if (!sb->s_def_hash_version) 403 sb->s_def_hash_version = EXT2_HASH_TEA; 404 if (uuid_is_null((unsigned char *) sb->s_hash_seed)) 405 uuid_generate((unsigned char *) sb->s_hash_seed); 406 } 407 408 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { 409 if (ext2fs_check_desc(fs)) { 410 fputs(_("Clearing the flex_bg flag would " 411 "cause the the filesystem to be\n" 412 "inconsistent.\n"), stderr); 413 exit(1); 414 } 415 } 416 417 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 418 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 419 if ((mount_flags & EXT2_MF_MOUNTED) && 420 !(mount_flags & EXT2_MF_READONLY)) { 421 fputs(_("The huge_file feature may only be " 422 "cleared when the filesystem is\n" 423 "unmounted or mounted " 424 "read-only.\n"), stderr); 425 exit(1); 426 } 427 } 428 429 if (sb->s_rev_level == EXT2_GOOD_OLD_REV && 430 (sb->s_feature_compat || sb->s_feature_ro_compat || 431 sb->s_feature_incompat)) 432 ext2fs_update_dynamic_rev(fs); 433 434 if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, 435 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || 436 FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, 437 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) || 438 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 439 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || 440 FEATURE_CHANGED(E2P_FEATURE_INCOMPAT, 441 EXT2_FEATURE_INCOMPAT_FILETYPE) || 442 FEATURE_CHANGED(E2P_FEATURE_COMPAT, 443 EXT2_FEATURE_COMPAT_RESIZE_INODE) || 444 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 445 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { 446 sb->s_state &= ~EXT2_VALID_FS; 447 printf("\n%s\n", _(please_fsck)); 448 if (mount_flags & EXT2_MF_READONLY) 449 printf(_("(and reboot afterwards!)\n")); 450 } 451 452 if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) || 453 (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) || 454 (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat)) 455 ext2fs_mark_super_dirty(fs); 456} 457 458/* 459 * Add a journal to the filesystem. 460 */ 461static void add_journal(ext2_filsys fs) 462{ 463 unsigned long journal_blocks; 464 errcode_t retval; 465 ext2_filsys jfs; 466 io_manager io_ptr; 467 468 if (fs->super->s_feature_compat & 469 EXT3_FEATURE_COMPAT_HAS_JOURNAL) { 470 fputs(_("The filesystem already has a journal.\n"), stderr); 471 goto err; 472 } 473 if (journal_device) { 474 check_plausibility(journal_device); 475 check_mount(journal_device, 0, _("journal")); 476#ifdef CONFIG_TESTIO_DEBUG 477 io_ptr = test_io_manager; 478 test_io_backing_manager = unix_io_manager; 479#else 480 io_ptr = unix_io_manager; 481#endif 482 retval = ext2fs_open(journal_device, EXT2_FLAG_RW| 483 EXT2_FLAG_JOURNAL_DEV_OK, 0, 484 fs->blocksize, io_ptr, &jfs); 485 if (retval) { 486 com_err(program_name, retval, 487 _("\n\twhile trying to open journal on %s\n"), 488 journal_device); 489 goto err; 490 } 491 printf(_("Creating journal on device %s: "), 492 journal_device); 493 fflush(stdout); 494 495 retval = ext2fs_add_journal_device(fs, jfs); 496 ext2fs_close(jfs); 497 if (retval) { 498 com_err (program_name, retval, 499 _("while adding filesystem to journal on %s"), 500 journal_device); 501 goto err; 502 } 503 fputs(_("done\n"), stdout); 504 } else if (journal_size) { 505 fputs(_("Creating journal inode: "), stdout); 506 fflush(stdout); 507 journal_blocks = figure_journal_size(journal_size, fs); 508 509 retval = ext2fs_add_journal_inode(fs, journal_blocks, 510 journal_flags); 511 if (retval) { 512 fprintf(stderr, "\n"); 513 com_err(program_name, retval, 514 _("\n\twhile trying to create journal file")); 515 exit(1); 516 } else 517 fputs(_("done\n"), stdout); 518 /* 519 * If the filesystem wasn't mounted, we need to force 520 * the block group descriptors out. 521 */ 522 if ((mount_flags & EXT2_MF_MOUNTED) == 0) 523 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 524 } 525 print_check_message(fs); 526 return; 527 528err: 529 if (journal_device) 530 free(journal_device); 531 exit(1); 532} 533 534 535static void parse_e2label_options(int argc, char ** argv) 536{ 537 if ((argc < 2) || (argc > 3)) { 538 fputs(_("Usage: e2label device [newlabel]\n"), stderr); 539 exit(1); 540 } 541 io_options = strchr(argv[1], '?'); 542 if (io_options) 543 *io_options++ = 0; 544 device_name = blkid_get_devname(NULL, argv[1], NULL); 545 if (!device_name) { 546 com_err("e2label", 0, _("Unable to resolve '%s'"), 547 argv[1]); 548 exit(1); 549 } 550 open_flag = EXT2_FLAG_JOURNAL_DEV_OK; 551 if (argc == 3) { 552 open_flag |= EXT2_FLAG_RW; 553 L_flag = 1; 554 new_label = argv[2]; 555 } else 556 print_label++; 557} 558 559static time_t parse_time(char *str) 560{ 561 struct tm ts; 562 563 if (strcmp(str, "now") == 0) { 564 return (time(0)); 565 } 566 memset(&ts, 0, sizeof(ts)); 567#ifdef HAVE_STRPTIME 568 strptime(str, "%Y%m%d%H%M%S", &ts); 569#else 570 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, 571 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); 572 ts.tm_year -= 1900; 573 ts.tm_mon -= 1; 574 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || 575 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || 576 ts.tm_min > 59 || ts.tm_sec > 61) 577 ts.tm_mday = 0; 578#endif 579 if (ts.tm_mday == 0) { 580 com_err(program_name, 0, 581 _("Couldn't parse date/time specifier: %s"), 582 str); 583 usage(); 584 } 585 ts.tm_isdst = -1; 586 return (mktime(&ts)); 587} 588 589static void parse_tune2fs_options(int argc, char **argv) 590{ 591 int c; 592 char * tmp; 593 struct group * gr; 594 struct passwd * pw; 595 596 open_flag = 0; 597 598 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); 599 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:")) != EOF) 600 switch (c) 601 { 602 case 'c': 603 max_mount_count = strtol (optarg, &tmp, 0); 604 if (*tmp || max_mount_count > 16000) { 605 com_err (program_name, 0, 606 _("bad mounts count - %s"), 607 optarg); 608 usage(); 609 } 610 if (max_mount_count == 0) 611 max_mount_count = -1; 612 c_flag = 1; 613 open_flag = EXT2_FLAG_RW; 614 break; 615 case 'C': 616 mount_count = strtoul (optarg, &tmp, 0); 617 if (*tmp || mount_count > 16000) { 618 com_err (program_name, 0, 619 _("bad mounts count - %s"), 620 optarg); 621 usage(); 622 } 623 C_flag = 1; 624 open_flag = EXT2_FLAG_RW; 625 break; 626 case 'e': 627 if (strcmp (optarg, "continue") == 0) 628 errors = EXT2_ERRORS_CONTINUE; 629 else if (strcmp (optarg, "remount-ro") == 0) 630 errors = EXT2_ERRORS_RO; 631 else if (strcmp (optarg, "panic") == 0) 632 errors = EXT2_ERRORS_PANIC; 633 else { 634 com_err (program_name, 0, 635 _("bad error behavior - %s"), 636 optarg); 637 usage(); 638 } 639 e_flag = 1; 640 open_flag = EXT2_FLAG_RW; 641 break; 642 case 'E': 643 extended_cmd = optarg; 644 open_flag |= EXT2_FLAG_RW; 645 break; 646 case 'f': /* Force */ 647 f_flag = 1; 648 break; 649 case 'g': 650 resgid = strtoul (optarg, &tmp, 0); 651 if (*tmp) { 652 gr = getgrnam (optarg); 653 if (gr == NULL) 654 tmp = optarg; 655 else { 656 resgid = gr->gr_gid; 657 *tmp =0; 658 } 659 } 660 if (*tmp) { 661 com_err (program_name, 0, 662 _("bad gid/group name - %s"), 663 optarg); 664 usage(); 665 } 666 g_flag = 1; 667 open_flag = EXT2_FLAG_RW; 668 break; 669 case 'i': 670 interval = strtoul (optarg, &tmp, 0); 671 switch (*tmp) { 672 case 's': 673 tmp++; 674 break; 675 case '\0': 676 case 'd': 677 case 'D': /* days */ 678 interval *= 86400; 679 if (*tmp != '\0') 680 tmp++; 681 break; 682 case 'm': 683 case 'M': /* months! */ 684 interval *= 86400 * 30; 685 tmp++; 686 break; 687 case 'w': 688 case 'W': /* weeks */ 689 interval *= 86400 * 7; 690 tmp++; 691 break; 692 } 693 if (*tmp) { 694 com_err (program_name, 0, 695 _("bad interval - %s"), optarg); 696 usage(); 697 } 698 i_flag = 1; 699 open_flag = EXT2_FLAG_RW; 700 break; 701 case 'j': 702 if (!journal_size) 703 journal_size = -1; 704 open_flag = EXT2_FLAG_RW; 705 break; 706 case 'J': 707 parse_journal_opts(optarg); 708 open_flag = EXT2_FLAG_RW; 709 break; 710 case 'l': 711 l_flag = 1; 712 break; 713 case 'L': 714 new_label = optarg; 715 L_flag = 1; 716 open_flag |= EXT2_FLAG_RW | 717 EXT2_FLAG_JOURNAL_DEV_OK; 718 break; 719 case 'm': 720 reserved_ratio = strtod(optarg, &tmp); 721 if (*tmp || reserved_ratio > 50) { 722 com_err (program_name, 0, 723 _("bad reserved block ratio - %s"), 724 optarg); 725 usage(); 726 } 727 m_flag = 1; 728 open_flag = EXT2_FLAG_RW; 729 break; 730 case 'M': 731 new_last_mounted = optarg; 732 M_flag = 1; 733 open_flag = EXT2_FLAG_RW; 734 break; 735 case 'o': 736 if (mntopts_cmd) { 737 com_err (program_name, 0, 738 _("-o may only be specified once")); 739 usage(); 740 } 741 mntopts_cmd = optarg; 742 open_flag = EXT2_FLAG_RW; 743 break; 744 745 case 'O': 746 if (features_cmd) { 747 com_err (program_name, 0, 748 _("-O may only be specified once")); 749 usage(); 750 } 751 features_cmd = optarg; 752 open_flag = EXT2_FLAG_RW; 753 break; 754 case 'r': 755 reserved_blocks = strtoul (optarg, &tmp, 0); 756 if (*tmp) { 757 com_err (program_name, 0, 758 _("bad reserved blocks count - %s"), 759 optarg); 760 usage(); 761 } 762 r_flag = 1; 763 open_flag = EXT2_FLAG_RW; 764 break; 765 case 's': /* Deprecated */ 766 s_flag = atoi(optarg); 767 open_flag = EXT2_FLAG_RW; 768 break; 769 case 'T': 770 T_flag = 1; 771 last_check_time = parse_time(optarg); 772 open_flag = EXT2_FLAG_RW; 773 break; 774 case 'u': 775 resuid = strtoul (optarg, &tmp, 0); 776 if (*tmp) { 777 pw = getpwnam (optarg); 778 if (pw == NULL) 779 tmp = optarg; 780 else { 781 resuid = pw->pw_uid; 782 *tmp = 0; 783 } 784 } 785 if (*tmp) { 786 com_err (program_name, 0, 787 _("bad uid/user name - %s"), 788 optarg); 789 usage(); 790 } 791 u_flag = 1; 792 open_flag = EXT2_FLAG_RW; 793 break; 794 case 'U': 795 new_UUID = optarg; 796 U_flag = 1; 797 open_flag = EXT2_FLAG_RW | 798 EXT2_FLAG_JOURNAL_DEV_OK; 799 break; 800 case 'I': 801 new_inode_size = strtoul (optarg, &tmp, 0); 802 if (*tmp) { 803 com_err (program_name, 0, 804 _("bad inode size - %s"), 805 optarg); 806 usage(); 807 } 808 if (!((new_inode_size & 809 (new_inode_size - 1)) == 0)) { 810 com_err (program_name, 0, 811 _("Inode size must be a " 812 "power of two- %s"), 813 optarg); 814 usage(); 815 } 816 open_flag = EXT2_FLAG_RW; 817 I_flag = 1; 818 break; 819 default: 820 usage(); 821 } 822 if (optind < argc - 1 || optind == argc) 823 usage(); 824 if (!open_flag && !l_flag) 825 usage(); 826 io_options = strchr(argv[optind], '?'); 827 if (io_options) 828 *io_options++ = 0; 829 device_name = blkid_get_devname(NULL, argv[optind], NULL); 830 if (!device_name) { 831 com_err("tune2fs", 0, _("Unable to resolve '%s'"), 832 argv[optind]); 833 exit(1); 834 } 835} 836 837void do_findfs(int argc, char **argv) 838{ 839 char *dev; 840 841 if ((argc != 2) || 842 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { 843 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n"); 844 exit(2); 845 } 846 dev = blkid_get_devname(NULL, argv[1], NULL); 847 if (!dev) { 848 com_err("findfs", 0, _("Unable to resolve '%s'"), 849 argv[1]); 850 exit(1); 851 } 852 puts(dev); 853 exit(0); 854} 855 856static void parse_extended_opts(ext2_filsys fs, const char *opts) 857{ 858 char *buf, *token, *next, *p, *arg; 859 int len; 860 int r_usage = 0; 861 862 len = strlen(opts); 863 buf = malloc(len+1); 864 if (!buf) { 865 fprintf(stderr, 866 _("Couldn't allocate memory to parse options!\n")); 867 exit(1); 868 } 869 strcpy(buf, opts); 870 for (token = buf; token && *token; token = next) { 871 p = strchr(token, ','); 872 next = 0; 873 if (p) { 874 *p = 0; 875 next = p+1; 876 } 877 arg = strchr(token, '='); 878 if (arg) { 879 *arg = 0; 880 arg++; 881 } 882 if (!strcmp(token, "test_fs")) { 883 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; 884 printf("Setting test filesystem flag\n"); 885 ext2fs_mark_super_dirty(fs); 886 } else if (!strcmp(token, "^test_fs")) { 887 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS; 888 printf("Clearing test filesystem flag\n"); 889 ext2fs_mark_super_dirty(fs); 890 } else if (strcmp(token, "stride") == 0) { 891 if (!arg) { 892 r_usage++; 893 continue; 894 } 895 stride = strtoul(arg, &p, 0); 896 if (*p || (stride == 0)) { 897 fprintf(stderr, 898 _("Invalid RAID stride: %s\n"), 899 arg); 900 r_usage++; 901 continue; 902 } 903 stride_set = 1; 904 } else if (strcmp(token, "stripe-width") == 0 || 905 strcmp(token, "stripe_width") == 0) { 906 if (!arg) { 907 r_usage++; 908 continue; 909 } 910 stripe_width = strtoul(arg, &p, 0); 911 if (*p || (stripe_width == 0)) { 912 fprintf(stderr, 913 _("Invalid RAID stripe-width: %s\n"), 914 arg); 915 r_usage++; 916 continue; 917 } 918 stripe_width_set = 1; 919 } else 920 r_usage++; 921 } 922 if (r_usage) { 923 fprintf(stderr, _("\nBad options specified.\n\n" 924 "Extended options are separated by commas, " 925 "and may take an argument which\n" 926 "\tis set off by an equals ('=') sign.\n\n" 927 "Valid extended options are:\n" 928 "\tstride=<RAID per-disk chunk size in blocks>\n" 929 "\tstripe-width=<RAID stride*data disks in blocks>\n" 930 "\ttest_fs\n" 931 "\t^test_fs\n")); 932 free(buf); 933 exit(1); 934 } 935 free(buf); 936} 937 938static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp, 939 ext2fs_block_bitmap bmap) 940{ 941 dgrp_t i; 942 blk_t j, needed_blocks = 0; 943 blk_t start_blk, end_blk; 944 945 for (i = 0; i < fs->group_desc_count; i++) { 946 947 start_blk = fs->group_desc[i].bg_inode_table + 948 fs->inode_blocks_per_group; 949 950 end_blk = fs->group_desc[i].bg_inode_table + 951 new_ino_blks_per_grp; 952 953 for (j = start_blk; j < end_blk; j++) { 954 955 if (ext2fs_test_block_bitmap(fs->block_map, j)) { 956 /* FIXME!! 957 * What happens if the block is marked 958 * as a bad block 959 */ 960 ext2fs_mark_block_bitmap(bmap, j); 961 needed_blocks++; 962 } else { 963 /* 964 * We are going to use this block for 965 * inode table. So mark them used. 966 */ 967 ext2fs_mark_block_bitmap(fs->block_map, j); 968 } 969 } 970 } 971 972 if (needed_blocks > fs->super->s_free_blocks_count ) { 973 return ENOSPC; 974 } 975 976 return 0; 977} 978 979static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap) 980{ 981 char *buf; 982 errcode_t retval; 983 blk_t blk, new_blk; 984 struct blk_move *bmv; 985 986 987 retval = ext2fs_get_mem(fs->blocksize, &buf); 988 if (retval) 989 return retval; 990 991 for (blk = fs->super->s_first_data_block; 992 blk < fs->super->s_blocks_count; blk++) { 993 994 if (!ext2fs_test_block_bitmap(bmap, blk)) 995 continue; 996 997 retval = ext2fs_new_block(fs, blk, NULL, &new_blk); 998 if (retval) 999 goto err_out; 1000 1001 /* Mark this block as allocated */ 1002 ext2fs_mark_block_bitmap(fs->block_map, new_blk); 1003 1004 /* Add it to block move list */ 1005 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv); 1006 if (retval) 1007 goto err_out; 1008 1009 bmv->old_loc = blk; 1010 bmv->new_loc = new_blk; 1011 1012 list_add(&(bmv->list), &blk_move_list); 1013 1014 retval = io_channel_read_blk(fs->io, blk, 1, buf); 1015 if (retval) 1016 goto err_out; 1017 1018 retval = io_channel_write_blk(fs->io, new_blk, 1, buf); 1019 if (retval) 1020 goto err_out; 1021 } 1022 1023err_out: 1024 ext2fs_free_mem(&buf); 1025 return retval; 1026} 1027 1028static blk_t transalate_block(blk_t blk) 1029{ 1030 struct list_head *entry; 1031 struct blk_move *bmv; 1032 1033 list_for_each(entry, &blk_move_list) { 1034 1035 bmv = list_entry(entry, struct blk_move, list); 1036 if (bmv->old_loc == blk) 1037 return bmv->new_loc; 1038 } 1039 1040 return 0; 1041} 1042 1043static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)), 1044 blk_t *block_nr, 1045 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1046 blk_t ref_block EXT2FS_ATTR((unused)), 1047 int ref_offset EXT2FS_ATTR((unused)), 1048 void *priv_data EXT2FS_ATTR((unused))) 1049{ 1050 int ret = 0; 1051 blk_t new_blk; 1052 1053 1054 new_blk = transalate_block(*block_nr); 1055 if (new_blk) { 1056 *block_nr = new_blk; 1057 /* 1058 * This will force the ext2fs_write_inode in the iterator 1059 */ 1060 ret |= BLOCK_CHANGED; 1061 } 1062 1063 return ret; 1064} 1065 1066static int inode_scan_and_fix(ext2_filsys fs) 1067{ 1068 errcode_t retval = 0; 1069 ext2_ino_t ino; 1070 blk_t blk; 1071 char *block_buf = 0; 1072 struct ext2_inode inode; 1073 ext2_inode_scan scan = NULL; 1074 1075 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf); 1076 if (retval) 1077 return retval; 1078 1079 retval = ext2fs_open_inode_scan(fs, 0, &scan); 1080 if (retval) 1081 goto err_out; 1082 1083 while (1) { 1084 1085 retval = ext2fs_get_next_inode(scan, &ino, &inode); 1086 if (retval) 1087 goto err_out; 1088 1089 if (!ino) 1090 break; 1091 1092 if (inode.i_links_count == 0) 1093 continue; /* inode not in use */ 1094 1095 /* FIXME!! 1096 * If we end up modifying the journal inode 1097 * the sb->s_jnl_blocks will differ. But a 1098 * subsequent e2fsck fixes that. 1099 * Do we need to fix this ?? 1100 */ 1101 1102 if (inode.i_file_acl) { 1103 1104 blk = transalate_block(inode.i_file_acl); 1105 if (!blk) 1106 continue; 1107 1108 inode.i_file_acl = blk; 1109 1110 /* 1111 * Write the inode to disk so that inode table 1112 * resizing can work 1113 */ 1114 retval = ext2fs_write_inode(fs, ino, &inode); 1115 if (retval) 1116 goto err_out; 1117 } 1118 1119 if (!ext2fs_inode_has_valid_blocks(&inode)) 1120 continue; 1121 1122 retval = ext2fs_block_iterate2(fs, ino, 0, 1123 block_buf, process_block, 1124 0); 1125 if (retval) 1126 goto err_out; 1127 1128 } 1129 1130err_out: 1131 ext2fs_free_mem(&block_buf); 1132 1133 return retval; 1134 1135} 1136 1137static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size) 1138{ 1139 dgrp_t i; 1140 blk_t blk; 1141 errcode_t retval; 1142 int new_ino_blks_per_grp; 1143 unsigned int j; 1144 char *old_itable = NULL, *new_itable = NULL; 1145 char *tmp_old_itable = NULL, *tmp_new_itable = NULL; 1146 unsigned long old_ino_size; 1147 int old_itable_size, new_itable_size; 1148 1149 old_itable_size = fs->inode_blocks_per_group * fs->blocksize; 1150 old_ino_size = EXT2_INODE_SIZE(fs->super); 1151 1152 new_ino_blks_per_grp = ext2fs_div_ceil( 1153 EXT2_INODES_PER_GROUP(fs->super) * 1154 new_ino_size, 1155 fs->blocksize); 1156 1157 new_itable_size = new_ino_blks_per_grp * fs->blocksize; 1158 1159 retval = ext2fs_get_mem(old_itable_size, &old_itable); 1160 if (retval) 1161 return retval; 1162 1163 retval = ext2fs_get_mem(new_itable_size, &new_itable); 1164 if (retval) 1165 goto err_out; 1166 1167 tmp_old_itable = old_itable; 1168 tmp_new_itable = new_itable; 1169 1170 for (i = 0; i < fs->group_desc_count; i++) { 1171 1172 blk = fs->group_desc[i].bg_inode_table; 1173 retval = io_channel_read_blk(fs->io, blk, 1174 fs->inode_blocks_per_group, old_itable); 1175 if (retval) 1176 goto err_out; 1177 1178 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) { 1179 1180 memcpy(new_itable, old_itable, old_ino_size); 1181 1182 memset(new_itable+old_ino_size, 0, 1183 new_ino_size - old_ino_size); 1184 1185 new_itable += new_ino_size; 1186 old_itable += old_ino_size; 1187 } 1188 1189 /* reset the pointer */ 1190 old_itable = tmp_old_itable; 1191 new_itable = tmp_new_itable; 1192 1193 retval = io_channel_write_blk(fs->io, blk, 1194 new_ino_blks_per_grp, new_itable); 1195 if (retval) 1196 goto err_out; 1197 } 1198 1199 /* Update the meta data */ 1200 fs->inode_blocks_per_group = new_ino_blks_per_grp; 1201 fs->super->s_inode_size = new_ino_size; 1202 1203err_out: 1204 if (old_itable) 1205 ext2fs_free_mem(&old_itable); 1206 1207 if (new_itable) 1208 ext2fs_free_mem(&new_itable); 1209 1210 return retval; 1211} 1212 1213static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs) 1214{ 1215 blk_t blk; 1216 ext2_ino_t ino; 1217 unsigned int group = 0; 1218 unsigned int count = 0; 1219 int total_free = 0; 1220 int group_free = 0; 1221 1222 /* 1223 * First calculate the block statistics 1224 */ 1225 for (blk = fs->super->s_first_data_block; 1226 blk < fs->super->s_blocks_count; blk++) { 1227 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) { 1228 group_free++; 1229 total_free++; 1230 } 1231 count++; 1232 if ((count == fs->super->s_blocks_per_group) || 1233 (blk == fs->super->s_blocks_count-1)) { 1234 fs->group_desc[group++].bg_free_blocks_count = 1235 group_free; 1236 count = 0; 1237 group_free = 0; 1238 } 1239 } 1240 fs->super->s_free_blocks_count = total_free; 1241 1242 /* 1243 * Next, calculate the inode statistics 1244 */ 1245 group_free = 0; 1246 total_free = 0; 1247 count = 0; 1248 group = 0; 1249 1250 /* Protect loop from wrap-around if s_inodes_count maxed */ 1251 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) { 1252 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) { 1253 group_free++; 1254 total_free++; 1255 } 1256 count++; 1257 if ((count == fs->super->s_inodes_per_group) || 1258 (ino == fs->super->s_inodes_count)) { 1259 fs->group_desc[group++].bg_free_inodes_count = 1260 group_free; 1261 count = 0; 1262 group_free = 0; 1263 } 1264 } 1265 fs->super->s_free_inodes_count = total_free; 1266 ext2fs_mark_super_dirty(fs); 1267 return 0; 1268} 1269 1270#define list_for_each_safe(pos, pnext, head) \ 1271 for (pos = (head)->next, pnext = pos->next; pos != (head); \ 1272 pos = pnext, pnext = pos->next) 1273 1274static void free_blk_move_list(void) 1275{ 1276 struct list_head *entry, *tmp; 1277 struct blk_move *bmv; 1278 1279 list_for_each_safe(entry, tmp, &blk_move_list) { 1280 1281 bmv = list_entry(entry, struct blk_move, list); 1282 list_del(entry); 1283 ext2fs_free_mem(&bmv); 1284 } 1285 1286 return ; 1287} 1288 1289static int resize_inode(ext2_filsys fs, unsigned long new_size) 1290{ 1291 errcode_t retval; 1292 int new_ino_blks_per_grp; 1293 ext2fs_block_bitmap bmap; 1294 1295 if (new_size <= EXT2_INODE_SIZE(fs->super)) { 1296 fprintf(stderr, _("New inode size too small\n")); 1297 return EXT2_ET_INVALID_ARGUMENT; 1298 } 1299 1300 ext2fs_read_inode_bitmap(fs); 1301 ext2fs_read_block_bitmap(fs); 1302 INIT_LIST_HEAD(&blk_move_list); 1303 1304 1305 new_ino_blks_per_grp = ext2fs_div_ceil( 1306 EXT2_INODES_PER_GROUP(fs->super)* 1307 new_size, 1308 fs->blocksize); 1309 1310 /* We may change the file system. 1311 * Mark the file system as invalid so that 1312 * the user is prompted to run fsck. 1313 */ 1314 fs->super->s_state &= ~EXT2_VALID_FS; 1315 1316 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"), 1317 &bmap); 1318 if (retval) 1319 return retval; 1320 1321 retval = get_move_bitmap(fs, new_ino_blks_per_grp, bmap); 1322 if (retval) 1323 goto err_out; 1324 1325 retval = move_block(fs, bmap); 1326 if (retval) 1327 goto err_out; 1328 1329 retval = inode_scan_and_fix(fs); 1330 if (retval) 1331 goto err_out; 1332 1333 retval = expand_inode_table(fs, new_size); 1334 if (retval) 1335 goto err_out; 1336 1337 ext2fs_calculate_summary_stats(fs); 1338 1339 fs->super->s_state |= EXT2_VALID_FS; 1340 /* mark super block and block bitmap as dirty */ 1341 ext2fs_mark_super_dirty(fs); 1342 ext2fs_mark_bb_dirty(fs); 1343 1344err_out: 1345 free_blk_move_list(); 1346 ext2fs_free_block_bitmap(bmap); 1347 1348 return retval; 1349} 1350 1351static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) 1352{ 1353 errcode_t retval = 0; 1354 const char *tdb_dir; 1355 char tdb_file[PATH_MAX]; 1356 char *dev_name, *tmp_name; 1357 1358#if 0 /* FIXME!! */ 1359 /* 1360 * Configuration via a conf file would be 1361 * nice 1362 */ 1363 profile_get_string(profile, "scratch_files", 1364 "directory", 0, 0, 1365 &tdb_dir); 1366#endif 1367 tmp_name = strdup(name); 1368 dev_name = basename(tmp_name); 1369 1370 tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); 1371 if (!tdb_dir) 1372 tdb_dir="/var/lib/e2fsprogs"; 1373 1374 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || 1375 access(tdb_dir, W_OK)) 1376 return 0; 1377 1378 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); 1379 1380 if (!access(tdb_file, F_OK)) { 1381 if (unlink(tdb_file) < 0) { 1382 retval = errno; 1383 com_err(program_name, retval, 1384 _("while trying to delete %s"), 1385 tdb_file); 1386 return retval; 1387 } 1388 } 1389 1390 set_undo_io_backing_manager(*io_ptr); 1391 *io_ptr = undo_io_manager; 1392 set_undo_io_backup_file(tdb_file); 1393 printf(_("To undo the tune2fs operations please run " 1394 "the command\n undoe2fs %s %s\n\n"), 1395 tdb_file, name); 1396 free(tmp_name); 1397 return retval; 1398} 1399 1400int main (int argc, char ** argv) 1401{ 1402 errcode_t retval; 1403 ext2_filsys fs; 1404 struct ext2_super_block *sb; 1405 io_manager io_ptr; 1406 1407#ifdef ENABLE_NLS 1408 setlocale(LC_MESSAGES, ""); 1409 setlocale(LC_CTYPE, ""); 1410 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1411 textdomain(NLS_CAT_NAME); 1412#endif 1413 if (argc && *argv) 1414 program_name = *argv; 1415 add_error_table(&et_ext2_error_table); 1416 1417 if (strcmp(get_progname(argv[0]), "findfs") == 0) 1418 do_findfs(argc, argv); 1419 if (strcmp(get_progname(argv[0]), "e2label") == 0) 1420 parse_e2label_options(argc, argv); 1421 else 1422 parse_tune2fs_options(argc, argv); 1423 1424#ifdef CONFIG_TESTIO_DEBUG 1425 io_ptr = test_io_manager; 1426 test_io_backing_manager = unix_io_manager; 1427#else 1428 io_ptr = unix_io_manager; 1429#endif 1430 1431 if (I_flag) { 1432 /* 1433 * If inode resize is requested use the 1434 * Undo I/O manager 1435 */ 1436 retval = tune2fs_setup_tdb(device_name, &io_ptr); 1437 if (retval) 1438 exit(1); 1439 } 1440 1441 retval = ext2fs_open2(device_name, io_options, open_flag, 1442 0, 0, io_ptr, &fs); 1443 if (retval) { 1444 com_err (program_name, retval, _("while trying to open %s"), 1445 device_name); 1446 fprintf(stderr, 1447 _("Couldn't find valid filesystem superblock.\n")); 1448 exit(1); 1449 } 1450 sb = fs->super; 1451 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1452 1453 if (print_label) { 1454 /* For e2label emulation */ 1455 printf("%.*s\n", (int) sizeof(sb->s_volume_name), 1456 sb->s_volume_name); 1457 remove_error_table(&et_ext2_error_table); 1458 exit(0); 1459 } 1460 1461 retval = ext2fs_check_if_mounted(device_name, &mount_flags); 1462 if (retval) { 1463 com_err("ext2fs_check_if_mount", retval, 1464 _("while determining whether %s is mounted."), 1465 device_name); 1466 exit(1); 1467 } 1468 /* Normally we only need to write out the superblock */ 1469 fs->flags |= EXT2_FLAG_SUPER_ONLY; 1470 1471 if (c_flag) { 1472 sb->s_max_mnt_count = max_mount_count; 1473 ext2fs_mark_super_dirty(fs); 1474 printf (_("Setting maximal mount count to %d\n"), 1475 max_mount_count); 1476 } 1477 if (C_flag) { 1478 sb->s_mnt_count = mount_count; 1479 ext2fs_mark_super_dirty(fs); 1480 printf (_("Setting current mount count to %d\n"), mount_count); 1481 } 1482 if (e_flag) { 1483 sb->s_errors = errors; 1484 ext2fs_mark_super_dirty(fs); 1485 printf (_("Setting error behavior to %d\n"), errors); 1486 } 1487 if (g_flag) { 1488 sb->s_def_resgid = resgid; 1489 ext2fs_mark_super_dirty(fs); 1490 printf (_("Setting reserved blocks gid to %lu\n"), resgid); 1491 } 1492 if (i_flag) { 1493 sb->s_checkinterval = interval; 1494 ext2fs_mark_super_dirty(fs); 1495 printf (_("Setting interval between checks to %lu seconds\n"), interval); 1496 } 1497 if (m_flag) { 1498 sb->s_r_blocks_count = (unsigned int) (reserved_ratio * 1499 sb->s_blocks_count / 100.0); 1500 ext2fs_mark_super_dirty(fs); 1501 printf (_("Setting reserved blocks percentage to %g%% (%u blocks)\n"), 1502 reserved_ratio, sb->s_r_blocks_count); 1503 } 1504 if (r_flag) { 1505 if (reserved_blocks >= sb->s_blocks_count/2) { 1506 com_err (program_name, 0, 1507 _("reserved blocks count is too big (%lu)"), 1508 reserved_blocks); 1509 exit (1); 1510 } 1511 sb->s_r_blocks_count = reserved_blocks; 1512 ext2fs_mark_super_dirty(fs); 1513 printf (_("Setting reserved blocks count to %lu\n"), 1514 reserved_blocks); 1515 } 1516 if (s_flag == 1) { 1517 if (sb->s_feature_ro_compat & 1518 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) 1519 fputs(_("\nThe filesystem already has sparse " 1520 "superblocks.\n"), stderr); 1521 else { 1522 sb->s_feature_ro_compat |= 1523 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; 1524 sb->s_state &= ~EXT2_VALID_FS; 1525 ext2fs_mark_super_dirty(fs); 1526 printf(_("\nSparse superblock flag set. %s"), 1527 _(please_fsck)); 1528 } 1529 } 1530 if (s_flag == 0) { 1531 fputs(_("\nClearing the sparse superflag not supported.\n"), 1532 stderr); 1533 exit(1); 1534 } 1535 if (T_flag) { 1536 sb->s_lastcheck = last_check_time; 1537 ext2fs_mark_super_dirty(fs); 1538 printf(_("Setting time filesystem last checked to %s\n"), 1539 ctime(&last_check_time)); 1540 } 1541 if (u_flag) { 1542 sb->s_def_resuid = resuid; 1543 ext2fs_mark_super_dirty(fs); 1544 printf (_("Setting reserved blocks uid to %lu\n"), resuid); 1545 } 1546 if (L_flag) { 1547 if (strlen(new_label) > sizeof(sb->s_volume_name)) 1548 fputs(_("Warning: label too long, truncating.\n"), 1549 stderr); 1550 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); 1551 strncpy(sb->s_volume_name, new_label, 1552 sizeof(sb->s_volume_name)); 1553 ext2fs_mark_super_dirty(fs); 1554 } 1555 if (M_flag) { 1556 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); 1557 strncpy(sb->s_last_mounted, new_last_mounted, 1558 sizeof(sb->s_last_mounted)); 1559 ext2fs_mark_super_dirty(fs); 1560 } 1561 if (mntopts_cmd) 1562 update_mntopts(fs, mntopts_cmd); 1563 if (features_cmd) 1564 update_feature_set(fs, features_cmd); 1565 if (extended_cmd) 1566 parse_extended_opts(fs, extended_cmd); 1567 if (journal_size || journal_device) 1568 add_journal(fs); 1569 1570 if (U_flag) { 1571 if ((strcasecmp(new_UUID, "null") == 0) || 1572 (strcasecmp(new_UUID, "clear") == 0)) { 1573 uuid_clear(sb->s_uuid); 1574 } else if (strcasecmp(new_UUID, "time") == 0) { 1575 uuid_generate_time(sb->s_uuid); 1576 } else if (strcasecmp(new_UUID, "random") == 0) { 1577 uuid_generate(sb->s_uuid); 1578 } else if (uuid_parse(new_UUID, sb->s_uuid)) { 1579 com_err(program_name, 0, _("Invalid UUID format\n")); 1580 exit(1); 1581 } 1582 ext2fs_mark_super_dirty(fs); 1583 } 1584 if (I_flag) { 1585 if (mount_flags & EXT2_MF_MOUNTED) { 1586 fputs(_("The inode size may only be " 1587 "changed when the filesystem is " 1588 "unmounted.\n"), stderr); 1589 exit(1); 1590 } 1591 /* 1592 * We want to update group descriptor also 1593 * with the new free inode count 1594 */ 1595 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 1596 if (resize_inode(fs, new_inode_size)) { 1597 fputs(_("Error in resizing the inode size.\n" 1598 "Run undoe2fs to undo the " 1599 "file system changes. \n"), stderr); 1600 } else { 1601 printf (_("Setting inode size %lu\n"), 1602 new_inode_size); 1603 } 1604 } 1605 1606 if (l_flag) 1607 list_super (sb); 1608 if (stride_set) { 1609 sb->s_raid_stride = stride; 1610 ext2fs_mark_super_dirty(fs); 1611 printf(_("Setting stride size to %d\n"), stride); 1612 } 1613 if (stripe_width_set) { 1614 sb->s_raid_stripe_width = stripe_width; 1615 ext2fs_mark_super_dirty(fs); 1616 printf(_("Setting stripe width to %d\n"), stripe_width); 1617 } 1618 remove_error_table(&et_ext2_error_table); 1619 return (ext2fs_close (fs) ? 1 : 0); 1620} 1621