tune2fs.c revision a86d55da8bf41335aa2fc5ec16ca63859d918e81
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 "config.h" 31#include <fcntl.h> 32#include <grp.h> 33#ifdef HAVE_GETOPT_H 34#include <getopt.h> 35#else 36extern char *optarg; 37extern int optind; 38#endif 39#include <pwd.h> 40#include <stdio.h> 41#ifdef HAVE_STDLIB_H 42#include <stdlib.h> 43#endif 44#include <string.h> 45#include <time.h> 46#include <unistd.h> 47#include <sys/types.h> 48#include <libgen.h> 49#include <limits.h> 50 51#include "ext2fs/ext2_fs.h" 52#include "ext2fs/ext2fs.h" 53#include "et/com_err.h" 54#include "uuid/uuid.h" 55#include "e2p/e2p.h" 56#include "jfs_user.h" 57#include "util.h" 58#include "blkid/blkid.h" 59#include "quota/mkquota.h" 60 61#include "../version.h" 62#include "nls-enable.h" 63 64#define QOPT_ENABLE (1) 65#define QOPT_DISABLE (-1) 66 67extern int ask_yn(const char *string, int def); 68 69const char *program_name = "tune2fs"; 70char *device_name; 71char *new_label, *new_last_mounted, *new_UUID; 72char *io_options; 73static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; 74static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; 75static int I_flag; 76static int clear_mmp; 77static time_t last_check_time; 78static int print_label; 79static int max_mount_count, mount_count, mount_flags; 80static unsigned long interval; 81static blk64_t reserved_blocks; 82static double reserved_ratio; 83static unsigned long resgid, resuid; 84static unsigned short errors; 85static int open_flag; 86static char *features_cmd; 87static char *mntopts_cmd; 88static int stride, stripe_width; 89static int stride_set, stripe_width_set; 90static char *extended_cmd; 91static unsigned long new_inode_size; 92static char *ext_mount_opts; 93static int usrquota, grpquota; 94 95int journal_size, journal_flags; 96char *journal_device; 97 98static struct list_head blk_move_list; 99 100struct blk_move { 101 struct list_head list; 102 blk64_t old_loc; 103 blk64_t new_loc; 104}; 105 106 107static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); 108 109#ifdef CONFIG_BUILD_FINDFS 110void do_findfs(int argc, char **argv); 111#endif 112 113static void usage(void) 114{ 115 fprintf(stderr, 116 _("Usage: %s [-c max_mounts_count] [-e errors_behavior] " 117 "[-g group]\n" 118 "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n" 119 "\t[-m reserved_blocks_percent] " 120 "[-o [^]mount_options[,...]] [-p mmp_update_interval]\n" 121 "\t[-r reserved_blocks_count] [-u user] [-C mount_count] " 122 "[-L volume_label]\n" 123 "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n" 124 "\t[-E extended-option[,...]] [-T last_check_time] " 125 "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name); 126 exit(1); 127} 128 129static __u32 ok_features[3] = { 130 /* Compat */ 131 EXT3_FEATURE_COMPAT_HAS_JOURNAL | 132 EXT2_FEATURE_COMPAT_DIR_INDEX, 133 /* Incompat */ 134 EXT2_FEATURE_INCOMPAT_FILETYPE | 135 EXT3_FEATURE_INCOMPAT_EXTENTS | 136 EXT4_FEATURE_INCOMPAT_FLEX_BG | 137 EXT4_FEATURE_INCOMPAT_MMP, 138 /* R/O compat */ 139 EXT2_FEATURE_RO_COMPAT_LARGE_FILE | 140 EXT4_FEATURE_RO_COMPAT_HUGE_FILE| 141 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| 142 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| 143 EXT4_FEATURE_RO_COMPAT_GDT_CSUM | 144 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | 145 EXT4_FEATURE_RO_COMPAT_QUOTA 146}; 147 148static __u32 clear_ok_features[3] = { 149 /* Compat */ 150 EXT3_FEATURE_COMPAT_HAS_JOURNAL | 151 EXT2_FEATURE_COMPAT_RESIZE_INODE | 152 EXT2_FEATURE_COMPAT_DIR_INDEX, 153 /* Incompat */ 154 EXT2_FEATURE_INCOMPAT_FILETYPE | 155 EXT4_FEATURE_INCOMPAT_FLEX_BG | 156 EXT4_FEATURE_INCOMPAT_MMP, 157 /* R/O compat */ 158 EXT2_FEATURE_RO_COMPAT_LARGE_FILE | 159 EXT4_FEATURE_RO_COMPAT_HUGE_FILE| 160 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| 161 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| 162 EXT4_FEATURE_RO_COMPAT_GDT_CSUM | 163 EXT4_FEATURE_RO_COMPAT_QUOTA 164}; 165 166/* 167 * Remove an external journal from the filesystem 168 */ 169static int remove_journal_device(ext2_filsys fs) 170{ 171 char *journal_path; 172 ext2_filsys jfs; 173 char buf[1024]; 174 journal_superblock_t *jsb; 175 int i, nr_users; 176 errcode_t retval; 177 int commit_remove_journal = 0; 178 io_manager io_ptr; 179 180 if (f_flag) 181 commit_remove_journal = 1; /* force removal even if error */ 182 183 uuid_unparse(fs->super->s_journal_uuid, buf); 184 journal_path = blkid_get_devname(NULL, "UUID", buf); 185 186 if (!journal_path) { 187 journal_path = 188 ext2fs_find_block_device(fs->super->s_journal_dev); 189 if (!journal_path) 190 goto no_valid_journal; 191 } 192 193#ifdef CONFIG_TESTIO_DEBUG 194 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 195 io_ptr = test_io_manager; 196 test_io_backing_manager = unix_io_manager; 197 } else 198#endif 199 io_ptr = unix_io_manager; 200 retval = ext2fs_open(journal_path, EXT2_FLAG_RW| 201 EXT2_FLAG_JOURNAL_DEV_OK, 0, 202 fs->blocksize, io_ptr, &jfs); 203 if (retval) { 204 com_err(program_name, retval, 205 _("while trying to open external journal")); 206 goto no_valid_journal; 207 } 208 if (!(jfs->super->s_feature_incompat & 209 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { 210 fprintf(stderr, _("%s is not a journal device.\n"), 211 journal_path); 212 goto no_valid_journal; 213 } 214 215 /* Get the journal superblock */ 216 if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) { 217 com_err(program_name, retval, 218 _("while reading journal superblock")); 219 goto no_valid_journal; 220 } 221 222 jsb = (journal_superblock_t *) buf; 223 if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) || 224 (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) { 225 fputs(_("Journal superblock not found!\n"), stderr); 226 goto no_valid_journal; 227 } 228 229 /* Find the filesystem UUID */ 230 nr_users = ntohl(jsb->s_nr_users); 231 for (i = 0; i < nr_users; i++) { 232 if (memcmp(fs->super->s_uuid, &jsb->s_users[i * 16], 16) == 0) 233 break; 234 } 235 if (i >= nr_users) { 236 fputs(_("Filesystem's UUID not found on journal device.\n"), 237 stderr); 238 commit_remove_journal = 1; 239 goto no_valid_journal; 240 } 241 nr_users--; 242 for (i = 0; i < nr_users; i++) 243 memcpy(&jsb->s_users[i * 16], &jsb->s_users[(i + 1) * 16], 16); 244 jsb->s_nr_users = htonl(nr_users); 245 246 /* Write back the journal superblock */ 247 if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) { 248 com_err(program_name, retval, 249 "while writing journal superblock."); 250 goto no_valid_journal; 251 } 252 253 commit_remove_journal = 1; 254 255no_valid_journal: 256 if (commit_remove_journal == 0) { 257 fputs(_("Cannot locate journal device. It was NOT removed\n" 258 "Use -f option to remove missing journal device.\n"), 259 stderr); 260 return 1; 261 } 262 fs->super->s_journal_dev = 0; 263 uuid_clear(fs->super->s_journal_uuid); 264 ext2fs_mark_super_dirty(fs); 265 fputs(_("Journal removed\n"), stdout); 266 free(journal_path); 267 268 return 0; 269} 270 271/* Helper function for remove_journal_inode */ 272static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, 273 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 274 blk64_t ref_block EXT2FS_ATTR((unused)), 275 int ref_offset EXT2FS_ATTR((unused)), 276 void *private EXT2FS_ATTR((unused))) 277{ 278 blk64_t block; 279 int group; 280 281 block = *blocknr; 282 ext2fs_unmark_block_bitmap2(fs->block_map, block); 283 group = ext2fs_group_of_blk2(fs, block); 284 ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1); 285 ext2fs_group_desc_csum_set(fs, group); 286 ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs)); 287 return 0; 288} 289 290/* 291 * Remove the journal inode from the filesystem 292 */ 293static errcode_t remove_journal_inode(ext2_filsys fs) 294{ 295 struct ext2_inode inode; 296 errcode_t retval; 297 ino_t ino = fs->super->s_journal_inum; 298 299 retval = ext2fs_read_inode(fs, ino, &inode); 300 if (retval) { 301 com_err(program_name, retval, 302 _("while reading journal inode")); 303 return retval; 304 } 305 if (ino == EXT2_JOURNAL_INO) { 306 retval = ext2fs_read_bitmaps(fs); 307 if (retval) { 308 com_err(program_name, retval, 309 _("while reading bitmaps")); 310 return retval; 311 } 312 retval = ext2fs_block_iterate3(fs, ino, 313 BLOCK_FLAG_READ_ONLY, NULL, 314 release_blocks_proc, NULL); 315 if (retval) { 316 com_err(program_name, retval, 317 _("while clearing journal inode")); 318 return retval; 319 } 320 memset(&inode, 0, sizeof(inode)); 321 ext2fs_mark_bb_dirty(fs); 322 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 323 } else 324 inode.i_flags &= ~EXT2_IMMUTABLE_FL; 325 retval = ext2fs_write_inode(fs, ino, &inode); 326 if (retval) { 327 com_err(program_name, retval, 328 _("while writing journal inode")); 329 return retval; 330 } 331 fs->super->s_journal_inum = 0; 332 ext2fs_mark_super_dirty(fs); 333 334 return 0; 335} 336 337/* 338 * Update the default mount options 339 */ 340static int update_mntopts(ext2_filsys fs, char *mntopts) 341{ 342 struct ext2_super_block *sb = fs->super; 343 344 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) { 345 fprintf(stderr, _("Invalid mount option set: %s\n"), 346 mntopts); 347 return 1; 348 } 349 ext2fs_mark_super_dirty(fs); 350 351 return 0; 352} 353 354static void request_fsck_afterwards(ext2_filsys fs) 355{ 356 static int requested = 0; 357 358 if (requested++) 359 return; 360 fs->super->s_state &= ~EXT2_VALID_FS; 361 printf("\n%s\n", _(please_fsck)); 362 if (mount_flags & EXT2_MF_READONLY) 363 printf(_("(and reboot afterwards!)\n")); 364} 365 366/* 367 * Update the feature set as provided by the user. 368 */ 369static int update_feature_set(ext2_filsys fs, char *features) 370{ 371 struct ext2_super_block *sb = fs->super; 372 struct ext2_group_desc *gd; 373 __u32 old_features[3]; 374 int i, type_err; 375 unsigned int mask_err; 376 377#define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \ 378 ((&sb->s_feature_compat)[(type)] & (mask))) 379#define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \ 380 !((&sb->s_feature_compat)[(type)] & (mask))) 381#define FEATURE_CHANGED(type, mask) ((mask) & \ 382 (old_features[(type)] ^ (&sb->s_feature_compat)[(type)])) 383 384 old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat; 385 old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat; 386 old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat; 387 388 if (e2p_edit_feature2(features, &sb->s_feature_compat, 389 ok_features, clear_ok_features, 390 &type_err, &mask_err)) { 391 if (!mask_err) 392 fprintf(stderr, 393 _("Invalid filesystem option set: %s\n"), 394 features); 395 else if (type_err & E2P_FEATURE_NEGATE_FLAG) 396 fprintf(stderr, _("Clearing filesystem feature '%s' " 397 "not supported.\n"), 398 e2p_feature2string(type_err & 399 E2P_FEATURE_TYPE_MASK, 400 mask_err)); 401 else 402 fprintf(stderr, _("Setting filesystem feature '%s' " 403 "not supported.\n"), 404 e2p_feature2string(type_err, mask_err)); 405 return 1; 406 } 407 408 if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 409 if ((mount_flags & EXT2_MF_MOUNTED) && 410 !(mount_flags & EXT2_MF_READONLY)) { 411 fputs(_("The has_journal feature may only be " 412 "cleared when the filesystem is\n" 413 "unmounted or mounted " 414 "read-only.\n"), stderr); 415 return 1; 416 } 417 if (sb->s_feature_incompat & 418 EXT3_FEATURE_INCOMPAT_RECOVER) { 419 fputs(_("The needs_recovery flag is set. " 420 "Please run e2fsck before clearing\n" 421 "the has_journal flag.\n"), stderr); 422 return 1; 423 } 424 if (sb->s_journal_inum) { 425 if (remove_journal_inode(fs)) 426 return 1; 427 } 428 if (sb->s_journal_dev) { 429 if (remove_journal_device(fs)) 430 return 1; 431 } 432 } 433 if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) { 434 int error; 435 436 if ((mount_flags & EXT2_MF_MOUNTED) || 437 (mount_flags & EXT2_MF_READONLY)) { 438 fputs(_("The multiple mount protection feature can't\n" 439 "be set if the filesystem is mounted or\n" 440 "read-only.\n"), stderr); 441 return 1; 442 } 443 444 error = ext2fs_mmp_init(fs); 445 if (error) { 446 fputs(_("\nError while enabling multiple mount " 447 "protection feature."), stderr); 448 return 1; 449 } 450 451 /* 452 * We want to update group desc with the new free blocks count 453 */ 454 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 455 456 printf(_("Multiple mount protection has been enabled " 457 "with update interval %ds.\n"), 458 sb->s_mmp_update_interval); 459 } 460 461 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) { 462 int error; 463 464 if (mount_flags & EXT2_MF_READONLY) { 465 fputs(_("The multiple mount protection feature cannot\n" 466 "be disabled if the filesystem is readonly.\n"), 467 stderr); 468 return 1; 469 } 470 471 error = ext2fs_read_bitmaps(fs); 472 if (error) { 473 fputs(_("Error while reading bitmaps\n"), stderr); 474 return 1; 475 } 476 477 error = ext2fs_mmp_read(fs, sb->s_mmp_block, NULL); 478 if (error) { 479 struct mmp_struct *mmp_cmp = fs->mmp_cmp; 480 481 if (error == EXT2_ET_MMP_MAGIC_INVALID) 482 printf(_("Magic number in MMP block does not " 483 "match. expected: %x, actual: %x\n"), 484 EXT4_MMP_MAGIC, mmp_cmp->mmp_magic); 485 else 486 com_err(program_name, error, 487 _("while reading MMP block.")); 488 goto mmp_error; 489 } 490 491 /* We need to force out the group descriptors as well */ 492 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 493 ext2fs_block_alloc_stats(fs, sb->s_mmp_block, -1); 494mmp_error: 495 sb->s_mmp_block = 0; 496 sb->s_mmp_update_interval = 0; 497 } 498 499 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 500 /* 501 * If adding a journal flag, let the create journal 502 * code below handle setting the flag and creating the 503 * journal. We supply a default size if necessary. 504 */ 505 if (!journal_size) 506 journal_size = -1; 507 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; 508 } 509 510 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) { 511 if (!sb->s_def_hash_version) 512 sb->s_def_hash_version = EXT2_HASH_HALF_MD4; 513 if (uuid_is_null((unsigned char *) sb->s_hash_seed)) 514 uuid_generate((unsigned char *) sb->s_hash_seed); 515 } 516 517 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { 518 if (ext2fs_check_desc(fs)) { 519 fputs(_("Clearing the flex_bg flag would " 520 "cause the the filesystem to be\n" 521 "inconsistent.\n"), stderr); 522 return 1; 523 } 524 } 525 526 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 527 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 528 if ((mount_flags & EXT2_MF_MOUNTED) && 529 !(mount_flags & EXT2_MF_READONLY)) { 530 fputs(_("The huge_file feature may only be " 531 "cleared when the filesystem is\n" 532 "unmounted or mounted " 533 "read-only.\n"), stderr); 534 return 1; 535 } 536 } 537 538 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT, 539 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 540 for (i = 0; i < fs->group_desc_count; i++) { 541 gd = ext2fs_group_desc(fs, fs->group_desc, i); 542 gd->bg_itable_unused = 0; 543 gd->bg_flags = EXT2_BG_INODE_ZEROED; 544 ext2fs_group_desc_csum_set(fs, i); 545 } 546 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 547 } 548 549 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 550 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 551 for (i = 0; i < fs->group_desc_count; i++) { 552 gd = ext2fs_group_desc(fs, fs->group_desc, i); 553 if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) { 554 /* 555 * XXX what we really should do is zap 556 * uninitialized inode tables instead. 557 */ 558 request_fsck_afterwards(fs); 559 break; 560 } 561 gd->bg_itable_unused = 0; 562 gd->bg_flags = 0; 563 gd->bg_checksum = 0; 564 } 565 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 566 } 567 568 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT, 569 EXT4_FEATURE_RO_COMPAT_QUOTA)) { 570 /* 571 * Set the Q_flag here and handle the quota options in the code 572 * below. 573 */ 574 if (!Q_flag) { 575 Q_flag = 1; 576 /* Enable both user quota and group quota by default */ 577 usrquota = QOPT_ENABLE; 578 grpquota = QOPT_ENABLE; 579 } 580 sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA; 581 } 582 583 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 584 EXT4_FEATURE_RO_COMPAT_QUOTA)) { 585 /* 586 * Set the Q_flag here and handle the quota options in the code 587 * below. 588 */ 589 if (Q_flag) 590 fputs(_("\nWarning: '^quota' option overrides '-Q'" 591 "arguments.\n"), stderr); 592 Q_flag = 1; 593 /* Disable both user quota and group quota by default */ 594 usrquota = QOPT_DISABLE; 595 grpquota = QOPT_DISABLE; 596 } 597 598 if (sb->s_rev_level == EXT2_GOOD_OLD_REV && 599 (sb->s_feature_compat || sb->s_feature_ro_compat || 600 sb->s_feature_incompat)) 601 ext2fs_update_dynamic_rev(fs); 602 603 if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, 604 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || 605 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 606 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || 607 FEATURE_CHANGED(E2P_FEATURE_INCOMPAT, 608 EXT2_FEATURE_INCOMPAT_FILETYPE) || 609 FEATURE_CHANGED(E2P_FEATURE_COMPAT, 610 EXT2_FEATURE_COMPAT_RESIZE_INODE) || 611 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, 612 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) 613 request_fsck_afterwards(fs); 614 615 if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) || 616 (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) || 617 (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat)) 618 ext2fs_mark_super_dirty(fs); 619 620 return 0; 621} 622 623/* 624 * Add a journal to the filesystem. 625 */ 626static int add_journal(ext2_filsys fs) 627{ 628 unsigned long journal_blocks; 629 errcode_t retval; 630 ext2_filsys jfs; 631 io_manager io_ptr; 632 633 if (fs->super->s_feature_compat & 634 EXT3_FEATURE_COMPAT_HAS_JOURNAL) { 635 fputs(_("The filesystem already has a journal.\n"), stderr); 636 goto err; 637 } 638 if (journal_device) { 639 check_plausibility(journal_device); 640 check_mount(journal_device, 0, _("journal")); 641#ifdef CONFIG_TESTIO_DEBUG 642 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 643 io_ptr = test_io_manager; 644 test_io_backing_manager = unix_io_manager; 645 } else 646#endif 647 io_ptr = unix_io_manager; 648 retval = ext2fs_open(journal_device, EXT2_FLAG_RW| 649 EXT2_FLAG_JOURNAL_DEV_OK, 0, 650 fs->blocksize, io_ptr, &jfs); 651 if (retval) { 652 com_err(program_name, retval, 653 _("\n\twhile trying to open journal on %s\n"), 654 journal_device); 655 goto err; 656 } 657 printf(_("Creating journal on device %s: "), 658 journal_device); 659 fflush(stdout); 660 661 retval = ext2fs_add_journal_device(fs, jfs); 662 ext2fs_close(jfs); 663 if (retval) { 664 com_err(program_name, retval, 665 _("while adding filesystem to journal on %s"), 666 journal_device); 667 goto err; 668 } 669 fputs(_("done\n"), stdout); 670 } else if (journal_size) { 671 fputs(_("Creating journal inode: "), stdout); 672 fflush(stdout); 673 journal_blocks = figure_journal_size(journal_size, fs); 674 675 retval = ext2fs_add_journal_inode(fs, journal_blocks, 676 journal_flags); 677 if (retval) { 678 fprintf(stderr, "\n"); 679 com_err(program_name, retval, 680 _("\n\twhile trying to create journal file")); 681 return retval; 682 } else 683 fputs(_("done\n"), stdout); 684 /* 685 * If the filesystem wasn't mounted, we need to force 686 * the block group descriptors out. 687 */ 688 if ((mount_flags & EXT2_MF_MOUNTED) == 0) 689 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 690 } 691 print_check_message(fs->super->s_max_mnt_count, 692 fs->super->s_checkinterval); 693 return 0; 694 695err: 696 free(journal_device); 697 return 1; 698} 699 700void handle_quota_options(ext2_filsys fs) 701{ 702 quota_ctx_t qctx; 703 errcode_t retval; 704 ext2_ino_t qf_ino; 705 706 if (!usrquota && !grpquota) 707 /* Nothing to do. */ 708 return; 709 710 quota_init_context(&qctx, fs, -1); 711 712 if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) { 713 if ((qf_ino = quota_file_exists(fs, USRQUOTA, QFMT_VFS_V1)) > 0) 714 quota_set_sb_inum(fs, qf_ino, USRQUOTA); 715 else 716 quota_write_inode(qctx, USRQUOTA); 717 } else if (usrquota == QOPT_DISABLE) { 718 quota_remove_inode(fs, USRQUOTA); 719 } 720 721 if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) { 722 if ((qf_ino = quota_file_exists(fs, GRPQUOTA, QFMT_VFS_V1)) > 0) 723 quota_set_sb_inum(fs, qf_ino, GRPQUOTA); 724 else 725 quota_write_inode(qctx, GRPQUOTA); 726 } else if (grpquota == QOPT_DISABLE) { 727 quota_remove_inode(fs, GRPQUOTA); 728 } 729 730 quota_release_context(&qctx); 731 732 if ((usrquota == QOPT_ENABLE) || (grpquota == QOPT_ENABLE)) { 733 fs->super->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_QUOTA; 734 ext2fs_mark_super_dirty(fs); 735 } else if ((usrquota == QOPT_DISABLE) && (grpquota == QOPT_DISABLE)) { 736 fs->super->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA; 737 ext2fs_mark_super_dirty(fs); 738 } 739 740 return; 741} 742 743void parse_quota_opts(const char *opts) 744{ 745 char *buf, *token, *next, *p, *arg; 746 int len; 747 748 len = strlen(opts); 749 buf = malloc(len+1); 750 if (!buf) { 751 fputs(_("Couldn't allocate memory to parse quota " 752 "options!\n"), stderr); 753 exit(1); 754 } 755 strcpy(buf, opts); 756 for (token = buf; token && *token; token = next) { 757 p = strchr(token, ','); 758 next = 0; 759 if (p) { 760 *p = 0; 761 next = p+1; 762 } 763 764 if (strcmp(token, "usrquota") == 0) { 765 usrquota = QOPT_ENABLE; 766 } else if (strcmp(token, "^usrquota") == 0) { 767 usrquota = QOPT_DISABLE; 768 } else if (strcmp(token, "grpquota") == 0) { 769 grpquota = QOPT_ENABLE; 770 } else if (strcmp(token, "^grpquota") == 0) { 771 grpquota = QOPT_DISABLE; 772 } else { 773 fputs(_("\nBad quota options specified.\n\n" 774 "Following valid quota options are available " 775 "(pass by separating with comma):\n" 776 "\t[^]usrquota\n" 777 "\t[^]grpquota\n" 778 "\n\n"), stderr); 779 free(buf); 780 exit(1); 781 } 782 } 783 free(buf); 784} 785 786 787 788static void parse_e2label_options(int argc, char ** argv) 789{ 790 if ((argc < 2) || (argc > 3)) { 791 fputs(_("Usage: e2label device [newlabel]\n"), stderr); 792 exit(1); 793 } 794 io_options = strchr(argv[1], '?'); 795 if (io_options) 796 *io_options++ = 0; 797 device_name = blkid_get_devname(NULL, argv[1], NULL); 798 if (!device_name) { 799 com_err("e2label", 0, _("Unable to resolve '%s'"), 800 argv[1]); 801 exit(1); 802 } 803 open_flag = EXT2_FLAG_JOURNAL_DEV_OK; 804 if (argc == 3) { 805 open_flag |= EXT2_FLAG_RW; 806 L_flag = 1; 807 new_label = argv[2]; 808 } else 809 print_label++; 810} 811 812static time_t parse_time(char *str) 813{ 814 struct tm ts; 815 816 if (strcmp(str, "now") == 0) { 817 return (time(0)); 818 } 819 memset(&ts, 0, sizeof(ts)); 820#ifdef HAVE_STRPTIME 821 strptime(str, "%Y%m%d%H%M%S", &ts); 822#else 823 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, 824 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); 825 ts.tm_year -= 1900; 826 ts.tm_mon -= 1; 827 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || 828 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || 829 ts.tm_min > 59 || ts.tm_sec > 61) 830 ts.tm_mday = 0; 831#endif 832 if (ts.tm_mday == 0) { 833 com_err(program_name, 0, 834 _("Couldn't parse date/time specifier: %s"), 835 str); 836 usage(); 837 } 838 ts.tm_isdst = -1; 839 return (mktime(&ts)); 840} 841 842static void parse_tune2fs_options(int argc, char **argv) 843{ 844 int c; 845 char *tmp; 846 struct group *gr; 847 struct passwd *pw; 848 849 open_flag = 0; 850 851 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); 852 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:Q:T:U:")) != EOF) 853 switch (c) { 854 case 'c': 855 max_mount_count = strtol(optarg, &tmp, 0); 856 if (*tmp || max_mount_count > 16000) { 857 com_err(program_name, 0, 858 _("bad mounts count - %s"), 859 optarg); 860 usage(); 861 } 862 if (max_mount_count == 0) 863 max_mount_count = -1; 864 c_flag = 1; 865 open_flag = EXT2_FLAG_RW; 866 break; 867 case 'C': 868 mount_count = strtoul(optarg, &tmp, 0); 869 if (*tmp || mount_count > 16000) { 870 com_err(program_name, 0, 871 _("bad mounts count - %s"), 872 optarg); 873 usage(); 874 } 875 C_flag = 1; 876 open_flag = EXT2_FLAG_RW; 877 break; 878 case 'e': 879 if (strcmp(optarg, "continue") == 0) 880 errors = EXT2_ERRORS_CONTINUE; 881 else if (strcmp(optarg, "remount-ro") == 0) 882 errors = EXT2_ERRORS_RO; 883 else if (strcmp(optarg, "panic") == 0) 884 errors = EXT2_ERRORS_PANIC; 885 else { 886 com_err(program_name, 0, 887 _("bad error behavior - %s"), 888 optarg); 889 usage(); 890 } 891 e_flag = 1; 892 open_flag = EXT2_FLAG_RW; 893 break; 894 case 'E': 895 extended_cmd = optarg; 896 open_flag |= EXT2_FLAG_RW; 897 break; 898 case 'f': /* Force */ 899 f_flag = 1; 900 break; 901 case 'g': 902 resgid = strtoul(optarg, &tmp, 0); 903 if (*tmp) { 904 gr = getgrnam(optarg); 905 if (gr == NULL) 906 tmp = optarg; 907 else { 908 resgid = gr->gr_gid; 909 *tmp = 0; 910 } 911 } 912 if (*tmp) { 913 com_err(program_name, 0, 914 _("bad gid/group name - %s"), 915 optarg); 916 usage(); 917 } 918 g_flag = 1; 919 open_flag = EXT2_FLAG_RW; 920 break; 921 case 'i': 922 interval = strtoul(optarg, &tmp, 0); 923 switch (*tmp) { 924 case 's': 925 tmp++; 926 break; 927 case '\0': 928 case 'd': 929 case 'D': /* days */ 930 interval *= 86400; 931 if (*tmp != '\0') 932 tmp++; 933 break; 934 case 'm': 935 case 'M': /* months! */ 936 interval *= 86400 * 30; 937 tmp++; 938 break; 939 case 'w': 940 case 'W': /* weeks */ 941 interval *= 86400 * 7; 942 tmp++; 943 break; 944 } 945 if (*tmp) { 946 com_err(program_name, 0, 947 _("bad interval - %s"), optarg); 948 usage(); 949 } 950 i_flag = 1; 951 open_flag = EXT2_FLAG_RW; 952 break; 953 case 'j': 954 if (!journal_size) 955 journal_size = -1; 956 open_flag = EXT2_FLAG_RW; 957 break; 958 case 'J': 959 parse_journal_opts(optarg); 960 open_flag = EXT2_FLAG_RW; 961 break; 962 case 'l': 963 l_flag = 1; 964 break; 965 case 'L': 966 new_label = optarg; 967 L_flag = 1; 968 open_flag |= EXT2_FLAG_RW | 969 EXT2_FLAG_JOURNAL_DEV_OK; 970 break; 971 case 'm': 972 reserved_ratio = strtod(optarg, &tmp); 973 if (*tmp || reserved_ratio > 50 || 974 reserved_ratio < 0) { 975 com_err(program_name, 0, 976 _("bad reserved block ratio - %s"), 977 optarg); 978 usage(); 979 } 980 m_flag = 1; 981 open_flag = EXT2_FLAG_RW; 982 break; 983 case 'M': 984 new_last_mounted = optarg; 985 M_flag = 1; 986 open_flag = EXT2_FLAG_RW; 987 break; 988 case 'o': 989 if (mntopts_cmd) { 990 com_err(program_name, 0, 991 _("-o may only be specified once")); 992 usage(); 993 } 994 mntopts_cmd = optarg; 995 open_flag = EXT2_FLAG_RW; 996 break; 997 case 'O': 998 if (features_cmd) { 999 com_err(program_name, 0, 1000 _("-O may only be specified once")); 1001 usage(); 1002 } 1003 features_cmd = optarg; 1004 open_flag = EXT2_FLAG_RW; 1005 break; 1006 case 'Q': 1007 Q_flag = 1; 1008 parse_quota_opts(optarg); 1009 open_flag = EXT2_FLAG_RW; 1010 break; 1011 case 'r': 1012 reserved_blocks = strtoul(optarg, &tmp, 0); 1013 if (*tmp) { 1014 com_err(program_name, 0, 1015 _("bad reserved blocks count - %s"), 1016 optarg); 1017 usage(); 1018 } 1019 r_flag = 1; 1020 open_flag = EXT2_FLAG_RW; 1021 break; 1022 case 's': /* Deprecated */ 1023 s_flag = atoi(optarg); 1024 open_flag = EXT2_FLAG_RW; 1025 break; 1026 case 'T': 1027 T_flag = 1; 1028 last_check_time = parse_time(optarg); 1029 open_flag = EXT2_FLAG_RW; 1030 break; 1031 case 'u': 1032 resuid = strtoul(optarg, &tmp, 0); 1033 if (*tmp) { 1034 pw = getpwnam(optarg); 1035 if (pw == NULL) 1036 tmp = optarg; 1037 else { 1038 resuid = pw->pw_uid; 1039 *tmp = 0; 1040 } 1041 } 1042 if (*tmp) { 1043 com_err(program_name, 0, 1044 _("bad uid/user name - %s"), 1045 optarg); 1046 usage(); 1047 } 1048 u_flag = 1; 1049 open_flag = EXT2_FLAG_RW; 1050 break; 1051 case 'U': 1052 new_UUID = optarg; 1053 U_flag = 1; 1054 open_flag = EXT2_FLAG_RW | 1055 EXT2_FLAG_JOURNAL_DEV_OK; 1056 break; 1057 case 'I': 1058 new_inode_size = strtoul(optarg, &tmp, 0); 1059 if (*tmp) { 1060 com_err(program_name, 0, 1061 _("bad inode size - %s"), 1062 optarg); 1063 usage(); 1064 } 1065 if (!((new_inode_size & 1066 (new_inode_size - 1)) == 0)) { 1067 com_err(program_name, 0, 1068 _("Inode size must be a " 1069 "power of two- %s"), 1070 optarg); 1071 usage(); 1072 } 1073 open_flag = EXT2_FLAG_RW; 1074 I_flag = 1; 1075 break; 1076 default: 1077 usage(); 1078 } 1079 if (optind < argc - 1 || optind == argc) 1080 usage(); 1081 if (!open_flag && !l_flag) 1082 usage(); 1083 io_options = strchr(argv[optind], '?'); 1084 if (io_options) 1085 *io_options++ = 0; 1086 device_name = blkid_get_devname(NULL, argv[optind], NULL); 1087 if (!device_name) { 1088 com_err("tune2fs", 0, _("Unable to resolve '%s'"), 1089 argv[optind]); 1090 exit(1); 1091 } 1092} 1093 1094#ifdef CONFIG_BUILD_FINDFS 1095void do_findfs(int argc, char **argv) 1096{ 1097 char *dev; 1098 1099 if ((argc != 2) || 1100 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { 1101 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n"); 1102 exit(2); 1103 } 1104 dev = blkid_get_devname(NULL, argv[1], NULL); 1105 if (!dev) { 1106 com_err("findfs", 0, _("Unable to resolve '%s'"), 1107 argv[1]); 1108 exit(1); 1109 } 1110 puts(dev); 1111 exit(0); 1112} 1113#endif 1114 1115static int parse_extended_opts(ext2_filsys fs, const char *opts) 1116{ 1117 char *buf, *token, *next, *p, *arg; 1118 int len, hash_alg; 1119 int r_usage = 0; 1120 1121 len = strlen(opts); 1122 buf = malloc(len+1); 1123 if (!buf) { 1124 fprintf(stderr, 1125 _("Couldn't allocate memory to parse options!\n")); 1126 return 1; 1127 } 1128 strcpy(buf, opts); 1129 for (token = buf; token && *token; token = next) { 1130 p = strchr(token, ','); 1131 next = 0; 1132 if (p) { 1133 *p = 0; 1134 next = p+1; 1135 } 1136 arg = strchr(token, '='); 1137 if (arg) { 1138 *arg = 0; 1139 arg++; 1140 } 1141 if (strcmp(token, "clear-mmp") == 0 || 1142 strcmp(token, "clear_mmp") == 0) { 1143 clear_mmp = 1; 1144 } else if (strcmp(token, "mmp_update_interval") == 0) { 1145 unsigned long interval; 1146 if (!arg) { 1147 r_usage++; 1148 continue; 1149 } 1150 interval = strtoul(arg, &p, 0); 1151 if (*p) { 1152 fprintf(stderr, 1153 _("Invalid mmp_update_interval: %s\n"), 1154 arg); 1155 r_usage++; 1156 continue; 1157 } 1158 if (interval == 0) { 1159 interval = EXT4_MMP_UPDATE_INTERVAL; 1160 } else if (interval > EXT4_MMP_MAX_UPDATE_INTERVAL) { 1161 fprintf(stderr, 1162 _("mmp_update_interval too big: %lu\n"), 1163 interval); 1164 r_usage++; 1165 continue; 1166 } 1167 printf(P_("Setting multiple mount protection update " 1168 "interval to %lu second\n", 1169 "Setting multiple mount protection update " 1170 "interval to %lu seconds\n", interval), 1171 interval); 1172 fs->super->s_mmp_update_interval = interval; 1173 ext2fs_mark_super_dirty(fs); 1174 } else if (!strcmp(token, "test_fs")) { 1175 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; 1176 printf("Setting test filesystem flag\n"); 1177 ext2fs_mark_super_dirty(fs); 1178 } else if (!strcmp(token, "^test_fs")) { 1179 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS; 1180 printf("Clearing test filesystem flag\n"); 1181 ext2fs_mark_super_dirty(fs); 1182 } else if (strcmp(token, "stride") == 0) { 1183 if (!arg) { 1184 r_usage++; 1185 continue; 1186 } 1187 stride = strtoul(arg, &p, 0); 1188 if (*p) { 1189 fprintf(stderr, 1190 _("Invalid RAID stride: %s\n"), 1191 arg); 1192 r_usage++; 1193 continue; 1194 } 1195 stride_set = 1; 1196 } else if (strcmp(token, "stripe-width") == 0 || 1197 strcmp(token, "stripe_width") == 0) { 1198 if (!arg) { 1199 r_usage++; 1200 continue; 1201 } 1202 stripe_width = strtoul(arg, &p, 0); 1203 if (*p) { 1204 fprintf(stderr, 1205 _("Invalid RAID stripe-width: %s\n"), 1206 arg); 1207 r_usage++; 1208 continue; 1209 } 1210 stripe_width_set = 1; 1211 } else if (strcmp(token, "hash_alg") == 0 || 1212 strcmp(token, "hash-alg") == 0) { 1213 if (!arg) { 1214 r_usage++; 1215 continue; 1216 } 1217 hash_alg = e2p_string2hash(arg); 1218 if (hash_alg < 0) { 1219 fprintf(stderr, 1220 _("Invalid hash algorithm: %s\n"), 1221 arg); 1222 r_usage++; 1223 continue; 1224 } 1225 fs->super->s_def_hash_version = hash_alg; 1226 printf(_("Setting default hash algorithm " 1227 "to %s (%d)\n"), 1228 arg, hash_alg); 1229 ext2fs_mark_super_dirty(fs); 1230 } else if (!strcmp(token, "mount_opts")) { 1231 if (!arg) { 1232 r_usage++; 1233 continue; 1234 } 1235 if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) { 1236 fprintf(stderr, 1237 "Extended mount options too long\n"); 1238 continue; 1239 } 1240 ext_mount_opts = strdup(arg); 1241 } else 1242 r_usage++; 1243 } 1244 if (r_usage) { 1245 fprintf(stderr, _("\nBad options specified.\n\n" 1246 "Extended options are separated by commas, " 1247 "and may take an argument which\n" 1248 "\tis set off by an equals ('=') sign.\n\n" 1249 "Valid extended options are:\n" 1250 "\tclear_mmp\n" 1251 "\thash_alg=<hash algorithm>\n" 1252 "\tmount_opts=<extended default mount options>\n" 1253 "\tstride=<RAID per-disk chunk size in blocks>\n" 1254 "\tstripe_width=<RAID stride*data disks in blocks>\n" 1255 "\ttest_fs\n" 1256 "\t^test_fs\n")); 1257 free(buf); 1258 return 1; 1259 } 1260 free(buf); 1261 1262 return 0; 1263} 1264 1265/* 1266 * Fill in the block bitmap bmap with the information regarding the 1267 * blocks to be moved 1268 */ 1269static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp, 1270 ext2fs_block_bitmap bmap) 1271{ 1272 dgrp_t i; 1273 int retval; 1274 ext2_badblocks_list bb_list = 0; 1275 blk64_t j, needed_blocks = 0; 1276 blk64_t start_blk, end_blk; 1277 1278 retval = ext2fs_read_bb_inode(fs, &bb_list); 1279 if (retval) 1280 return retval; 1281 1282 for (i = 0; i < fs->group_desc_count; i++) { 1283 start_blk = ext2fs_inode_table_loc(fs, i) + 1284 fs->inode_blocks_per_group; 1285 1286 end_blk = ext2fs_inode_table_loc(fs, i) + 1287 new_ino_blks_per_grp; 1288 1289 for (j = start_blk; j < end_blk; j++) { 1290 if (ext2fs_test_block_bitmap2(fs->block_map, j)) { 1291 /* 1292 * IF the block is a bad block we fail 1293 */ 1294 if (ext2fs_badblocks_list_test(bb_list, j)) { 1295 ext2fs_badblocks_list_free(bb_list); 1296 return ENOSPC; 1297 } 1298 1299 ext2fs_mark_block_bitmap2(bmap, j); 1300 } else { 1301 /* 1302 * We are going to use this block for 1303 * inode table. So mark them used. 1304 */ 1305 ext2fs_mark_block_bitmap2(fs->block_map, j); 1306 } 1307 } 1308 needed_blocks += end_blk - start_blk; 1309 } 1310 1311 ext2fs_badblocks_list_free(bb_list); 1312 if (needed_blocks > ext2fs_free_blocks_count(fs->super)) 1313 return ENOSPC; 1314 1315 return 0; 1316} 1317 1318static int ext2fs_is_meta_block(ext2_filsys fs, blk_t blk) 1319{ 1320 dgrp_t group; 1321 group = ext2fs_group_of_blk(fs, blk); 1322 if (ext2fs_block_bitmap_loc(fs, group) == blk) 1323 return 1; 1324 if (ext2fs_inode_bitmap_loc(fs, group) == blk) 1325 return 1; 1326 return 0; 1327} 1328 1329static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk_t blk) 1330{ 1331 blk_t start_blk, end_blk; 1332 start_blk = fs->super->s_first_data_block + 1333 EXT2_BLOCKS_PER_GROUP(fs->super) * group; 1334 /* 1335 * We cannot get new block beyond end_blk for for the last block group 1336 * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group 1337 */ 1338 end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super); 1339 if (blk >= start_blk && blk <= end_blk) 1340 return 1; 1341 return 0; 1342} 1343 1344static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap) 1345{ 1346 1347 char *buf; 1348 dgrp_t group = 0; 1349 errcode_t retval; 1350 int meta_data = 0; 1351 blk64_t blk, new_blk, goal; 1352 struct blk_move *bmv; 1353 1354 retval = ext2fs_get_mem(fs->blocksize, &buf); 1355 if (retval) 1356 return retval; 1357 1358 for (new_blk = blk = fs->super->s_first_data_block; 1359 blk < ext2fs_blocks_count(fs->super); blk++) { 1360 if (!ext2fs_test_block_bitmap2(bmap, blk)) 1361 continue; 1362 1363 if (ext2fs_is_meta_block(fs, blk)) { 1364 /* 1365 * If the block is mapping a fs meta data block 1366 * like group desc/block bitmap/inode bitmap. We 1367 * should find a block in the same group and fix 1368 * the respective fs metadata pointers. Otherwise 1369 * fail 1370 */ 1371 group = ext2fs_group_of_blk(fs, blk); 1372 goal = ext2fs_group_first_block2(fs, group); 1373 meta_data = 1; 1374 1375 } else { 1376 goal = new_blk; 1377 } 1378 retval = ext2fs_new_block2(fs, goal, NULL, &new_blk); 1379 if (retval) 1380 goto err_out; 1381 1382 /* new fs meta data block should be in the same group */ 1383 if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) { 1384 retval = ENOSPC; 1385 goto err_out; 1386 } 1387 1388 /* Mark this block as allocated */ 1389 ext2fs_mark_block_bitmap2(fs->block_map, new_blk); 1390 1391 /* Add it to block move list */ 1392 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv); 1393 if (retval) 1394 goto err_out; 1395 1396 bmv->old_loc = blk; 1397 bmv->new_loc = new_blk; 1398 1399 list_add(&(bmv->list), &blk_move_list); 1400 1401 retval = io_channel_read_blk64(fs->io, blk, 1, buf); 1402 if (retval) 1403 goto err_out; 1404 1405 retval = io_channel_write_blk64(fs->io, new_blk, 1, buf); 1406 if (retval) 1407 goto err_out; 1408 } 1409 1410err_out: 1411 ext2fs_free_mem(&buf); 1412 return retval; 1413} 1414 1415static blk64_t translate_block(blk64_t blk) 1416{ 1417 struct list_head *entry; 1418 struct blk_move *bmv; 1419 1420 list_for_each(entry, &blk_move_list) { 1421 bmv = list_entry(entry, struct blk_move, list); 1422 if (bmv->old_loc == blk) 1423 return bmv->new_loc; 1424 } 1425 1426 return 0; 1427} 1428 1429static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)), 1430 blk64_t *block_nr, 1431 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1432 blk64_t ref_block EXT2FS_ATTR((unused)), 1433 int ref_offset EXT2FS_ATTR((unused)), 1434 void *priv_data) 1435{ 1436 int ret = 0; 1437 blk64_t new_blk; 1438 ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data; 1439 1440 if (!ext2fs_test_block_bitmap2(bmap, *block_nr)) 1441 return 0; 1442 new_blk = translate_block(*block_nr); 1443 if (new_blk) { 1444 *block_nr = new_blk; 1445 /* 1446 * This will force the ext2fs_write_inode in the iterator 1447 */ 1448 ret |= BLOCK_CHANGED; 1449 } 1450 1451 return ret; 1452} 1453 1454static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap) 1455{ 1456 errcode_t retval = 0; 1457 ext2_ino_t ino; 1458 blk64_t blk; 1459 char *block_buf = 0; 1460 struct ext2_inode inode; 1461 ext2_inode_scan scan = NULL; 1462 1463 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf); 1464 if (retval) 1465 return retval; 1466 1467 retval = ext2fs_open_inode_scan(fs, 0, &scan); 1468 if (retval) 1469 goto err_out; 1470 1471 while (1) { 1472 retval = ext2fs_get_next_inode(scan, &ino, &inode); 1473 if (retval) 1474 goto err_out; 1475 1476 if (!ino) 1477 break; 1478 1479 if (inode.i_links_count == 0) 1480 continue; /* inode not in use */ 1481 1482 /* FIXME!! 1483 * If we end up modifying the journal inode 1484 * the sb->s_jnl_blocks will differ. But a 1485 * subsequent e2fsck fixes that. 1486 * Do we need to fix this ?? 1487 */ 1488 1489 if (ext2fs_file_acl_block(fs, &inode) && 1490 ext2fs_test_block_bitmap2(bmap, 1491 ext2fs_file_acl_block(fs, &inode))) { 1492 blk = translate_block(ext2fs_file_acl_block(fs, 1493 &inode)); 1494 if (!blk) 1495 continue; 1496 1497 ext2fs_file_acl_block_set(fs, &inode, blk); 1498 1499 /* 1500 * Write the inode to disk so that inode table 1501 * resizing can work 1502 */ 1503 retval = ext2fs_write_inode(fs, ino, &inode); 1504 if (retval) 1505 goto err_out; 1506 } 1507 1508 if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) 1509 continue; 1510 1511 retval = ext2fs_block_iterate3(fs, ino, 0, block_buf, 1512 process_block, bmap); 1513 if (retval) 1514 goto err_out; 1515 1516 } 1517 1518err_out: 1519 ext2fs_free_mem(&block_buf); 1520 1521 return retval; 1522} 1523 1524/* 1525 * We need to scan for inode and block bitmaps that may need to be 1526 * moved. This can take place if the filesystem was formatted for 1527 * RAID arrays using the mke2fs's extended option "stride". 1528 */ 1529static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap) 1530{ 1531 dgrp_t i; 1532 blk_t blk, new_blk; 1533 1534 for (i = 0; i < fs->group_desc_count; i++) { 1535 blk = ext2fs_block_bitmap_loc(fs, i); 1536 if (ext2fs_test_block_bitmap2(bmap, blk)) { 1537 new_blk = translate_block(blk); 1538 if (!new_blk) 1539 continue; 1540 ext2fs_block_bitmap_loc_set(fs, i, new_blk); 1541 } 1542 1543 blk = ext2fs_inode_bitmap_loc(fs, i); 1544 if (ext2fs_test_block_bitmap2(bmap, blk)) { 1545 new_blk = translate_block(blk); 1546 if (!new_blk) 1547 continue; 1548 ext2fs_inode_bitmap_loc_set(fs, i, new_blk); 1549 } 1550 } 1551 return 0; 1552} 1553 1554static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size) 1555{ 1556 dgrp_t i; 1557 blk64_t blk; 1558 errcode_t retval; 1559 int new_ino_blks_per_grp; 1560 unsigned int j; 1561 char *old_itable = NULL, *new_itable = NULL; 1562 char *tmp_old_itable = NULL, *tmp_new_itable = NULL; 1563 unsigned long old_ino_size; 1564 int old_itable_size, new_itable_size; 1565 1566 old_itable_size = fs->inode_blocks_per_group * fs->blocksize; 1567 old_ino_size = EXT2_INODE_SIZE(fs->super); 1568 1569 new_ino_blks_per_grp = ext2fs_div_ceil( 1570 EXT2_INODES_PER_GROUP(fs->super) * 1571 new_ino_size, 1572 fs->blocksize); 1573 1574 new_itable_size = new_ino_blks_per_grp * fs->blocksize; 1575 1576 retval = ext2fs_get_mem(old_itable_size, &old_itable); 1577 if (retval) 1578 return retval; 1579 1580 retval = ext2fs_get_mem(new_itable_size, &new_itable); 1581 if (retval) 1582 goto err_out; 1583 1584 tmp_old_itable = old_itable; 1585 tmp_new_itable = new_itable; 1586 1587 for (i = 0; i < fs->group_desc_count; i++) { 1588 blk = ext2fs_inode_table_loc(fs, i); 1589 retval = io_channel_read_blk64(fs->io, blk, 1590 fs->inode_blocks_per_group, old_itable); 1591 if (retval) 1592 goto err_out; 1593 1594 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) { 1595 memcpy(new_itable, old_itable, old_ino_size); 1596 1597 memset(new_itable+old_ino_size, 0, 1598 new_ino_size - old_ino_size); 1599 1600 new_itable += new_ino_size; 1601 old_itable += old_ino_size; 1602 } 1603 1604 /* reset the pointer */ 1605 old_itable = tmp_old_itable; 1606 new_itable = tmp_new_itable; 1607 1608 retval = io_channel_write_blk64(fs->io, blk, 1609 new_ino_blks_per_grp, new_itable); 1610 if (retval) 1611 goto err_out; 1612 } 1613 1614 /* Update the meta data */ 1615 fs->inode_blocks_per_group = new_ino_blks_per_grp; 1616 fs->super->s_inode_size = new_ino_size; 1617 1618err_out: 1619 if (old_itable) 1620 ext2fs_free_mem(&old_itable); 1621 1622 if (new_itable) 1623 ext2fs_free_mem(&new_itable); 1624 1625 return retval; 1626} 1627 1628static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs) 1629{ 1630 blk64_t blk; 1631 ext2_ino_t ino; 1632 unsigned int group = 0; 1633 unsigned int count = 0; 1634 int total_free = 0; 1635 int group_free = 0; 1636 1637 /* 1638 * First calculate the block statistics 1639 */ 1640 for (blk = fs->super->s_first_data_block; 1641 blk < ext2fs_blocks_count(fs->super); blk++) { 1642 if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) { 1643 group_free++; 1644 total_free++; 1645 } 1646 count++; 1647 if ((count == fs->super->s_blocks_per_group) || 1648 (blk == ext2fs_blocks_count(fs->super)-1)) { 1649 ext2fs_bg_free_blocks_count_set(fs, group++, 1650 group_free); 1651 count = 0; 1652 group_free = 0; 1653 } 1654 } 1655 total_free = EXT2FS_C2B(fs, total_free); 1656 ext2fs_free_blocks_count_set(fs->super, total_free); 1657 1658 /* 1659 * Next, calculate the inode statistics 1660 */ 1661 group_free = 0; 1662 total_free = 0; 1663 count = 0; 1664 group = 0; 1665 1666 /* Protect loop from wrap-around if s_inodes_count maxed */ 1667 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) { 1668 if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) { 1669 group_free++; 1670 total_free++; 1671 } 1672 count++; 1673 if ((count == fs->super->s_inodes_per_group) || 1674 (ino == fs->super->s_inodes_count)) { 1675 ext2fs_bg_free_inodes_count_set(fs, group++, 1676 group_free); 1677 count = 0; 1678 group_free = 0; 1679 } 1680 } 1681 fs->super->s_free_inodes_count = total_free; 1682 ext2fs_mark_super_dirty(fs); 1683 return 0; 1684} 1685 1686#define list_for_each_safe(pos, pnext, head) \ 1687 for (pos = (head)->next, pnext = pos->next; pos != (head); \ 1688 pos = pnext, pnext = pos->next) 1689 1690static void free_blk_move_list(void) 1691{ 1692 struct list_head *entry, *tmp; 1693 struct blk_move *bmv; 1694 1695 list_for_each_safe(entry, tmp, &blk_move_list) { 1696 bmv = list_entry(entry, struct blk_move, list); 1697 list_del(entry); 1698 ext2fs_free_mem(&bmv); 1699 } 1700 return; 1701} 1702 1703static int resize_inode(ext2_filsys fs, unsigned long new_size) 1704{ 1705 errcode_t retval; 1706 int new_ino_blks_per_grp; 1707 ext2fs_block_bitmap bmap; 1708 1709 retval = ext2fs_read_inode_bitmap(fs); 1710 if (retval) { 1711 fputs(_("Failed to read inode bitmap\n"), stderr); 1712 return retval; 1713 } 1714 retval = ext2fs_read_block_bitmap(fs); 1715 if (retval) { 1716 fputs(_("Failed to read block bitmap\n"), stderr); 1717 return retval; 1718 } 1719 INIT_LIST_HEAD(&blk_move_list); 1720 1721 1722 new_ino_blks_per_grp = ext2fs_div_ceil( 1723 EXT2_INODES_PER_GROUP(fs->super)* 1724 new_size, 1725 fs->blocksize); 1726 1727 /* We may change the file system. 1728 * Mark the file system as invalid so that 1729 * the user is prompted to run fsck. 1730 */ 1731 fs->super->s_state &= ~EXT2_VALID_FS; 1732 1733 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"), 1734 &bmap); 1735 if (retval) { 1736 fputs(_("Failed to allocate block bitmap when " 1737 "increasing inode size\n"), stderr); 1738 return retval; 1739 } 1740 retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap); 1741 if (retval) { 1742 fputs(_("Not enough space to increase inode size \n"), stderr); 1743 goto err_out; 1744 } 1745 retval = move_block(fs, bmap); 1746 if (retval) { 1747 fputs(_("Failed to relocate blocks during inode resize \n"), 1748 stderr); 1749 goto err_out; 1750 } 1751 retval = inode_scan_and_fix(fs, bmap); 1752 if (retval) 1753 goto err_out_undo; 1754 1755 retval = group_desc_scan_and_fix(fs, bmap); 1756 if (retval) 1757 goto err_out_undo; 1758 1759 retval = expand_inode_table(fs, new_size); 1760 if (retval) 1761 goto err_out_undo; 1762 1763 ext2fs_calculate_summary_stats(fs); 1764 1765 fs->super->s_state |= EXT2_VALID_FS; 1766 /* mark super block and block bitmap as dirty */ 1767 ext2fs_mark_super_dirty(fs); 1768 ext2fs_mark_bb_dirty(fs); 1769 1770err_out: 1771 free_blk_move_list(); 1772 ext2fs_free_block_bitmap(bmap); 1773 1774 return retval; 1775 1776err_out_undo: 1777 free_blk_move_list(); 1778 ext2fs_free_block_bitmap(bmap); 1779 fputs(_("Error in resizing the inode size.\n" 1780 "Run e2undo to undo the " 1781 "file system changes. \n"), stderr); 1782 1783 return retval; 1784} 1785 1786static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) 1787{ 1788 errcode_t retval = 0; 1789 const char *tdb_dir; 1790 char *tdb_file; 1791 char *dev_name, *tmp_name; 1792 1793#if 0 /* FIXME!! */ 1794 /* 1795 * Configuration via a conf file would be 1796 * nice 1797 */ 1798 profile_get_string(profile, "scratch_files", 1799 "directory", 0, 0, 1800 &tdb_dir); 1801#endif 1802 tmp_name = strdup(name); 1803 if (!tmp_name) { 1804 alloc_fn_fail: 1805 com_err(program_name, ENOMEM, 1806 _("Couldn't allocate memory for tdb filename\n")); 1807 return ENOMEM; 1808 } 1809 dev_name = basename(tmp_name); 1810 1811 tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); 1812 if (!tdb_dir) 1813 tdb_dir = "/var/lib/e2fsprogs"; 1814 1815 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || 1816 access(tdb_dir, W_OK)) 1817 return 0; 1818 1819 tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); 1820 if (!tdb_file) 1821 goto alloc_fn_fail; 1822 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); 1823 1824 if (!access(tdb_file, F_OK)) { 1825 if (unlink(tdb_file) < 0) { 1826 retval = errno; 1827 com_err(program_name, retval, 1828 _("while trying to delete %s"), 1829 tdb_file); 1830 free(tdb_file); 1831 return retval; 1832 } 1833 } 1834 1835 set_undo_io_backing_manager(*io_ptr); 1836 *io_ptr = undo_io_manager; 1837 set_undo_io_backup_file(tdb_file); 1838 printf(_("To undo the tune2fs operation please run " 1839 "the command\n e2undo %s %s\n\n"), 1840 tdb_file, name); 1841 free(tdb_file); 1842 free(tmp_name); 1843 return retval; 1844} 1845 1846int main(int argc, char **argv) 1847{ 1848 errcode_t retval; 1849 ext2_filsys fs; 1850 struct ext2_super_block *sb; 1851 io_manager io_ptr, io_ptr_orig = NULL; 1852 int rc = 0; 1853 1854#ifdef ENABLE_NLS 1855 setlocale(LC_MESSAGES, ""); 1856 setlocale(LC_CTYPE, ""); 1857 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1858 textdomain(NLS_CAT_NAME); 1859 set_com_err_gettext(gettext); 1860#endif 1861 if (argc && *argv) 1862 program_name = *argv; 1863 add_error_table(&et_ext2_error_table); 1864 1865#ifdef CONFIG_BUILD_FINDFS 1866 if (strcmp(get_progname(argv[0]), "findfs") == 0) 1867 do_findfs(argc, argv); 1868#endif 1869 if (strcmp(get_progname(argv[0]), "e2label") == 0) 1870 parse_e2label_options(argc, argv); 1871 else 1872 parse_tune2fs_options(argc, argv); 1873 1874#ifdef CONFIG_TESTIO_DEBUG 1875 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) { 1876 io_ptr = test_io_manager; 1877 test_io_backing_manager = unix_io_manager; 1878 } else 1879#endif 1880 io_ptr = unix_io_manager; 1881 1882retry_open: 1883 if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag) 1884 open_flag |= EXT2_FLAG_SKIP_MMP; 1885 1886 open_flag |= EXT2_FLAG_64BITS; 1887 1888 /* keep the filesystem struct around to dump MMP data */ 1889 open_flag |= EXT2_FLAG_NOFREE_ON_ERROR; 1890 1891 retval = ext2fs_open2(device_name, io_options, open_flag, 1892 0, 0, io_ptr, &fs); 1893 if (retval) { 1894 com_err(program_name, retval, 1895 _("while trying to open %s"), 1896 device_name); 1897 if (retval == EXT2_ET_MMP_FSCK_ON || 1898 retval == EXT2_ET_MMP_UNKNOWN_SEQ) 1899 dump_mmp_msg(fs->mmp_buf, 1900 _("If you are sure the filesystem " 1901 "is not in use on any node, run:\n" 1902 "'tune2fs -f -E clear_mmp {device}'\n")); 1903 else if (retval == EXT2_ET_MMP_FAILED) 1904 dump_mmp_msg(fs->mmp_buf, NULL); 1905 else if (retval == EXT2_ET_MMP_MAGIC_INVALID) 1906 fprintf(stderr, 1907 _("MMP block magic is bad. Try to fix it by " 1908 "running:\n'e2fsck -f %s'\n"), device_name); 1909 else if (retval != EXT2_ET_MMP_FAILED) 1910 fprintf(stderr, 1911 _("Couldn't find valid filesystem superblock.\n")); 1912 1913 ext2fs_free(fs); 1914 exit(1); 1915 } 1916 1917 if (I_flag && !io_ptr_orig) { 1918 /* 1919 * Check the inode size is right so we can issue an 1920 * error message and bail before setting up the tdb 1921 * file. 1922 */ 1923 if (new_inode_size == EXT2_INODE_SIZE(fs->super)) { 1924 fprintf(stderr, _("The inode size is already %lu\n"), 1925 new_inode_size); 1926 rc = 1; 1927 goto closefs; 1928 } 1929 if (new_inode_size < EXT2_INODE_SIZE(fs->super)) { 1930 fprintf(stderr, _("Shrinking the inode size is " 1931 "not supported\n")); 1932 rc = 1; 1933 goto closefs; 1934 } 1935 1936 /* 1937 * If inode resize is requested use the 1938 * Undo I/O manager 1939 */ 1940 io_ptr_orig = io_ptr; 1941 retval = tune2fs_setup_tdb(device_name, &io_ptr); 1942 if (retval) { 1943 rc = 1; 1944 goto closefs; 1945 } 1946 if (io_ptr != io_ptr_orig) { 1947 ext2fs_close(fs); 1948 goto retry_open; 1949 } 1950 } 1951 1952 sb = fs->super; 1953 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1954 1955 if (print_label) { 1956 /* For e2label emulation */ 1957 printf("%.*s\n", (int) sizeof(sb->s_volume_name), 1958 sb->s_volume_name); 1959 remove_error_table(&et_ext2_error_table); 1960 goto closefs; 1961 } 1962 1963 retval = ext2fs_check_if_mounted(device_name, &mount_flags); 1964 if (retval) { 1965 com_err("ext2fs_check_if_mount", retval, 1966 _("while determining whether %s is mounted."), 1967 device_name); 1968 rc = 1; 1969 goto closefs; 1970 } 1971 /* Normally we only need to write out the superblock */ 1972 fs->flags |= EXT2_FLAG_SUPER_ONLY; 1973 1974 if (c_flag) { 1975 sb->s_max_mnt_count = max_mount_count; 1976 ext2fs_mark_super_dirty(fs); 1977 printf(_("Setting maximal mount count to %d\n"), 1978 max_mount_count); 1979 } 1980 if (C_flag) { 1981 sb->s_mnt_count = mount_count; 1982 ext2fs_mark_super_dirty(fs); 1983 printf(_("Setting current mount count to %d\n"), mount_count); 1984 } 1985 if (e_flag) { 1986 sb->s_errors = errors; 1987 ext2fs_mark_super_dirty(fs); 1988 printf(_("Setting error behavior to %d\n"), errors); 1989 } 1990 if (g_flag) { 1991 sb->s_def_resgid = resgid; 1992 ext2fs_mark_super_dirty(fs); 1993 printf(_("Setting reserved blocks gid to %lu\n"), resgid); 1994 } 1995 if (i_flag) { 1996 if (interval >= (1ULL << 32)) { 1997 com_err(program_name, 0, 1998 _("interval between checks is too big (%lu)"), 1999 interval); 2000 rc = 1; 2001 goto closefs; 2002 } 2003 sb->s_checkinterval = interval; 2004 ext2fs_mark_super_dirty(fs); 2005 printf(_("Setting interval between checks to %lu seconds\n"), 2006 interval); 2007 } 2008 if (m_flag) { 2009 ext2fs_r_blocks_count_set(sb, reserved_ratio * 2010 ext2fs_blocks_count(sb) / 100.0); 2011 ext2fs_mark_super_dirty(fs); 2012 printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"), 2013 reserved_ratio, ext2fs_r_blocks_count(sb)); 2014 } 2015 if (r_flag) { 2016 if (reserved_blocks > ext2fs_blocks_count(sb)/2) { 2017 com_err(program_name, 0, 2018 _("reserved blocks count is too big (%llu)"), 2019 reserved_blocks); 2020 rc = 1; 2021 goto closefs; 2022 } 2023 ext2fs_r_blocks_count_set(sb, reserved_blocks); 2024 ext2fs_mark_super_dirty(fs); 2025 printf(_("Setting reserved blocks count to %llu\n"), 2026 reserved_blocks); 2027 } 2028 if (s_flag == 1) { 2029 if (sb->s_feature_ro_compat & 2030 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) 2031 fputs(_("\nThe filesystem already has sparse " 2032 "superblocks.\n"), stderr); 2033 else { 2034 sb->s_feature_ro_compat |= 2035 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; 2036 sb->s_state &= ~EXT2_VALID_FS; 2037 ext2fs_mark_super_dirty(fs); 2038 printf(_("\nSparse superblock flag set. %s"), 2039 _(please_fsck)); 2040 } 2041 } 2042 if (s_flag == 0) { 2043 fputs(_("\nClearing the sparse superflag not supported.\n"), 2044 stderr); 2045 rc = 1; 2046 goto closefs; 2047 } 2048 if (T_flag) { 2049 sb->s_lastcheck = last_check_time; 2050 ext2fs_mark_super_dirty(fs); 2051 printf(_("Setting time filesystem last checked to %s\n"), 2052 ctime(&last_check_time)); 2053 } 2054 if (u_flag) { 2055 sb->s_def_resuid = resuid; 2056 ext2fs_mark_super_dirty(fs); 2057 printf(_("Setting reserved blocks uid to %lu\n"), resuid); 2058 } 2059 if (L_flag) { 2060 if (strlen(new_label) > sizeof(sb->s_volume_name)) 2061 fputs(_("Warning: label too long, truncating.\n"), 2062 stderr); 2063 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); 2064 strncpy(sb->s_volume_name, new_label, 2065 sizeof(sb->s_volume_name)); 2066 ext2fs_mark_super_dirty(fs); 2067 } 2068 if (M_flag) { 2069 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); 2070 strncpy(sb->s_last_mounted, new_last_mounted, 2071 sizeof(sb->s_last_mounted)); 2072 ext2fs_mark_super_dirty(fs); 2073 } 2074 if (mntopts_cmd) { 2075 rc = update_mntopts(fs, mntopts_cmd); 2076 if (rc) 2077 goto closefs; 2078 } 2079 if (features_cmd) { 2080 rc = update_feature_set(fs, features_cmd); 2081 if (rc) 2082 goto closefs; 2083 } 2084 if (extended_cmd) { 2085 rc = parse_extended_opts(fs, extended_cmd); 2086 if (rc) 2087 goto closefs; 2088 if (clear_mmp && !f_flag) { 2089 fputs(_("Error in using clear_mmp. " 2090 "It must be used with -f\n"), 2091 stderr); 2092 goto closefs; 2093 } 2094 } 2095 if (clear_mmp) { 2096 rc = ext2fs_mmp_clear(fs); 2097 goto closefs; 2098 } 2099 if (journal_size || journal_device) { 2100 rc = add_journal(fs); 2101 if (rc) 2102 goto closefs; 2103 } 2104 2105 if (Q_flag) { 2106 if (mount_flags & EXT2_MF_MOUNTED) { 2107 fputs(_("The quota feature may only be changed when " 2108 "the filesystem is unmounted.\n"), stderr); 2109 rc = 1; 2110 goto closefs; 2111 } 2112 handle_quota_options(fs); 2113 } 2114 2115 if (U_flag) { 2116 int set_csum = 0; 2117 dgrp_t i; 2118 2119 if (sb->s_feature_ro_compat & 2120 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { 2121 /* 2122 * Determine if the block group checksums are 2123 * correct so we know whether or not to set 2124 * them later on. 2125 */ 2126 for (i = 0; i < fs->group_desc_count; i++) 2127 if (!ext2fs_group_desc_csum_verify(fs, i)) 2128 break; 2129 if (i >= fs->group_desc_count) 2130 set_csum = 1; 2131 } 2132 if ((strcasecmp(new_UUID, "null") == 0) || 2133 (strcasecmp(new_UUID, "clear") == 0)) { 2134 uuid_clear(sb->s_uuid); 2135 } else if (strcasecmp(new_UUID, "time") == 0) { 2136 uuid_generate_time(sb->s_uuid); 2137 } else if (strcasecmp(new_UUID, "random") == 0) { 2138 uuid_generate(sb->s_uuid); 2139 } else if (uuid_parse(new_UUID, sb->s_uuid)) { 2140 com_err(program_name, 0, _("Invalid UUID format\n")); 2141 rc = 1; 2142 goto closefs; 2143 } 2144 if (set_csum) { 2145 for (i = 0; i < fs->group_desc_count; i++) 2146 ext2fs_group_desc_csum_set(fs, i); 2147 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 2148 } 2149 ext2fs_mark_super_dirty(fs); 2150 } 2151 if (I_flag) { 2152 if (mount_flags & EXT2_MF_MOUNTED) { 2153 fputs(_("The inode size may only be " 2154 "changed when the filesystem is " 2155 "unmounted.\n"), stderr); 2156 rc = 1; 2157 goto closefs; 2158 } 2159 if (fs->super->s_feature_incompat & 2160 EXT4_FEATURE_INCOMPAT_FLEX_BG) { 2161 fputs(_("Changing the inode size not supported for " 2162 "filesystems with the flex_bg\n" 2163 "feature enabled.\n"), 2164 stderr); 2165 rc = 1; 2166 goto closefs; 2167 } 2168 /* 2169 * We want to update group descriptor also 2170 * with the new free inode count 2171 */ 2172 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 2173 if (resize_inode(fs, new_inode_size) == 0) { 2174 printf(_("Setting inode size %lu\n"), 2175 new_inode_size); 2176 } else { 2177 printf(_("Failed to change inode size\n")); 2178 rc = 1; 2179 goto closefs; 2180 } 2181 } 2182 2183 if (l_flag) 2184 list_super(sb); 2185 if (stride_set) { 2186 sb->s_raid_stride = stride; 2187 ext2fs_mark_super_dirty(fs); 2188 printf(_("Setting stride size to %d\n"), stride); 2189 } 2190 if (stripe_width_set) { 2191 sb->s_raid_stripe_width = stripe_width; 2192 ext2fs_mark_super_dirty(fs); 2193 printf(_("Setting stripe width to %d\n"), stripe_width); 2194 } 2195 if (ext_mount_opts) { 2196 strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts, 2197 sizeof(fs->super->s_mount_opts)); 2198 fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0; 2199 ext2fs_mark_super_dirty(fs); 2200 printf(_("Setting extended default mount options to '%s'\n"), 2201 ext_mount_opts); 2202 free(ext_mount_opts); 2203 } 2204 free(device_name); 2205 remove_error_table(&et_ext2_error_table); 2206 2207closefs: 2208 if (rc) { 2209 ext2fs_mmp_stop(fs); 2210 exit(1); 2211 } 2212 2213 return (ext2fs_close(fs) ? 1 : 0); 2214} 2215