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 int main(int argc, char **argv) 1881 { 1882 errcode_t retval; 1883 ext2_filsys fs; 1884 struct ext2_super_block *sb; 1885 io_manager io_ptr, io_ptr_orig = NULL; 1886 int rc = 0; 1887 1888 #ifdef ENABLE_NLS 1889 setlocale(LC_MESSAGES, ""); 1890 setlocale(LC_CTYPE, ""); 1891 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1892 textdomain(NLS_CAT_NAME); 1893 set_com_err_gettext(gettext); 1894 #endif 1895 if (argc && *argv) 1896 program_name = *argv; 1897 add_error_table(&et_ext2_error_table); 1898 1899 #ifdef CONFIG_BUILD_FINDFS 1900 if (strcmp(get_progname(argv[0]), "findfs") == 0) 1901 do_findfs(argc, argv); 1902 #endif 1903 if (strcmp(get_progname(argv[0]), "e2label") == 0) 1904 parse_e2label_options(argc, argv); 1905 else 1906 parse_tune2fs_options(argc, argv); 1907 1908 #ifdef CONFIG_TESTIO_DEBUG 1909 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) { 1910 io_ptr = test_io_manager; 1911 test_io_backing_manager = unix_io_manager; 1912 } else 1913 #endif 1914 io_ptr = unix_io_manager; 1915 1916 retry_open: 1917 if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag) 1918 open_flag |= EXT2_FLAG_SKIP_MMP; 1919 1920 open_flag |= EXT2_FLAG_64BITS; 1921 1922 /* keep the filesystem struct around to dump MMP data */ 1923 open_flag |= EXT2_FLAG_NOFREE_ON_ERROR; 1924 1925 retval = ext2fs_open2(device_name, io_options, open_flag, 1926 0, 0, io_ptr, &fs); 1927 if (retval) { 1928 com_err(program_name, retval, 1929 _("while trying to open %s"), 1930 device_name); 1931 if (retval == EXT2_ET_MMP_FSCK_ON || 1932 retval == EXT2_ET_MMP_UNKNOWN_SEQ) 1933 dump_mmp_msg(fs->mmp_buf, 1934 _("If you are sure the filesystem " 1935 "is not in use on any node, run:\n" 1936 "'tune2fs -f -E clear_mmp {device}'\n")); 1937 else if (retval == EXT2_ET_MMP_FAILED) 1938 dump_mmp_msg(fs->mmp_buf, NULL); 1939 else if (retval == EXT2_ET_MMP_MAGIC_INVALID) 1940 fprintf(stderr, 1941 _("MMP block magic is bad. Try to fix it by " 1942 "running:\n'e2fsck -f %s'\n"), device_name); 1943 else if (retval != EXT2_ET_MMP_FAILED) 1944 fprintf(stderr, "%s", 1945 _("Couldn't find valid filesystem superblock.\n")); 1946 1947 ext2fs_free(fs); 1948 exit(1); 1949 } 1950 fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; 1951 1952 if (I_flag && !io_ptr_orig) { 1953 /* 1954 * Check the inode size is right so we can issue an 1955 * error message and bail before setting up the tdb 1956 * file. 1957 */ 1958 if (new_inode_size == EXT2_INODE_SIZE(fs->super)) { 1959 fprintf(stderr, _("The inode size is already %lu\n"), 1960 new_inode_size); 1961 rc = 1; 1962 goto closefs; 1963 } 1964 if (new_inode_size < EXT2_INODE_SIZE(fs->super)) { 1965 fprintf(stderr, "%s", 1966 _("Shrinking inode size is not supported\n")); 1967 rc = 1; 1968 goto closefs; 1969 } 1970 if (new_inode_size > fs->blocksize) { 1971 fprintf(stderr, _("Invalid inode size %lu (max %d)\n"), 1972 new_inode_size, fs->blocksize); 1973 rc = 1; 1974 goto closefs; 1975 } 1976 1977 /* 1978 * If inode resize is requested use the 1979 * Undo I/O manager 1980 */ 1981 io_ptr_orig = io_ptr; 1982 retval = tune2fs_setup_tdb(device_name, &io_ptr); 1983 if (retval) { 1984 rc = 1; 1985 goto closefs; 1986 } 1987 if (io_ptr != io_ptr_orig) { 1988 ext2fs_close(fs); 1989 goto retry_open; 1990 } 1991 } 1992 1993 sb = fs->super; 1994 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1995 1996 if (print_label) { 1997 /* For e2label emulation */ 1998 printf("%.*s\n", (int) sizeof(sb->s_volume_name), 1999 sb->s_volume_name); 2000 remove_error_table(&et_ext2_error_table); 2001 goto closefs; 2002 } 2003 2004 retval = ext2fs_check_if_mounted(device_name, &mount_flags); 2005 if (retval) { 2006 com_err("ext2fs_check_if_mount", retval, 2007 _("while determining whether %s is mounted."), 2008 device_name); 2009 rc = 1; 2010 goto closefs; 2011 } 2012 /* Normally we only need to write out the superblock */ 2013 fs->flags |= EXT2_FLAG_SUPER_ONLY; 2014 2015 if (c_flag) { 2016 sb->s_max_mnt_count = max_mount_count; 2017 ext2fs_mark_super_dirty(fs); 2018 printf(_("Setting maximal mount count to %d\n"), 2019 max_mount_count); 2020 } 2021 if (C_flag) { 2022 sb->s_mnt_count = mount_count; 2023 ext2fs_mark_super_dirty(fs); 2024 printf(_("Setting current mount count to %d\n"), mount_count); 2025 } 2026 if (e_flag) { 2027 sb->s_errors = errors; 2028 ext2fs_mark_super_dirty(fs); 2029 printf(_("Setting error behavior to %d\n"), errors); 2030 } 2031 if (g_flag) { 2032 sb->s_def_resgid = resgid; 2033 ext2fs_mark_super_dirty(fs); 2034 printf(_("Setting reserved blocks gid to %lu\n"), resgid); 2035 } 2036 if (i_flag) { 2037 if (interval >= (1ULL << 32)) { 2038 com_err(program_name, 0, 2039 _("interval between checks is too big (%lu)"), 2040 interval); 2041 rc = 1; 2042 goto closefs; 2043 } 2044 sb->s_checkinterval = interval; 2045 ext2fs_mark_super_dirty(fs); 2046 printf(_("Setting interval between checks to %lu seconds\n"), 2047 interval); 2048 } 2049 if (m_flag) { 2050 ext2fs_r_blocks_count_set(sb, reserved_ratio * 2051 ext2fs_blocks_count(sb) / 100.0); 2052 ext2fs_mark_super_dirty(fs); 2053 printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"), 2054 reserved_ratio, ext2fs_r_blocks_count(sb)); 2055 } 2056 if (r_flag) { 2057 if (reserved_blocks > ext2fs_blocks_count(sb)/2) { 2058 com_err(program_name, 0, 2059 _("reserved blocks count is too big (%llu)"), 2060 reserved_blocks); 2061 rc = 1; 2062 goto closefs; 2063 } 2064 ext2fs_r_blocks_count_set(sb, reserved_blocks); 2065 ext2fs_mark_super_dirty(fs); 2066 printf(_("Setting reserved blocks count to %llu\n"), 2067 reserved_blocks); 2068 } 2069 if (s_flag == 1) { 2070 if (sb->s_feature_ro_compat & 2071 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) 2072 fputs(_("\nThe filesystem already has sparse " 2073 "superblocks.\n"), stderr); 2074 else { 2075 sb->s_feature_ro_compat |= 2076 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; 2077 sb->s_state &= ~EXT2_VALID_FS; 2078 ext2fs_mark_super_dirty(fs); 2079 printf(_("\nSparse superblock flag set. %s"), 2080 _(please_fsck)); 2081 } 2082 } 2083 if (s_flag == 0) { 2084 fputs(_("\nClearing the sparse superflag not supported.\n"), 2085 stderr); 2086 rc = 1; 2087 goto closefs; 2088 } 2089 if (T_flag) { 2090 sb->s_lastcheck = last_check_time; 2091 ext2fs_mark_super_dirty(fs); 2092 printf(_("Setting time filesystem last checked to %s\n"), 2093 ctime(&last_check_time)); 2094 } 2095 if (u_flag) { 2096 sb->s_def_resuid = resuid; 2097 ext2fs_mark_super_dirty(fs); 2098 printf(_("Setting reserved blocks uid to %lu\n"), resuid); 2099 } 2100 if (L_flag) { 2101 if (strlen(new_label) > sizeof(sb->s_volume_name)) 2102 fputs(_("Warning: label too long, truncating.\n"), 2103 stderr); 2104 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); 2105 strncpy(sb->s_volume_name, new_label, 2106 sizeof(sb->s_volume_name)); 2107 ext2fs_mark_super_dirty(fs); 2108 } 2109 if (M_flag) { 2110 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); 2111 strncpy(sb->s_last_mounted, new_last_mounted, 2112 sizeof(sb->s_last_mounted)); 2113 ext2fs_mark_super_dirty(fs); 2114 } 2115 if (mntopts_cmd) { 2116 rc = update_mntopts(fs, mntopts_cmd); 2117 if (rc) 2118 goto closefs; 2119 } 2120 if (features_cmd) { 2121 rc = update_feature_set(fs, features_cmd); 2122 if (rc) 2123 goto closefs; 2124 } 2125 if (extended_cmd) { 2126 rc = parse_extended_opts(fs, extended_cmd); 2127 if (rc) 2128 goto closefs; 2129 if (clear_mmp && !f_flag) { 2130 fputs(_("Error in using clear_mmp. " 2131 "It must be used with -f\n"), 2132 stderr); 2133 goto closefs; 2134 } 2135 } 2136 if (clear_mmp) { 2137 rc = ext2fs_mmp_clear(fs); 2138 goto closefs; 2139 } 2140 if (journal_size || journal_device) { 2141 rc = add_journal(fs); 2142 if (rc) 2143 goto closefs; 2144 } 2145 2146 if (Q_flag) { 2147 if (mount_flags & EXT2_MF_MOUNTED) { 2148 fputs(_("The quota feature may only be changed when " 2149 "the filesystem is unmounted.\n"), stderr); 2150 rc = 1; 2151 goto closefs; 2152 } 2153 handle_quota_options(fs); 2154 } 2155 2156 if (U_flag) { 2157 int set_csum = 0; 2158 dgrp_t i; 2159 2160 if (sb->s_feature_ro_compat & 2161 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { 2162 /* 2163 * Changing the UUID requires rewriting all metadata, 2164 * which can race with a mounted fs. Don't allow that. 2165 */ 2166 if (mount_flags & EXT2_MF_MOUNTED) { 2167 fputs(_("The UUID may only be " 2168 "changed when the filesystem is " 2169 "unmounted.\n"), stderr); 2170 exit(1); 2171 } 2172 if (check_fsck_needed(fs)) 2173 exit(1); 2174 2175 /* 2176 * Determine if the block group checksums are 2177 * correct so we know whether or not to set 2178 * them later on. 2179 */ 2180 for (i = 0; i < fs->group_desc_count; i++) 2181 if (!ext2fs_group_desc_csum_verify(fs, i)) 2182 break; 2183 if (i >= fs->group_desc_count) 2184 set_csum = 1; 2185 } 2186 if ((strcasecmp(new_UUID, "null") == 0) || 2187 (strcasecmp(new_UUID, "clear") == 0)) { 2188 uuid_clear(sb->s_uuid); 2189 } else if (strcasecmp(new_UUID, "time") == 0) { 2190 uuid_generate_time(sb->s_uuid); 2191 } else if (strcasecmp(new_UUID, "random") == 0) { 2192 uuid_generate(sb->s_uuid); 2193 } else if (uuid_parse(new_UUID, sb->s_uuid)) { 2194 com_err(program_name, 0, "%s", 2195 _("Invalid UUID format\n")); 2196 rc = 1; 2197 goto closefs; 2198 } 2199 if (set_csum) { 2200 for (i = 0; i < fs->group_desc_count; i++) 2201 ext2fs_group_desc_csum_set(fs, i); 2202 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 2203 } 2204 ext2fs_mark_super_dirty(fs); 2205 } 2206 if (I_flag) { 2207 if (mount_flags & EXT2_MF_MOUNTED) { 2208 fputs(_("The inode size may only be " 2209 "changed when the filesystem is " 2210 "unmounted.\n"), stderr); 2211 rc = 1; 2212 goto closefs; 2213 } 2214 if (fs->super->s_feature_incompat & 2215 EXT4_FEATURE_INCOMPAT_FLEX_BG) { 2216 fputs(_("Changing the inode size not supported for " 2217 "filesystems with the flex_bg\n" 2218 "feature enabled.\n"), 2219 stderr); 2220 rc = 1; 2221 goto closefs; 2222 } 2223 /* 2224 * We want to update group descriptor also 2225 * with the new free inode count 2226 */ 2227 fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 2228 if (resize_inode(fs, new_inode_size) == 0) { 2229 printf(_("Setting inode size %lu\n"), 2230 new_inode_size); 2231 } else { 2232 printf("%s", _("Failed to change inode size\n")); 2233 rc = 1; 2234 goto closefs; 2235 } 2236 } 2237 2238 if (l_flag) 2239 list_super(sb); 2240 if (stride_set) { 2241 sb->s_raid_stride = stride; 2242 ext2fs_mark_super_dirty(fs); 2243 printf(_("Setting stride size to %d\n"), stride); 2244 } 2245 if (stripe_width_set) { 2246 sb->s_raid_stripe_width = stripe_width; 2247 ext2fs_mark_super_dirty(fs); 2248 printf(_("Setting stripe width to %d\n"), stripe_width); 2249 } 2250 if (ext_mount_opts) { 2251 strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts, 2252 sizeof(fs->super->s_mount_opts)); 2253 fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0; 2254 ext2fs_mark_super_dirty(fs); 2255 printf(_("Setting extended default mount options to '%s'\n"), 2256 ext_mount_opts); 2257 free(ext_mount_opts); 2258 } 2259 free(device_name); 2260 remove_error_table(&et_ext2_error_table); 2261 2262 closefs: 2263 if (rc) { 2264 ext2fs_mmp_stop(fs); 2265 exit(1); 2266 } 2267 2268 return (ext2fs_close(fs) ? 1 : 0); 2269 } 2270