]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - misc/tune2fs.c
Merge branch 'maint' into next
[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 #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 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
151 #ifdef CONFIG_QUOTA
152 EXT4_FEATURE_RO_COMPAT_QUOTA |
153 #endif
154 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
155 };
156
157 static __u32 clear_ok_features[3] = {
158 /* Compat */
159 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
160 EXT2_FEATURE_COMPAT_RESIZE_INODE |
161 EXT2_FEATURE_COMPAT_DIR_INDEX,
162 /* Incompat */
163 EXT2_FEATURE_INCOMPAT_FILETYPE |
164 EXT4_FEATURE_INCOMPAT_FLEX_BG |
165 EXT4_FEATURE_INCOMPAT_MMP,
166 /* R/O compat */
167 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
168 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
169 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
170 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
171 EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
172 #ifdef CONFIG_QUOTA
173 EXT4_FEATURE_RO_COMPAT_QUOTA |
174 #endif
175 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
176 };
177
178 /*
179 * Remove an external journal from the filesystem
180 */
181 static int remove_journal_device(ext2_filsys fs)
182 {
183 char *journal_path;
184 ext2_filsys jfs;
185 char buf[1024];
186 journal_superblock_t *jsb;
187 int i, nr_users;
188 errcode_t retval;
189 int commit_remove_journal = 0;
190 io_manager io_ptr;
191
192 if (f_flag)
193 commit_remove_journal = 1; /* force removal even if error */
194
195 uuid_unparse(fs->super->s_journal_uuid, buf);
196 journal_path = blkid_get_devname(NULL, "UUID", buf);
197
198 if (!journal_path) {
199 journal_path =
200 ext2fs_find_block_device(fs->super->s_journal_dev);
201 if (!journal_path)
202 goto no_valid_journal;
203 }
204
205 #ifdef CONFIG_TESTIO_DEBUG
206 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
207 io_ptr = test_io_manager;
208 test_io_backing_manager = unix_io_manager;
209 } else
210 #endif
211 io_ptr = unix_io_manager;
212 retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
213 EXT2_FLAG_JOURNAL_DEV_OK, 0,
214 fs->blocksize, io_ptr, &jfs);
215 if (retval) {
216 com_err(program_name, retval,
217 _("while trying to open external journal"));
218 goto no_valid_journal;
219 }
220 if (!(jfs->super->s_feature_incompat &
221 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
222 fprintf(stderr, _("%s is not a journal device.\n"),
223 journal_path);
224 goto no_valid_journal;
225 }
226
227 /* Get the journal superblock */
228 if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) {
229 com_err(program_name, retval,
230 _("while reading journal superblock"));
231 goto no_valid_journal;
232 }
233
234 jsb = (journal_superblock_t *) buf;
235 if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) ||
236 (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) {
237 fputs(_("Journal superblock not found!\n"), stderr);
238 goto no_valid_journal;
239 }
240
241 /* Find the filesystem UUID */
242 nr_users = ntohl(jsb->s_nr_users);
243 for (i = 0; i < nr_users; i++) {
244 if (memcmp(fs->super->s_uuid, &jsb->s_users[i * 16], 16) == 0)
245 break;
246 }
247 if (i >= nr_users) {
248 fputs(_("Filesystem's UUID not found on journal device.\n"),
249 stderr);
250 commit_remove_journal = 1;
251 goto no_valid_journal;
252 }
253 nr_users--;
254 for (i = 0; i < nr_users; i++)
255 memcpy(&jsb->s_users[i * 16], &jsb->s_users[(i + 1) * 16], 16);
256 jsb->s_nr_users = htonl(nr_users);
257
258 /* Write back the journal superblock */
259 if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) {
260 com_err(program_name, retval,
261 "while writing journal superblock.");
262 goto no_valid_journal;
263 }
264
265 commit_remove_journal = 1;
266
267 no_valid_journal:
268 if (commit_remove_journal == 0) {
269 fputs(_("Cannot locate journal device. It was NOT removed\n"
270 "Use -f option to remove missing journal device.\n"),
271 stderr);
272 return 1;
273 }
274 fs->super->s_journal_dev = 0;
275 uuid_clear(fs->super->s_journal_uuid);
276 ext2fs_mark_super_dirty(fs);
277 fputs(_("Journal removed\n"), stdout);
278 free(journal_path);
279
280 return 0;
281 }
282
283 /* Helper function for remove_journal_inode */
284 static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
285 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
286 blk64_t ref_block EXT2FS_ATTR((unused)),
287 int ref_offset EXT2FS_ATTR((unused)),
288 void *private EXT2FS_ATTR((unused)))
289 {
290 blk64_t block;
291 int group;
292
293 block = *blocknr;
294 ext2fs_unmark_block_bitmap2(fs->block_map, block);
295 group = ext2fs_group_of_blk2(fs, block);
296 ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
297 ext2fs_group_desc_csum_set(fs, group);
298 ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs));
299 return 0;
300 }
301
302 /*
303 * Remove the journal inode from the filesystem
304 */
305 static errcode_t remove_journal_inode(ext2_filsys fs)
306 {
307 struct ext2_inode inode;
308 errcode_t retval;
309 ino_t ino = fs->super->s_journal_inum;
310
311 retval = ext2fs_read_inode(fs, ino, &inode);
312 if (retval) {
313 com_err(program_name, retval,
314 _("while reading journal inode"));
315 return retval;
316 }
317 if (ino == EXT2_JOURNAL_INO) {
318 retval = ext2fs_read_bitmaps(fs);
319 if (retval) {
320 com_err(program_name, retval,
321 _("while reading bitmaps"));
322 return retval;
323 }
324 retval = ext2fs_block_iterate3(fs, ino,
325 BLOCK_FLAG_READ_ONLY, NULL,
326 release_blocks_proc, NULL);
327 if (retval) {
328 com_err(program_name, retval,
329 _("while clearing journal inode"));
330 return retval;
331 }
332 memset(&inode, 0, sizeof(inode));
333 ext2fs_mark_bb_dirty(fs);
334 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
335 } else
336 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
337 retval = ext2fs_write_inode(fs, ino, &inode);
338 if (retval) {
339 com_err(program_name, retval,
340 _("while writing journal inode"));
341 return retval;
342 }
343 fs->super->s_journal_inum = 0;
344 ext2fs_mark_super_dirty(fs);
345
346 return 0;
347 }
348
349 /*
350 * Update the default mount options
351 */
352 static int update_mntopts(ext2_filsys fs, char *mntopts)
353 {
354 struct ext2_super_block *sb = fs->super;
355
356 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
357 fprintf(stderr, _("Invalid mount option set: %s\n"),
358 mntopts);
359 return 1;
360 }
361 ext2fs_mark_super_dirty(fs);
362
363 return 0;
364 }
365
366 static int check_fsck_needed(ext2_filsys fs)
367 {
368 if (fs->super->s_state & EXT2_VALID_FS)
369 return 0;
370 printf("\n%s\n", _(please_fsck));
371 if (mount_flags & EXT2_MF_READONLY)
372 printf(_("(and reboot afterwards!)\n"));
373 return 1;
374 }
375
376 static void request_dir_fsck_afterwards(ext2_filsys fs)
377 {
378 static int requested;
379
380 if (requested++)
381 return;
382 fs->super->s_state &= ~EXT2_VALID_FS;
383 printf("\n%s\n", _(please_dir_fsck));
384 if (mount_flags & EXT2_MF_READONLY)
385 printf(_("(and reboot afterwards!)\n"));
386 }
387
388 static void request_fsck_afterwards(ext2_filsys fs)
389 {
390 static int requested = 0;
391
392 if (requested++)
393 return;
394 fs->super->s_state &= ~EXT2_VALID_FS;
395 printf("\n%s\n", _(please_fsck));
396 if (mount_flags & EXT2_MF_READONLY)
397 printf(_("(and reboot afterwards!)\n"));
398 }
399
400 /* Rewrite extents */
401 static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino,
402 struct ext2_inode *inode)
403 {
404 ext2_extent_handle_t handle;
405 struct ext2fs_extent extent;
406 int op = EXT2_EXTENT_ROOT;
407 errcode_t errcode;
408
409 if (!(inode->i_flags & EXT4_EXTENTS_FL))
410 return 0;
411
412 errcode = ext2fs_extent_open(fs, ino, &handle);
413 if (errcode)
414 return errcode;
415
416 while (1) {
417 errcode = ext2fs_extent_get(handle, op, &extent);
418 if (errcode)
419 break;
420
421 /* Root node is in the separately checksummed inode */
422 if (op == EXT2_EXTENT_ROOT) {
423 op = EXT2_EXTENT_NEXT;
424 continue;
425 }
426 op = EXT2_EXTENT_NEXT;
427
428 /* Only visit the first extent in each extent block */
429 if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
430 continue;
431 errcode = ext2fs_extent_replace(handle, 0, &extent);
432 if (errcode)
433 break;
434 }
435
436 /* Ok if we run off the end */
437 if (errcode == EXT2_ET_EXTENT_NO_NEXT)
438 errcode = 0;
439 return errcode;
440 }
441
442 /*
443 * Rewrite directory blocks with checksums
444 */
445 struct rewrite_dir_context {
446 char *buf;
447 errcode_t errcode;
448 ext2_ino_t dir;
449 int is_htree;
450 };
451
452 static int rewrite_dir_block(ext2_filsys fs,
453 blk64_t *blocknr,
454 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
455 blk64_t ref_block EXT2FS_ATTR((unused)),
456 int ref_offset EXT2FS_ATTR((unused)),
457 void *priv_data)
458 {
459 struct ext2_dx_countlimit *dcl = NULL;
460 struct rewrite_dir_context *ctx = priv_data;
461 int dcl_offset, changed = 0;
462
463 ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
464 ctx->dir);
465 if (ctx->errcode)
466 return BLOCK_ABORT;
467
468 /* if htree node... */
469 if (ctx->is_htree)
470 ext2fs_get_dx_countlimit(fs, (struct ext2_dir_entry *)ctx->buf,
471 &dcl, &dcl_offset);
472 if (dcl) {
473 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
474 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
475 /* Ensure limit is the max size */
476 int max_entries = (fs->blocksize - dcl_offset) /
477 sizeof(struct ext2_dx_entry);
478 if (ext2fs_le16_to_cpu(dcl->limit) != max_entries) {
479 changed = 1;
480 dcl->limit = ext2fs_cpu_to_le16(max_entries);
481 }
482 } else {
483 /* If htree block is full then rebuild the dir */
484 if (ext2fs_le16_to_cpu(dcl->count) ==
485 ext2fs_le16_to_cpu(dcl->limit)) {
486 request_dir_fsck_afterwards(fs);
487 return 0;
488 }
489 /*
490 * Ensure dcl->limit is small enough to leave room for
491 * the checksum tail.
492 */
493 int max_entries = (fs->blocksize - (dcl_offset +
494 sizeof(struct ext2_dx_tail))) /
495 sizeof(struct ext2_dx_entry);
496 if (ext2fs_le16_to_cpu(dcl->limit) != max_entries)
497 dcl->limit = ext2fs_cpu_to_le16(max_entries);
498 /* Always rewrite checksum */
499 changed = 1;
500 }
501 } else {
502 unsigned int rec_len, name_size;
503 char *top = ctx->buf + fs->blocksize;
504 struct ext2_dir_entry *de = (struct ext2_dir_entry *)ctx->buf;
505 struct ext2_dir_entry *last_de = NULL, *penultimate_de = NULL;
506
507 /* Find last and penultimate dirent */
508 while ((char *)de < top) {
509 penultimate_de = last_de;
510 last_de = de;
511 ctx->errcode = ext2fs_get_rec_len(fs, de, &rec_len);
512 if (!ctx->errcode && !rec_len)
513 ctx->errcode = EXT2_ET_DIR_CORRUPTED;
514 if (ctx->errcode)
515 return BLOCK_ABORT;
516 de = (struct ext2_dir_entry *)(((char *)de) + rec_len);
517 }
518 ctx->errcode = ext2fs_get_rec_len(fs, last_de, &rec_len);
519 if (ctx->errcode)
520 return BLOCK_ABORT;
521 name_size = ext2fs_dirent_name_len(last_de);
522
523 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
524 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
525 if (!penultimate_de)
526 return 0;
527 if (last_de->inode ||
528 name_size ||
529 rec_len != sizeof(struct ext2_dir_entry_tail))
530 return 0;
531 /*
532 * The last dirent is unused and the right length to
533 * have stored a checksum. Erase it.
534 */
535 ctx->errcode = ext2fs_get_rec_len(fs, penultimate_de,
536 &rec_len);
537 if (!rec_len)
538 ctx->errcode = EXT2_ET_DIR_CORRUPTED;
539 if (ctx->errcode)
540 return BLOCK_ABORT;
541 ext2fs_set_rec_len(fs, rec_len +
542 sizeof(struct ext2_dir_entry_tail),
543 penultimate_de);
544 changed = 1;
545 } else {
546 unsigned csum_size = sizeof(struct ext2_dir_entry_tail);
547 struct ext2_dir_entry_tail *t;
548
549 /*
550 * If the last dirent looks like the tail, just update
551 * the checksum.
552 */
553 if (!last_de->inode &&
554 rec_len == csum_size) {
555 t = (struct ext2_dir_entry_tail *)last_de;
556 t->det_reserved_name_len =
557 EXT2_DIR_NAME_LEN_CSUM;
558 changed = 1;
559 goto out;
560 }
561 if (name_size & 3)
562 name_size = (name_size & ~3) + 4;
563 /* If there's not enough space for the tail, e2fsck */
564 if (rec_len <= (8 + name_size + csum_size)) {
565 request_dir_fsck_afterwards(fs);
566 return 0;
567 }
568 /* Shorten that last de and insert the tail */
569 ext2fs_set_rec_len(fs, rec_len - csum_size, last_de);
570 t = EXT2_DIRENT_TAIL(ctx->buf, fs->blocksize);
571 ext2fs_initialize_dirent_tail(fs, t);
572
573 /* Always update checksum */
574 changed = 1;
575 }
576 }
577
578 out:
579 if (!changed)
580 return 0;
581
582 ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf,
583 0, ctx->dir);
584 if (ctx->errcode)
585 return BLOCK_ABORT;
586
587 return 0;
588 }
589
590 static errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
591 struct ext2_inode *inode)
592 {
593 errcode_t retval;
594 struct rewrite_dir_context ctx;
595
596 retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
597 if (retval)
598 return retval;
599
600 ctx.is_htree = (inode->i_flags & EXT2_INDEX_FL);
601 ctx.dir = dir;
602 ctx.errcode = 0;
603 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY |
604 BLOCK_FLAG_DATA_ONLY,
605 0, rewrite_dir_block, &ctx);
606
607 ext2fs_free_mem(&ctx.buf);
608 if (retval)
609 return retval;
610
611 return ctx.errcode;
612 }
613
614 /*
615 * Forcibly set checksums in all inodes.
616 */
617 static void rewrite_inodes(ext2_filsys fs)
618 {
619 int length = EXT2_INODE_SIZE(fs->super);
620 struct ext2_inode *inode, *zero;
621 char *ea_buf;
622 ext2_inode_scan scan;
623 errcode_t retval;
624 ext2_ino_t ino;
625 blk64_t file_acl_block;
626 int inode_dirty;
627
628 if (fs->super->s_creator_os != EXT2_OS_LINUX)
629 return;
630
631 retval = ext2fs_open_inode_scan(fs, 0, &scan);
632 if (retval) {
633 com_err("set_csum", retval, "while opening inode scan");
634 exit(1);
635 }
636
637 retval = ext2fs_get_mem(length, &inode);
638 if (retval) {
639 com_err("set_csum", retval, "while allocating memory");
640 exit(1);
641 }
642
643 retval = ext2fs_get_memzero(length, &zero);
644 if (retval) {
645 com_err("set_csum", retval, "while allocating memory");
646 exit(1);
647 }
648
649 retval = ext2fs_get_mem(fs->blocksize, &ea_buf);
650 if (retval) {
651 com_err("set_csum", retval, "while allocating memory");
652 exit(1);
653 }
654
655 do {
656 retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
657 if (retval) {
658 com_err("set_csum", retval, "while getting next inode");
659 exit(1);
660 }
661 if (!ino)
662 break;
663 if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
664 inode_dirty = 1;
665 } else {
666 if (memcmp(inode, zero, length) != 0) {
667 memset(inode, 0, length);
668 inode_dirty = 1;
669 } else {
670 inode_dirty = 0;
671 }
672 }
673
674 if (inode_dirty) {
675 retval = ext2fs_write_inode_full(fs, ino, inode,
676 length);
677 if (retval) {
678 com_err("set_csum", retval, "while writing "
679 "inode");
680 exit(1);
681 }
682 }
683
684 retval = rewrite_extents(fs, ino, inode);
685 if (retval) {
686 com_err("rewrite_extents", retval,
687 "while rewriting extents");
688 exit(1);
689 }
690
691 if (LINUX_S_ISDIR(inode->i_mode)) {
692 retval = rewrite_directory(fs, ino, inode);
693 if (retval) {
694 com_err("rewrite_directory", retval,
695 "while rewriting directories");
696 exit(1);
697 }
698 }
699
700 file_acl_block = ext2fs_file_acl_block(fs, inode);
701 if (!file_acl_block)
702 continue;
703 retval = ext2fs_read_ext_attr3(fs, file_acl_block, ea_buf, ino);
704 if (retval) {
705 com_err("rewrite_eablock", retval,
706 "while rewriting extended attribute");
707 exit(1);
708 }
709 retval = ext2fs_write_ext_attr3(fs, file_acl_block, ea_buf,
710 ino);
711 if (retval) {
712 com_err("rewrite_eablock", retval,
713 "while rewriting extended attribute");
714 exit(1);
715 }
716 } while (ino);
717
718 ext2fs_free_mem(&zero);
719 ext2fs_free_mem(&inode);
720 ext2fs_free_mem(&ea_buf);
721 ext2fs_close_inode_scan(scan);
722 }
723
724 static void rewrite_metadata_checksums(ext2_filsys fs)
725 {
726 dgrp_t i;
727
728 fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
729 ext2fs_init_csum_seed(fs);
730 for (i = 0; i < fs->group_desc_count; i++)
731 ext2fs_group_desc_csum_set(fs, i);
732 ext2fs_read_bitmaps(fs);
733 rewrite_inodes(fs);
734 ext2fs_mark_ib_dirty(fs);
735 ext2fs_mark_bb_dirty(fs);
736 ext2fs_mmp_update2(fs, 1);
737 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
738 fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
739 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
740 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
741 fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM;
742 else
743 fs->super->s_checksum_type = 0;
744 ext2fs_mark_super_dirty(fs);
745 }
746
747 static void enable_uninit_bg(ext2_filsys fs)
748 {
749 struct ext2_group_desc *gd;
750 dgrp_t i;
751
752 for (i = 0; i < fs->group_desc_count; i++) {
753 gd = ext2fs_group_desc(fs, fs->group_desc, i);
754 gd->bg_itable_unused = 0;
755 gd->bg_flags = EXT2_BG_INODE_ZEROED;
756 ext2fs_group_desc_csum_set(fs, i);
757 }
758 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
759 }
760
761 static errcode_t zero_empty_inodes(ext2_filsys fs)
762 {
763 int length = EXT2_INODE_SIZE(fs->super);
764 struct ext2_inode *inode;
765 ext2_inode_scan scan;
766 errcode_t retval;
767 ext2_ino_t ino;
768
769 retval = ext2fs_open_inode_scan(fs, 0, &scan);
770 if (retval)
771 goto out;
772
773 retval = ext2fs_get_mem(length, &inode);
774 if (retval)
775 goto out;
776
777 do {
778 retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
779 if (retval)
780 goto out;
781 if (!ino)
782 break;
783 if (!ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
784 memset(inode, 0, length);
785 retval = ext2fs_write_inode_full(fs, ino, inode,
786 length);
787 if (retval)
788 goto out;
789 }
790 } while (1);
791
792 out:
793 ext2fs_free_mem(&inode);
794 ext2fs_close_inode_scan(scan);
795 return retval;
796 }
797
798 static void disable_uninit_bg(ext2_filsys fs, __u32 csum_feature_flag)
799 {
800 struct ext2_group_desc *gd;
801 dgrp_t i;
802 errcode_t retval;
803 blk64_t b, c, d;
804 int has_super;
805
806 /* Load bitmaps to ensure that the uninit ones get written out */
807 fs->super->s_feature_ro_compat |= csum_feature_flag;
808 ext2fs_read_bitmaps(fs);
809 ext2fs_mark_ib_dirty(fs);
810 ext2fs_mark_bb_dirty(fs);
811 fs->super->s_feature_ro_compat &= ~csum_feature_flag;
812
813 /* If we're only turning off uninit_bg, zero the inodes */
814 if (csum_feature_flag == EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
815 retval = zero_empty_inodes(fs);
816 if (retval) {
817 com_err("disable_uninit_bg", retval,
818 "while zeroing unused inodes");
819 request_fsck_afterwards(fs);
820 }
821 }
822
823 /* The bbitmap is zeroed; we must mark group metadata blocks in use */
824 for (i = 0; i < fs->group_desc_count; i++) {
825 b = ext2fs_block_bitmap_loc(fs, i);
826 ext2fs_mark_block_bitmap2(fs->block_map, b);
827 b = ext2fs_inode_bitmap_loc(fs, i);
828 ext2fs_mark_block_bitmap2(fs->block_map, b);
829
830 retval = ext2fs_super_and_bgd_loc2(fs, i, &b, &c, &d, NULL);
831 if (retval == 0 && b)
832 ext2fs_mark_block_bitmap2(fs->block_map, b);
833 if (retval == 0 && c)
834 ext2fs_mark_block_bitmap2(fs->block_map, c);
835 if (retval == 0 && d)
836 ext2fs_mark_block_bitmap2(fs->block_map, 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_stats2(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 char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:";
1373
1374 #ifdef CONFIG_QUOTA
1375 strcat(optstring, "Q:");
1376 #endif
1377 open_flag = 0;
1378
1379 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
1380 while ((c = getopt(argc, argv, optstring)) != EOF)
1381 switch (c) {
1382 case 'c':
1383 max_mount_count = strtol(optarg, &tmp, 0);
1384 if (*tmp || max_mount_count > 16000) {
1385 com_err(program_name, 0,
1386 _("bad mounts count - %s"),
1387 optarg);
1388 usage();
1389 }
1390 if (max_mount_count == 0)
1391 max_mount_count = -1;
1392 c_flag = 1;
1393 open_flag = EXT2_FLAG_RW;
1394 break;
1395 case 'C':
1396 mount_count = strtoul(optarg, &tmp, 0);
1397 if (*tmp || mount_count > 16000) {
1398 com_err(program_name, 0,
1399 _("bad mounts count - %s"),
1400 optarg);
1401 usage();
1402 }
1403 C_flag = 1;
1404 open_flag = EXT2_FLAG_RW;
1405 break;
1406 case 'e':
1407 if (strcmp(optarg, "continue") == 0)
1408 errors = EXT2_ERRORS_CONTINUE;
1409 else if (strcmp(optarg, "remount-ro") == 0)
1410 errors = EXT2_ERRORS_RO;
1411 else if (strcmp(optarg, "panic") == 0)
1412 errors = EXT2_ERRORS_PANIC;
1413 else {
1414 com_err(program_name, 0,
1415 _("bad error behavior - %s"),
1416 optarg);
1417 usage();
1418 }
1419 e_flag = 1;
1420 open_flag = EXT2_FLAG_RW;
1421 break;
1422 case 'E':
1423 extended_cmd = optarg;
1424 open_flag |= EXT2_FLAG_RW;
1425 break;
1426 case 'f': /* Force */
1427 f_flag = 1;
1428 break;
1429 case 'g':
1430 resgid = strtoul(optarg, &tmp, 0);
1431 if (*tmp) {
1432 gr = getgrnam(optarg);
1433 if (gr == NULL)
1434 tmp = optarg;
1435 else {
1436 resgid = gr->gr_gid;
1437 *tmp = 0;
1438 }
1439 }
1440 if (*tmp) {
1441 com_err(program_name, 0,
1442 _("bad gid/group name - %s"),
1443 optarg);
1444 usage();
1445 }
1446 g_flag = 1;
1447 open_flag = EXT2_FLAG_RW;
1448 break;
1449 case 'i':
1450 interval = strtoul(optarg, &tmp, 0);
1451 switch (*tmp) {
1452 case 's':
1453 tmp++;
1454 break;
1455 case '\0':
1456 case 'd':
1457 case 'D': /* days */
1458 interval *= 86400;
1459 if (*tmp != '\0')
1460 tmp++;
1461 break;
1462 case 'm':
1463 case 'M': /* months! */
1464 interval *= 86400 * 30;
1465 tmp++;
1466 break;
1467 case 'w':
1468 case 'W': /* weeks */
1469 interval *= 86400 * 7;
1470 tmp++;
1471 break;
1472 }
1473 if (*tmp) {
1474 com_err(program_name, 0,
1475 _("bad interval - %s"), optarg);
1476 usage();
1477 }
1478 i_flag = 1;
1479 open_flag = EXT2_FLAG_RW;
1480 break;
1481 case 'j':
1482 if (!journal_size)
1483 journal_size = -1;
1484 open_flag = EXT2_FLAG_RW;
1485 break;
1486 case 'J':
1487 parse_journal_opts(optarg);
1488 open_flag = EXT2_FLAG_RW;
1489 break;
1490 case 'l':
1491 l_flag = 1;
1492 break;
1493 case 'L':
1494 new_label = optarg;
1495 L_flag = 1;
1496 open_flag |= EXT2_FLAG_RW |
1497 EXT2_FLAG_JOURNAL_DEV_OK;
1498 break;
1499 case 'm':
1500 reserved_ratio = strtod(optarg, &tmp);
1501 if (*tmp || reserved_ratio > 50 ||
1502 reserved_ratio < 0) {
1503 com_err(program_name, 0,
1504 _("bad reserved block ratio - %s"),
1505 optarg);
1506 usage();
1507 }
1508 m_flag = 1;
1509 open_flag = EXT2_FLAG_RW;
1510 break;
1511 case 'M':
1512 new_last_mounted = optarg;
1513 M_flag = 1;
1514 open_flag = EXT2_FLAG_RW;
1515 break;
1516 case 'o':
1517 if (mntopts_cmd) {
1518 com_err(program_name, 0,
1519 _("-o may only be specified once"));
1520 usage();
1521 }
1522 mntopts_cmd = optarg;
1523 open_flag = EXT2_FLAG_RW;
1524 break;
1525 case 'O':
1526 if (features_cmd) {
1527 com_err(program_name, 0,
1528 _("-O may only be specified once"));
1529 usage();
1530 }
1531 features_cmd = optarg;
1532 open_flag = EXT2_FLAG_RW;
1533 break;
1534 #ifdef CONFIG_QUOTA
1535 case 'Q':
1536 Q_flag = 1;
1537 parse_quota_opts(optarg);
1538 open_flag = EXT2_FLAG_RW;
1539 break;
1540 #endif
1541 case 'r':
1542 reserved_blocks = strtoul(optarg, &tmp, 0);
1543 if (*tmp) {
1544 com_err(program_name, 0,
1545 _("bad reserved blocks count - %s"),
1546 optarg);
1547 usage();
1548 }
1549 r_flag = 1;
1550 open_flag = EXT2_FLAG_RW;
1551 break;
1552 case 's': /* Deprecated */
1553 s_flag = atoi(optarg);
1554 open_flag = EXT2_FLAG_RW;
1555 break;
1556 case 'T':
1557 T_flag = 1;
1558 last_check_time = parse_time(optarg);
1559 open_flag = EXT2_FLAG_RW;
1560 break;
1561 case 'u':
1562 resuid = strtoul(optarg, &tmp, 0);
1563 if (*tmp) {
1564 pw = getpwnam(optarg);
1565 if (pw == NULL)
1566 tmp = optarg;
1567 else {
1568 resuid = pw->pw_uid;
1569 *tmp = 0;
1570 }
1571 }
1572 if (*tmp) {
1573 com_err(program_name, 0,
1574 _("bad uid/user name - %s"),
1575 optarg);
1576 usage();
1577 }
1578 u_flag = 1;
1579 open_flag = EXT2_FLAG_RW;
1580 break;
1581 case 'U':
1582 new_UUID = optarg;
1583 U_flag = 1;
1584 open_flag = EXT2_FLAG_RW |
1585 EXT2_FLAG_JOURNAL_DEV_OK;
1586 break;
1587 case 'I':
1588 new_inode_size = strtoul(optarg, &tmp, 0);
1589 if (*tmp) {
1590 com_err(program_name, 0,
1591 _("bad inode size - %s"),
1592 optarg);
1593 usage();
1594 }
1595 if (!((new_inode_size &
1596 (new_inode_size - 1)) == 0)) {
1597 com_err(program_name, 0,
1598 _("Inode size must be a "
1599 "power of two- %s"),
1600 optarg);
1601 usage();
1602 }
1603 open_flag = EXT2_FLAG_RW;
1604 I_flag = 1;
1605 break;
1606 default:
1607 usage();
1608 }
1609 if (optind < argc - 1 || optind == argc)
1610 usage();
1611 if (!open_flag && !l_flag)
1612 usage();
1613 io_options = strchr(argv[optind], '?');
1614 if (io_options)
1615 *io_options++ = 0;
1616 device_name = blkid_get_devname(NULL, argv[optind], NULL);
1617 if (!device_name) {
1618 com_err(program_name, 0, _("Unable to resolve '%s'"),
1619 argv[optind]);
1620 exit(1);
1621 }
1622 }
1623
1624 #ifdef CONFIG_BUILD_FINDFS
1625 void do_findfs(int argc, char **argv)
1626 {
1627 char *dev;
1628
1629 if ((argc != 2) ||
1630 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
1631 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
1632 exit(2);
1633 }
1634 dev = blkid_get_devname(NULL, argv[1], NULL);
1635 if (!dev) {
1636 com_err("findfs", 0, _("Unable to resolve '%s'"),
1637 argv[1]);
1638 exit(1);
1639 }
1640 puts(dev);
1641 exit(0);
1642 }
1643 #endif
1644
1645 static int parse_extended_opts(ext2_filsys fs, const char *opts)
1646 {
1647 char *buf, *token, *next, *p, *arg;
1648 int len, hash_alg;
1649 int r_usage = 0;
1650
1651 len = strlen(opts);
1652 buf = malloc(len+1);
1653 if (!buf) {
1654 fprintf(stderr,
1655 _("Couldn't allocate memory to parse options!\n"));
1656 return 1;
1657 }
1658 strcpy(buf, opts);
1659 for (token = buf; token && *token; token = next) {
1660 p = strchr(token, ',');
1661 next = 0;
1662 if (p) {
1663 *p = 0;
1664 next = p+1;
1665 }
1666 arg = strchr(token, '=');
1667 if (arg) {
1668 *arg = 0;
1669 arg++;
1670 }
1671 if (strcmp(token, "clear-mmp") == 0 ||
1672 strcmp(token, "clear_mmp") == 0) {
1673 clear_mmp = 1;
1674 } else if (strcmp(token, "mmp_update_interval") == 0) {
1675 unsigned long intv;
1676 if (!arg) {
1677 r_usage++;
1678 continue;
1679 }
1680 intv = strtoul(arg, &p, 0);
1681 if (*p) {
1682 fprintf(stderr,
1683 _("Invalid mmp_update_interval: %s\n"),
1684 arg);
1685 r_usage++;
1686 continue;
1687 }
1688 if (intv == 0) {
1689 intv = EXT4_MMP_UPDATE_INTERVAL;
1690 } else if (intv > EXT4_MMP_MAX_UPDATE_INTERVAL) {
1691 fprintf(stderr,
1692 _("mmp_update_interval too big: %lu\n"),
1693 intv);
1694 r_usage++;
1695 continue;
1696 }
1697 printf(P_("Setting multiple mount protection update "
1698 "interval to %lu second\n",
1699 "Setting multiple mount protection update "
1700 "interval to %lu seconds\n", intv),
1701 intv);
1702 fs->super->s_mmp_update_interval = intv;
1703 ext2fs_mark_super_dirty(fs);
1704 } else if (!strcmp(token, "test_fs")) {
1705 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
1706 printf("Setting test filesystem flag\n");
1707 ext2fs_mark_super_dirty(fs);
1708 } else if (!strcmp(token, "^test_fs")) {
1709 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
1710 printf("Clearing test filesystem flag\n");
1711 ext2fs_mark_super_dirty(fs);
1712 } else if (strcmp(token, "stride") == 0) {
1713 if (!arg) {
1714 r_usage++;
1715 continue;
1716 }
1717 stride = strtoul(arg, &p, 0);
1718 if (*p) {
1719 fprintf(stderr,
1720 _("Invalid RAID stride: %s\n"),
1721 arg);
1722 r_usage++;
1723 continue;
1724 }
1725 stride_set = 1;
1726 } else if (strcmp(token, "stripe-width") == 0 ||
1727 strcmp(token, "stripe_width") == 0) {
1728 if (!arg) {
1729 r_usage++;
1730 continue;
1731 }
1732 stripe_width = strtoul(arg, &p, 0);
1733 if (*p) {
1734 fprintf(stderr,
1735 _("Invalid RAID stripe-width: %s\n"),
1736 arg);
1737 r_usage++;
1738 continue;
1739 }
1740 stripe_width_set = 1;
1741 } else if (strcmp(token, "hash_alg") == 0 ||
1742 strcmp(token, "hash-alg") == 0) {
1743 if (!arg) {
1744 r_usage++;
1745 continue;
1746 }
1747 hash_alg = e2p_string2hash(arg);
1748 if (hash_alg < 0) {
1749 fprintf(stderr,
1750 _("Invalid hash algorithm: %s\n"),
1751 arg);
1752 r_usage++;
1753 continue;
1754 }
1755 fs->super->s_def_hash_version = hash_alg;
1756 printf(_("Setting default hash algorithm "
1757 "to %s (%d)\n"),
1758 arg, hash_alg);
1759 ext2fs_mark_super_dirty(fs);
1760 } else if (!strcmp(token, "mount_opts")) {
1761 if (!arg) {
1762 r_usage++;
1763 continue;
1764 }
1765 if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) {
1766 fprintf(stderr,
1767 "Extended mount options too long\n");
1768 continue;
1769 }
1770 ext_mount_opts = strdup(arg);
1771 } else
1772 r_usage++;
1773 }
1774 if (r_usage) {
1775 fprintf(stderr, _("\nBad options specified.\n\n"
1776 "Extended options are separated by commas, "
1777 "and may take an argument which\n"
1778 "\tis set off by an equals ('=') sign.\n\n"
1779 "Valid extended options are:\n"
1780 "\tclear_mmp\n"
1781 "\thash_alg=<hash algorithm>\n"
1782 "\tmount_opts=<extended default mount options>\n"
1783 "\tstride=<RAID per-disk chunk size in blocks>\n"
1784 "\tstripe_width=<RAID stride*data disks in blocks>\n"
1785 "\ttest_fs\n"
1786 "\t^test_fs\n"));
1787 free(buf);
1788 return 1;
1789 }
1790 free(buf);
1791
1792 return 0;
1793 }
1794
1795 /*
1796 * Fill in the block bitmap bmap with the information regarding the
1797 * blocks to be moved
1798 */
1799 static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
1800 ext2fs_block_bitmap bmap)
1801 {
1802 dgrp_t i;
1803 int retval;
1804 ext2_badblocks_list bb_list = 0;
1805 blk64_t j, needed_blocks = 0;
1806 blk64_t start_blk, end_blk;
1807
1808 retval = ext2fs_read_bb_inode(fs, &bb_list);
1809 if (retval)
1810 return retval;
1811
1812 for (i = 0; i < fs->group_desc_count; i++) {
1813 start_blk = ext2fs_inode_table_loc(fs, i) +
1814 fs->inode_blocks_per_group;
1815
1816 end_blk = ext2fs_inode_table_loc(fs, i) +
1817 new_ino_blks_per_grp;
1818
1819 for (j = start_blk; j < end_blk; j++) {
1820 if (ext2fs_test_block_bitmap2(fs->block_map, j)) {
1821 /*
1822 * IF the block is a bad block we fail
1823 */
1824 if (ext2fs_badblocks_list_test(bb_list, j)) {
1825 ext2fs_badblocks_list_free(bb_list);
1826 return ENOSPC;
1827 }
1828
1829 ext2fs_mark_block_bitmap2(bmap, j);
1830 } else {
1831 /*
1832 * We are going to use this block for
1833 * inode table. So mark them used.
1834 */
1835 ext2fs_mark_block_bitmap2(fs->block_map, j);
1836 }
1837 }
1838 needed_blocks += end_blk - start_blk;
1839 }
1840
1841 ext2fs_badblocks_list_free(bb_list);
1842 if (needed_blocks > ext2fs_free_blocks_count(fs->super))
1843 return ENOSPC;
1844
1845 return 0;
1846 }
1847
1848 static int ext2fs_is_meta_block(ext2_filsys fs, blk64_t blk)
1849 {
1850 dgrp_t group;
1851 group = ext2fs_group_of_blk2(fs, blk);
1852 if (ext2fs_block_bitmap_loc(fs, group) == blk)
1853 return 1;
1854 if (ext2fs_inode_bitmap_loc(fs, group) == blk)
1855 return 1;
1856 return 0;
1857 }
1858
1859 static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk64_t blk)
1860 {
1861 blk64_t start_blk, end_blk;
1862 start_blk = fs->super->s_first_data_block +
1863 EXT2_BLOCKS_PER_GROUP(fs->super) * group;
1864 /*
1865 * We cannot get new block beyond end_blk for for the last block group
1866 * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
1867 */
1868 end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
1869 if (blk >= start_blk && blk <= end_blk)
1870 return 1;
1871 return 0;
1872 }
1873
1874 static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
1875 {
1876
1877 char *buf;
1878 dgrp_t group = 0;
1879 errcode_t retval;
1880 int meta_data = 0;
1881 blk64_t blk, new_blk, goal;
1882 struct blk_move *bmv;
1883
1884 retval = ext2fs_get_mem(fs->blocksize, &buf);
1885 if (retval)
1886 return retval;
1887
1888 for (new_blk = blk = fs->super->s_first_data_block;
1889 blk < ext2fs_blocks_count(fs->super); blk++) {
1890 if (!ext2fs_test_block_bitmap2(bmap, blk))
1891 continue;
1892
1893 if (ext2fs_is_meta_block(fs, blk)) {
1894 /*
1895 * If the block is mapping a fs meta data block
1896 * like group desc/block bitmap/inode bitmap. We
1897 * should find a block in the same group and fix
1898 * the respective fs metadata pointers. Otherwise
1899 * fail
1900 */
1901 group = ext2fs_group_of_blk2(fs, blk);
1902 goal = ext2fs_group_first_block2(fs, group);
1903 meta_data = 1;
1904
1905 } else {
1906 goal = new_blk;
1907 }
1908 retval = ext2fs_new_block2(fs, goal, NULL, &new_blk);
1909 if (retval)
1910 goto err_out;
1911
1912 /* new fs meta data block should be in the same group */
1913 if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
1914 retval = ENOSPC;
1915 goto err_out;
1916 }
1917
1918 /* Mark this block as allocated */
1919 ext2fs_mark_block_bitmap2(fs->block_map, new_blk);
1920
1921 /* Add it to block move list */
1922 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
1923 if (retval)
1924 goto err_out;
1925
1926 bmv->old_loc = blk;
1927 bmv->new_loc = new_blk;
1928
1929 list_add(&(bmv->list), &blk_move_list);
1930
1931 retval = io_channel_read_blk64(fs->io, blk, 1, buf);
1932 if (retval)
1933 goto err_out;
1934
1935 retval = io_channel_write_blk64(fs->io, new_blk, 1, buf);
1936 if (retval)
1937 goto err_out;
1938 }
1939
1940 err_out:
1941 ext2fs_free_mem(&buf);
1942 return retval;
1943 }
1944
1945 static blk64_t translate_block(blk64_t blk)
1946 {
1947 struct list_head *entry;
1948 struct blk_move *bmv;
1949
1950 list_for_each(entry, &blk_move_list) {
1951 bmv = list_entry(entry, struct blk_move, list);
1952 if (bmv->old_loc == blk)
1953 return bmv->new_loc;
1954 }
1955
1956 return 0;
1957 }
1958
1959 static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
1960 blk64_t *block_nr,
1961 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
1962 blk64_t ref_block EXT2FS_ATTR((unused)),
1963 int ref_offset EXT2FS_ATTR((unused)),
1964 void *priv_data)
1965 {
1966 int ret = 0;
1967 blk64_t new_blk;
1968 ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
1969
1970 if (!ext2fs_test_block_bitmap2(bmap, *block_nr))
1971 return 0;
1972 new_blk = translate_block(*block_nr);
1973 if (new_blk) {
1974 *block_nr = new_blk;
1975 /*
1976 * This will force the ext2fs_write_inode in the iterator
1977 */
1978 ret |= BLOCK_CHANGED;
1979 }
1980
1981 return ret;
1982 }
1983
1984 static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
1985 {
1986 errcode_t retval = 0;
1987 ext2_ino_t ino;
1988 blk64_t blk;
1989 char *block_buf = 0;
1990 struct ext2_inode inode;
1991 ext2_inode_scan scan = NULL;
1992
1993 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1994 if (retval)
1995 return retval;
1996
1997 retval = ext2fs_open_inode_scan(fs, 0, &scan);
1998 if (retval)
1999 goto err_out;
2000
2001 while (1) {
2002 retval = ext2fs_get_next_inode(scan, &ino, &inode);
2003 if (retval)
2004 goto err_out;
2005
2006 if (!ino)
2007 break;
2008
2009 if (inode.i_links_count == 0)
2010 continue; /* inode not in use */
2011
2012 /* FIXME!!
2013 * If we end up modifying the journal inode
2014 * the sb->s_jnl_blocks will differ. But a
2015 * subsequent e2fsck fixes that.
2016 * Do we need to fix this ??
2017 */
2018
2019 if (ext2fs_file_acl_block(fs, &inode) &&
2020 ext2fs_test_block_bitmap2(bmap,
2021 ext2fs_file_acl_block(fs, &inode))) {
2022 blk = translate_block(ext2fs_file_acl_block(fs,
2023 &inode));
2024 if (!blk)
2025 continue;
2026
2027 ext2fs_file_acl_block_set(fs, &inode, blk);
2028
2029 /*
2030 * Write the inode to disk so that inode table
2031 * resizing can work
2032 */
2033 retval = ext2fs_write_inode(fs, ino, &inode);
2034 if (retval)
2035 goto err_out;
2036 }
2037
2038 if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
2039 continue;
2040
2041 retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
2042 process_block, bmap);
2043 if (retval)
2044 goto err_out;
2045
2046 }
2047
2048 err_out:
2049 ext2fs_free_mem(&block_buf);
2050
2051 return retval;
2052 }
2053
2054 /*
2055 * We need to scan for inode and block bitmaps that may need to be
2056 * moved. This can take place if the filesystem was formatted for
2057 * RAID arrays using the mke2fs's extended option "stride".
2058 */
2059 static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
2060 {
2061 dgrp_t i;
2062 blk64_t blk, new_blk;
2063
2064 for (i = 0; i < fs->group_desc_count; i++) {
2065 blk = ext2fs_block_bitmap_loc(fs, i);
2066 if (ext2fs_test_block_bitmap2(bmap, blk)) {
2067 new_blk = translate_block(blk);
2068 if (!new_blk)
2069 continue;
2070 ext2fs_block_bitmap_loc_set(fs, i, new_blk);
2071 }
2072
2073 blk = ext2fs_inode_bitmap_loc(fs, i);
2074 if (ext2fs_test_block_bitmap2(bmap, blk)) {
2075 new_blk = translate_block(blk);
2076 if (!new_blk)
2077 continue;
2078 ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
2079 }
2080 }
2081 return 0;
2082 }
2083
2084 static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
2085 {
2086 dgrp_t i;
2087 blk64_t blk;
2088 errcode_t retval;
2089 int new_ino_blks_per_grp;
2090 unsigned int j;
2091 char *old_itable = NULL, *new_itable = NULL;
2092 char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
2093 unsigned long old_ino_size;
2094 int old_itable_size, new_itable_size;
2095
2096 old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
2097 old_ino_size = EXT2_INODE_SIZE(fs->super);
2098
2099 new_ino_blks_per_grp = ext2fs_div_ceil(
2100 EXT2_INODES_PER_GROUP(fs->super) *
2101 new_ino_size,
2102 fs->blocksize);
2103
2104 new_itable_size = new_ino_blks_per_grp * fs->blocksize;
2105
2106 retval = ext2fs_get_mem(old_itable_size, &old_itable);
2107 if (retval)
2108 return retval;
2109
2110 retval = ext2fs_get_mem(new_itable_size, &new_itable);
2111 if (retval)
2112 goto err_out;
2113
2114 tmp_old_itable = old_itable;
2115 tmp_new_itable = new_itable;
2116
2117 for (i = 0; i < fs->group_desc_count; i++) {
2118 blk = ext2fs_inode_table_loc(fs, i);
2119 retval = io_channel_read_blk64(fs->io, blk,
2120 fs->inode_blocks_per_group, old_itable);
2121 if (retval)
2122 goto err_out;
2123
2124 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
2125 memcpy(new_itable, old_itable, old_ino_size);
2126
2127 memset(new_itable+old_ino_size, 0,
2128 new_ino_size - old_ino_size);
2129
2130 new_itable += new_ino_size;
2131 old_itable += old_ino_size;
2132 }
2133
2134 /* reset the pointer */
2135 old_itable = tmp_old_itable;
2136 new_itable = tmp_new_itable;
2137
2138 retval = io_channel_write_blk64(fs->io, blk,
2139 new_ino_blks_per_grp, new_itable);
2140 if (retval)
2141 goto err_out;
2142 }
2143
2144 /* Update the meta data */
2145 fs->inode_blocks_per_group = new_ino_blks_per_grp;
2146 fs->super->s_inode_size = new_ino_size;
2147
2148 err_out:
2149 if (old_itable)
2150 ext2fs_free_mem(&old_itable);
2151
2152 if (new_itable)
2153 ext2fs_free_mem(&new_itable);
2154
2155 return retval;
2156 }
2157
2158 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
2159 {
2160 blk64_t blk;
2161 ext2_ino_t ino;
2162 unsigned int group = 0;
2163 unsigned int count = 0;
2164 int total_free = 0;
2165 int group_free = 0;
2166
2167 /*
2168 * First calculate the block statistics
2169 */
2170 for (blk = fs->super->s_first_data_block;
2171 blk < ext2fs_blocks_count(fs->super); blk++) {
2172 if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
2173 group_free++;
2174 total_free++;
2175 }
2176 count++;
2177 if ((count == fs->super->s_blocks_per_group) ||
2178 (blk == ext2fs_blocks_count(fs->super)-1)) {
2179 ext2fs_bg_free_blocks_count_set(fs, group++,
2180 group_free);
2181 count = 0;
2182 group_free = 0;
2183 }
2184 }
2185 total_free = EXT2FS_C2B(fs, total_free);
2186 ext2fs_free_blocks_count_set(fs->super, total_free);
2187
2188 /*
2189 * Next, calculate the inode statistics
2190 */
2191 group_free = 0;
2192 total_free = 0;
2193 count = 0;
2194 group = 0;
2195
2196 /* Protect loop from wrap-around if s_inodes_count maxed */
2197 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
2198 if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
2199 group_free++;
2200 total_free++;
2201 }
2202 count++;
2203 if ((count == fs->super->s_inodes_per_group) ||
2204 (ino == fs->super->s_inodes_count)) {
2205 ext2fs_bg_free_inodes_count_set(fs, group++,
2206 group_free);
2207 count = 0;
2208 group_free = 0;
2209 }
2210 }
2211 fs->super->s_free_inodes_count = total_free;
2212 ext2fs_mark_super_dirty(fs);
2213 return 0;
2214 }
2215
2216 #define list_for_each_safe(pos, pnext, head) \
2217 for (pos = (head)->next, pnext = pos->next; pos != (head); \
2218 pos = pnext, pnext = pos->next)
2219
2220 static void free_blk_move_list(void)
2221 {
2222 struct list_head *entry, *tmp;
2223 struct blk_move *bmv;
2224
2225 list_for_each_safe(entry, tmp, &blk_move_list) {
2226 bmv = list_entry(entry, struct blk_move, list);
2227 list_del(entry);
2228 ext2fs_free_mem(&bmv);
2229 }
2230 return;
2231 }
2232
2233 static int resize_inode(ext2_filsys fs, unsigned long new_size)
2234 {
2235 errcode_t retval;
2236 int new_ino_blks_per_grp;
2237 ext2fs_block_bitmap bmap;
2238
2239 retval = ext2fs_read_inode_bitmap(fs);
2240 if (retval) {
2241 fputs(_("Failed to read inode bitmap\n"), stderr);
2242 return retval;
2243 }
2244 retval = ext2fs_read_block_bitmap(fs);
2245 if (retval) {
2246 fputs(_("Failed to read block bitmap\n"), stderr);
2247 return retval;
2248 }
2249 INIT_LIST_HEAD(&blk_move_list);
2250
2251
2252 new_ino_blks_per_grp = ext2fs_div_ceil(
2253 EXT2_INODES_PER_GROUP(fs->super)*
2254 new_size,
2255 fs->blocksize);
2256
2257 /* We may change the file system.
2258 * Mark the file system as invalid so that
2259 * the user is prompted to run fsck.
2260 */
2261 fs->super->s_state &= ~EXT2_VALID_FS;
2262
2263 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
2264 &bmap);
2265 if (retval) {
2266 fputs(_("Failed to allocate block bitmap when "
2267 "increasing inode size\n"), stderr);
2268 return retval;
2269 }
2270 retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
2271 if (retval) {
2272 fputs(_("Not enough space to increase inode size \n"), stderr);
2273 goto err_out;
2274 }
2275 retval = move_block(fs, bmap);
2276 if (retval) {
2277 fputs(_("Failed to relocate blocks during inode resize \n"),
2278 stderr);
2279 goto err_out;
2280 }
2281 retval = inode_scan_and_fix(fs, bmap);
2282 if (retval)
2283 goto err_out_undo;
2284
2285 retval = group_desc_scan_and_fix(fs, bmap);
2286 if (retval)
2287 goto err_out_undo;
2288
2289 retval = expand_inode_table(fs, new_size);
2290 if (retval)
2291 goto err_out_undo;
2292
2293 ext2fs_calculate_summary_stats(fs);
2294
2295 fs->super->s_state |= EXT2_VALID_FS;
2296 /* mark super block and block bitmap as dirty */
2297 ext2fs_mark_super_dirty(fs);
2298 ext2fs_mark_bb_dirty(fs);
2299
2300 err_out:
2301 free_blk_move_list();
2302 ext2fs_free_block_bitmap(bmap);
2303
2304 return retval;
2305
2306 err_out_undo:
2307 free_blk_move_list();
2308 ext2fs_free_block_bitmap(bmap);
2309 fputs(_("Error in resizing the inode size.\n"
2310 "Run e2undo to undo the "
2311 "file system changes. \n"), stderr);
2312
2313 return retval;
2314 }
2315
2316 static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
2317 {
2318 errcode_t retval = 0;
2319 const char *tdb_dir;
2320 char *tdb_file;
2321 char *dev_name, *tmp_name;
2322
2323 #if 0 /* FIXME!! */
2324 /*
2325 * Configuration via a conf file would be
2326 * nice
2327 */
2328 profile_get_string(profile, "scratch_files",
2329 "directory", 0, 0,
2330 &tdb_dir);
2331 #endif
2332 tmp_name = strdup(name);
2333 if (!tmp_name) {
2334 alloc_fn_fail:
2335 com_err(program_name, ENOMEM,
2336 _("Couldn't allocate memory for tdb filename\n"));
2337 return ENOMEM;
2338 }
2339 dev_name = basename(tmp_name);
2340
2341 tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
2342 if (!tdb_dir)
2343 tdb_dir = "/var/lib/e2fsprogs";
2344
2345 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
2346 access(tdb_dir, W_OK))
2347 return 0;
2348
2349 tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
2350 if (!tdb_file)
2351 goto alloc_fn_fail;
2352 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
2353
2354 if (!access(tdb_file, F_OK)) {
2355 if (unlink(tdb_file) < 0) {
2356 retval = errno;
2357 com_err(program_name, retval,
2358 _("while trying to delete %s"),
2359 tdb_file);
2360 free(tdb_file);
2361 return retval;
2362 }
2363 }
2364
2365 set_undo_io_backing_manager(*io_ptr);
2366 *io_ptr = undo_io_manager;
2367 set_undo_io_backup_file(tdb_file);
2368 printf(_("To undo the tune2fs operation please run "
2369 "the command\n e2undo %s %s\n\n"),
2370 tdb_file, name);
2371 free(tdb_file);
2372 free(tmp_name);
2373 return retval;
2374 }
2375
2376 int main(int argc, char **argv)
2377 {
2378 errcode_t retval;
2379 ext2_filsys fs;
2380 struct ext2_super_block *sb;
2381 io_manager io_ptr, io_ptr_orig = NULL;
2382 int rc = 0;
2383
2384 #ifdef ENABLE_NLS
2385 setlocale(LC_MESSAGES, "");
2386 setlocale(LC_CTYPE, "");
2387 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
2388 textdomain(NLS_CAT_NAME);
2389 set_com_err_gettext(gettext);
2390 #endif
2391 if (argc && *argv)
2392 program_name = *argv;
2393 add_error_table(&et_ext2_error_table);
2394
2395 #ifdef CONFIG_BUILD_FINDFS
2396 if (strcmp(get_progname(argv[0]), "findfs") == 0)
2397 do_findfs(argc, argv);
2398 #endif
2399 if (strcmp(get_progname(argv[0]), "e2label") == 0)
2400 parse_e2label_options(argc, argv);
2401 else
2402 parse_tune2fs_options(argc, argv);
2403
2404 #ifdef CONFIG_TESTIO_DEBUG
2405 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
2406 io_ptr = test_io_manager;
2407 test_io_backing_manager = unix_io_manager;
2408 } else
2409 #endif
2410 io_ptr = unix_io_manager;
2411
2412 retry_open:
2413 if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
2414 open_flag |= EXT2_FLAG_SKIP_MMP;
2415
2416 open_flag |= EXT2_FLAG_64BITS;
2417
2418 /* keep the filesystem struct around to dump MMP data */
2419 open_flag |= EXT2_FLAG_NOFREE_ON_ERROR;
2420
2421 retval = ext2fs_open2(device_name, io_options, open_flag,
2422 0, 0, io_ptr, &fs);
2423 if (retval) {
2424 com_err(program_name, retval,
2425 _("while trying to open %s"),
2426 device_name);
2427 if (retval == EXT2_ET_MMP_FSCK_ON ||
2428 retval == EXT2_ET_MMP_UNKNOWN_SEQ)
2429 dump_mmp_msg(fs->mmp_buf,
2430 _("If you are sure the filesystem "
2431 "is not in use on any node, run:\n"
2432 "'tune2fs -f -E clear_mmp {device}'\n"));
2433 else if (retval == EXT2_ET_MMP_FAILED)
2434 dump_mmp_msg(fs->mmp_buf, NULL);
2435 else if (retval == EXT2_ET_MMP_MAGIC_INVALID)
2436 fprintf(stderr,
2437 _("MMP block magic is bad. Try to fix it by "
2438 "running:\n'e2fsck -f %s'\n"), device_name);
2439 else if (retval != EXT2_ET_MMP_FAILED)
2440 fprintf(stderr,
2441 _("Couldn't find valid filesystem superblock.\n"));
2442
2443 ext2fs_free(fs);
2444 exit(1);
2445 }
2446 fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
2447
2448 if (I_flag && !io_ptr_orig) {
2449 /*
2450 * Check the inode size is right so we can issue an
2451 * error message and bail before setting up the tdb
2452 * file.
2453 */
2454 if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
2455 fprintf(stderr, _("The inode size is already %lu\n"),
2456 new_inode_size);
2457 rc = 1;
2458 goto closefs;
2459 }
2460 if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
2461 fprintf(stderr, _("Shrinking the inode size is "
2462 "not supported\n"));
2463 rc = 1;
2464 goto closefs;
2465 }
2466 if (new_inode_size > fs->blocksize) {
2467 fprintf(stderr, _("Invalid inode size %lu (max %d)\n"),
2468 new_inode_size, fs->blocksize);
2469 rc = 1;
2470 goto closefs;
2471 }
2472
2473 /*
2474 * If inode resize is requested use the
2475 * Undo I/O manager
2476 */
2477 io_ptr_orig = io_ptr;
2478 retval = tune2fs_setup_tdb(device_name, &io_ptr);
2479 if (retval) {
2480 rc = 1;
2481 goto closefs;
2482 }
2483 if (io_ptr != io_ptr_orig) {
2484 ext2fs_close(fs);
2485 goto retry_open;
2486 }
2487 }
2488
2489 sb = fs->super;
2490 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2491
2492 if (print_label) {
2493 /* For e2label emulation */
2494 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
2495 sb->s_volume_name);
2496 remove_error_table(&et_ext2_error_table);
2497 goto closefs;
2498 }
2499
2500 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
2501 if (retval) {
2502 com_err("ext2fs_check_if_mount", retval,
2503 _("while determining whether %s is mounted."),
2504 device_name);
2505 rc = 1;
2506 goto closefs;
2507 }
2508 /* Normally we only need to write out the superblock */
2509 fs->flags |= EXT2_FLAG_SUPER_ONLY;
2510
2511 if (c_flag) {
2512 sb->s_max_mnt_count = max_mount_count;
2513 ext2fs_mark_super_dirty(fs);
2514 printf(_("Setting maximal mount count to %d\n"),
2515 max_mount_count);
2516 }
2517 if (C_flag) {
2518 sb->s_mnt_count = mount_count;
2519 ext2fs_mark_super_dirty(fs);
2520 printf(_("Setting current mount count to %d\n"), mount_count);
2521 }
2522 if (e_flag) {
2523 sb->s_errors = errors;
2524 ext2fs_mark_super_dirty(fs);
2525 printf(_("Setting error behavior to %d\n"), errors);
2526 }
2527 if (g_flag) {
2528 sb->s_def_resgid = resgid;
2529 ext2fs_mark_super_dirty(fs);
2530 printf(_("Setting reserved blocks gid to %lu\n"), resgid);
2531 }
2532 if (i_flag) {
2533 if (interval >= (1ULL << 32)) {
2534 com_err(program_name, 0,
2535 _("interval between checks is too big (%lu)"),
2536 interval);
2537 rc = 1;
2538 goto closefs;
2539 }
2540 sb->s_checkinterval = interval;
2541 ext2fs_mark_super_dirty(fs);
2542 printf(_("Setting interval between checks to %lu seconds\n"),
2543 interval);
2544 }
2545 if (m_flag) {
2546 ext2fs_r_blocks_count_set(sb, reserved_ratio *
2547 ext2fs_blocks_count(sb) / 100.0);
2548 ext2fs_mark_super_dirty(fs);
2549 printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"),
2550 reserved_ratio, ext2fs_r_blocks_count(sb));
2551 }
2552 if (r_flag) {
2553 if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
2554 com_err(program_name, 0,
2555 _("reserved blocks count is too big (%llu)"),
2556 reserved_blocks);
2557 rc = 1;
2558 goto closefs;
2559 }
2560 ext2fs_r_blocks_count_set(sb, reserved_blocks);
2561 ext2fs_mark_super_dirty(fs);
2562 printf(_("Setting reserved blocks count to %llu\n"),
2563 reserved_blocks);
2564 }
2565 if (s_flag == 1) {
2566 if (sb->s_feature_ro_compat &
2567 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
2568 fputs(_("\nThe filesystem already has sparse "
2569 "superblocks.\n"), stderr);
2570 else {
2571 sb->s_feature_ro_compat |=
2572 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
2573 sb->s_state &= ~EXT2_VALID_FS;
2574 ext2fs_mark_super_dirty(fs);
2575 printf(_("\nSparse superblock flag set. %s"),
2576 _(please_fsck));
2577 }
2578 }
2579 if (s_flag == 0) {
2580 fputs(_("\nClearing the sparse superflag not supported.\n"),
2581 stderr);
2582 rc = 1;
2583 goto closefs;
2584 }
2585 if (T_flag) {
2586 sb->s_lastcheck = last_check_time;
2587 ext2fs_mark_super_dirty(fs);
2588 printf(_("Setting time filesystem last checked to %s\n"),
2589 ctime(&last_check_time));
2590 }
2591 if (u_flag) {
2592 sb->s_def_resuid = resuid;
2593 ext2fs_mark_super_dirty(fs);
2594 printf(_("Setting reserved blocks uid to %lu\n"), resuid);
2595 }
2596 if (L_flag) {
2597 if (strlen(new_label) > sizeof(sb->s_volume_name))
2598 fputs(_("Warning: label too long, truncating.\n"),
2599 stderr);
2600 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
2601 strncpy(sb->s_volume_name, new_label,
2602 sizeof(sb->s_volume_name));
2603 ext2fs_mark_super_dirty(fs);
2604 }
2605 if (M_flag) {
2606 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
2607 strncpy(sb->s_last_mounted, new_last_mounted,
2608 sizeof(sb->s_last_mounted));
2609 ext2fs_mark_super_dirty(fs);
2610 }
2611 if (mntopts_cmd) {
2612 rc = update_mntopts(fs, mntopts_cmd);
2613 if (rc)
2614 goto closefs;
2615 }
2616 if (features_cmd) {
2617 rc = update_feature_set(fs, features_cmd);
2618 if (rc)
2619 goto closefs;
2620 }
2621 if (extended_cmd) {
2622 rc = parse_extended_opts(fs, extended_cmd);
2623 if (rc)
2624 goto closefs;
2625 if (clear_mmp && !f_flag) {
2626 fputs(_("Error in using clear_mmp. "
2627 "It must be used with -f\n"),
2628 stderr);
2629 goto closefs;
2630 }
2631 }
2632 if (clear_mmp) {
2633 rc = ext2fs_mmp_clear(fs);
2634 goto closefs;
2635 }
2636 if (journal_size || journal_device) {
2637 rc = add_journal(fs);
2638 if (rc)
2639 goto closefs;
2640 }
2641
2642 if (Q_flag) {
2643 if (mount_flags & EXT2_MF_MOUNTED) {
2644 fputs(_("The quota feature may only be changed when "
2645 "the filesystem is unmounted.\n"), stderr);
2646 rc = 1;
2647 goto closefs;
2648 }
2649 handle_quota_options(fs);
2650 }
2651
2652 if (U_flag) {
2653 int set_csum = 0;
2654 dgrp_t i;
2655
2656 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
2657 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
2658 /*
2659 * Changing the UUID requires rewriting all metadata,
2660 * which can race with a mounted fs. Don't allow that.
2661 */
2662 if (mount_flags & EXT2_MF_MOUNTED) {
2663 fputs(_("The UUID may only be "
2664 "changed when the filesystem is "
2665 "unmounted.\n"), stderr);
2666 exit(1);
2667 }
2668
2669 if (check_fsck_needed(fs))
2670 exit(1);
2671 }
2672
2673 if (ext2fs_has_group_desc_csum(fs)) {
2674 /*
2675 * Determine if the block group checksums are
2676 * correct so we know whether or not to set
2677 * them later on.
2678 */
2679 for (i = 0; i < fs->group_desc_count; i++)
2680 if (!ext2fs_group_desc_csum_verify(fs, i))
2681 break;
2682 if (i >= fs->group_desc_count)
2683 set_csum = 1;
2684 }
2685 if ((strcasecmp(new_UUID, "null") == 0) ||
2686 (strcasecmp(new_UUID, "clear") == 0)) {
2687 uuid_clear(sb->s_uuid);
2688 } else if (strcasecmp(new_UUID, "time") == 0) {
2689 uuid_generate_time(sb->s_uuid);
2690 } else if (strcasecmp(new_UUID, "random") == 0) {
2691 uuid_generate(sb->s_uuid);
2692 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
2693 com_err(program_name, 0, _("Invalid UUID format\n"));
2694 rc = 1;
2695 goto closefs;
2696 }
2697 ext2fs_init_csum_seed(fs);
2698 if (set_csum) {
2699 for (i = 0; i < fs->group_desc_count; i++)
2700 ext2fs_group_desc_csum_set(fs, i);
2701 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
2702 }
2703 ext2fs_mark_super_dirty(fs);
2704 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
2705 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
2706 rewrite_checksums = 1;
2707 }
2708 if (rewrite_checksums)
2709 rewrite_metadata_checksums(fs);
2710 if (I_flag) {
2711 if (mount_flags & EXT2_MF_MOUNTED) {
2712 fputs(_("The inode size may only be "
2713 "changed when the filesystem is "
2714 "unmounted.\n"), stderr);
2715 rc = 1;
2716 goto closefs;
2717 }
2718 if (fs->super->s_feature_incompat &
2719 EXT4_FEATURE_INCOMPAT_FLEX_BG) {
2720 fputs(_("Changing the inode size not supported for "
2721 "filesystems with the flex_bg\n"
2722 "feature enabled.\n"),
2723 stderr);
2724 rc = 1;
2725 goto closefs;
2726 }
2727 /*
2728 * We want to update group descriptor also
2729 * with the new free inode count
2730 */
2731 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
2732 if (resize_inode(fs, new_inode_size) == 0) {
2733 printf(_("Setting inode size %lu\n"),
2734 new_inode_size);
2735 } else {
2736 printf(_("Failed to change inode size\n"));
2737 rc = 1;
2738 goto closefs;
2739 }
2740 }
2741
2742 if (l_flag)
2743 list_super(sb);
2744 if (stride_set) {
2745 sb->s_raid_stride = stride;
2746 ext2fs_mark_super_dirty(fs);
2747 printf(_("Setting stride size to %d\n"), stride);
2748 }
2749 if (stripe_width_set) {
2750 sb->s_raid_stripe_width = stripe_width;
2751 ext2fs_mark_super_dirty(fs);
2752 printf(_("Setting stripe width to %d\n"), stripe_width);
2753 }
2754 if (ext_mount_opts) {
2755 strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts,
2756 sizeof(fs->super->s_mount_opts));
2757 fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0;
2758 ext2fs_mark_super_dirty(fs);
2759 printf(_("Setting extended default mount options to '%s'\n"),
2760 ext_mount_opts);
2761 free(ext_mount_opts);
2762 }
2763 free(device_name);
2764 remove_error_table(&et_ext2_error_table);
2765
2766 closefs:
2767 if (rc) {
2768 ext2fs_mmp_stop(fs);
2769 exit(1);
2770 }
2771
2772 return (ext2fs_close(fs) ? 1 : 0);
2773 }