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