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