]>
Commit | Line | Data |
---|---|---|
24b2c7a7 TT |
1 | /* |
2 | * main.c --- ext2 resizer main program | |
3 | * | |
0cee8a5c TT |
4 | * Copyright (C) 1997, 1998 by Theodore Ts'o and |
5 | * PowerQuest, Inc. | |
6 | * | |
55f4cbd9 | 7 | * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 by Theodore Ts'o |
efc6f628 | 8 | * |
24b2c7a7 | 9 | * %Begin-Header% |
0cee8a5c TT |
10 | * This file may be redistributed under the terms of the GNU Public |
11 | * License. | |
24b2c7a7 TT |
12 | * %End-Header% |
13 | */ | |
14 | ||
f1644c32 | 15 | #ifndef _LARGEFILE_SOURCE |
fe07357f | 16 | #define _LARGEFILE_SOURCE |
f1644c32 TT |
17 | #endif |
18 | #ifndef _LARGEFILE64_SOURCE | |
fe07357f | 19 | #define _LARGEFILE64_SOURCE |
f1644c32 | 20 | #endif |
fe07357f | 21 | |
d1154eb4 | 22 | #include "config.h" |
c762c8e6 TT |
23 | #ifdef HAVE_GETOPT_H |
24 | #include <getopt.h> | |
373b8337 TT |
25 | #else |
26 | extern char *optarg; | |
27 | extern int optind; | |
c762c8e6 | 28 | #endif |
fe07357f | 29 | #include <unistd.h> |
f38cf3cb TT |
30 | #ifdef HAVE_STDLIB_H |
31 | #include <stdlib.h> | |
32 | #endif | |
fe07357f | 33 | #include <sys/types.h> |
116db1b5 | 34 | #include <sys/stat.h> |
fe07357f | 35 | #include <fcntl.h> |
03f9fd2a | 36 | #include <libgen.h> |
c762c8e6 | 37 | |
55f4cbd9 TT |
38 | #include "e2p/e2p.h" |
39 | ||
24b2c7a7 TT |
40 | #include "resize2fs.h" |
41 | ||
0cee8a5c | 42 | #include "../version.h" |
2e561e02 | 43 | |
f404167d TT |
44 | char *program_name; |
45 | static char *device_name, *io_options; | |
24b2c7a7 | 46 | |
dfcdc32f | 47 | static void usage (char *prog) |
24b2c7a7 | 48 | { |
199ddaaa | 49 | fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] " |
03f9fd2a DW |
50 | "[-p] device [-b|-s|new_size] [-z undo_file]\n\n"), |
51 | prog); | |
2e561e02 | 52 | |
24b2c7a7 TT |
53 | exit (1); |
54 | } | |
55 | ||
3b627e8d TT |
56 | static errcode_t resize_progress_func(ext2_resize_t rfs, int pass, |
57 | unsigned long cur, unsigned long max) | |
63b44fbe TT |
58 | { |
59 | ext2_sim_progmeter progress; | |
60 | const char *label; | |
61 | errcode_t retval; | |
62 | ||
63 | progress = (ext2_sim_progmeter) rfs->prog_data; | |
f4b2a6db | 64 | if (max == 0) |
3b627e8d | 65 | return 0; |
63b44fbe TT |
66 | if (cur == 0) { |
67 | if (progress) | |
68 | ext2fs_progress_close(progress); | |
69 | progress = 0; | |
70 | switch (pass) { | |
a8519a2d | 71 | case E2_RSZ_EXTEND_ITABLE_PASS: |
a13575f4 | 72 | label = _("Extending the inode table"); |
63b44fbe TT |
73 | break; |
74 | case E2_RSZ_BLOCK_RELOC_PASS: | |
a13575f4 | 75 | label = _("Relocating blocks"); |
63b44fbe | 76 | break; |
a8519a2d | 77 | case E2_RSZ_INODE_SCAN_PASS: |
a13575f4 | 78 | label = _("Scanning inode table"); |
63b44fbe TT |
79 | break; |
80 | case E2_RSZ_INODE_REF_UPD_PASS: | |
a13575f4 | 81 | label = _("Updating inode references"); |
63b44fbe TT |
82 | break; |
83 | case E2_RSZ_MOVE_ITABLE_PASS: | |
a13575f4 | 84 | label = _("Moving inode table"); |
63b44fbe | 85 | break; |
a8519a2d | 86 | default: |
a13575f4 | 87 | label = _("Unknown pass?!?"); |
a8519a2d | 88 | break; |
63b44fbe | 89 | } |
a13575f4 | 90 | printf(_("Begin pass %d (max = %lu)\n"), pass, max); |
63b44fbe TT |
91 | retval = ext2fs_progress_init(&progress, label, 30, |
92 | 40, max, 0); | |
93 | if (retval) | |
94 | progress = 0; | |
95 | rfs->prog_data = (void *) progress; | |
96 | } | |
97 | if (progress) | |
98 | ext2fs_progress_update(progress, cur); | |
99 | if (cur >= max) { | |
100 | if (progress) | |
101 | ext2fs_progress_close(progress); | |
102 | progress = 0; | |
103 | rfs->prog_data = 0; | |
104 | } | |
3b627e8d | 105 | return 0; |
63b44fbe TT |
106 | } |
107 | ||
46c5490d TT |
108 | static void determine_fs_stride(ext2_filsys fs) |
109 | { | |
110 | unsigned int group; | |
111 | unsigned long long sum; | |
5e27a274 | 112 | unsigned int has_sb, prev_has_sb = 0, num; |
46c5490d | 113 | int i_stride, b_stride; |
2273a17a | 114 | int flexbg_size = 1 << fs->super->s_log_groups_per_flex; |
46c5490d | 115 | |
96c6a3ac TT |
116 | if (fs->stride) |
117 | return; | |
46c5490d TT |
118 | num = 0; sum = 0; |
119 | for (group = 0; group < fs->group_desc_count; group++) { | |
120 | has_sb = ext2fs_bg_has_super(fs, group); | |
121 | if (group == 0 || has_sb != prev_has_sb) | |
122 | goto next; | |
d7cca6b0 VAH |
123 | b_stride = ext2fs_block_bitmap_loc(fs, group) - |
124 | ext2fs_block_bitmap_loc(fs, group - 1) - | |
46c5490d | 125 | fs->super->s_blocks_per_group; |
d7cca6b0 VAH |
126 | i_stride = ext2fs_inode_bitmap_loc(fs, group) - |
127 | ext2fs_inode_bitmap_loc(fs, group - 1) - | |
46c5490d TT |
128 | fs->super->s_blocks_per_group; |
129 | if (b_stride != i_stride || | |
2273a17a DW |
130 | b_stride < 0 || |
131 | (flexbg_size > 1 && (group % flexbg_size == 0))) | |
46c5490d TT |
132 | goto next; |
133 | ||
134 | /* printf("group %d has stride %d\n", group, b_stride); */ | |
135 | sum += b_stride; | |
136 | num++; | |
efc6f628 | 137 | |
46c5490d TT |
138 | next: |
139 | prev_has_sb = has_sb; | |
140 | } | |
141 | ||
142 | if (fs->group_desc_count > 12 && num < 3) | |
143 | sum = 0; | |
144 | ||
145 | if (num) | |
146 | fs->stride = sum / num; | |
147 | else | |
148 | fs->stride = 0; | |
149 | ||
96c6a3ac TT |
150 | fs->super->s_raid_stride = fs->stride; |
151 | ext2fs_mark_super_dirty(fs); | |
152 | ||
46c5490d TT |
153 | #if 0 |
154 | if (fs->stride) | |
155 | printf("Using RAID stride of %d\n", fs->stride); | |
156 | #endif | |
157 | } | |
158 | ||
0d89e5ac | 159 | static void bigalloc_check(ext2_filsys fs, int force) |
a713a7fe | 160 | { |
21e37be6 | 161 | if (!force && ext2fs_has_feature_bigalloc(fs->super)) { |
45ff69ff AD |
162 | fprintf(stderr, "%s", _("\nResizing bigalloc file systems has " |
163 | "not been fully tested. Proceed at\n" | |
164 | "your own risk! Use the force option " | |
165 | "if you want to go ahead anyway.\n\n")); | |
a713a7fe TT |
166 | exit(1); |
167 | } | |
168 | } | |
169 | ||
62f9bd0e | 170 | static int resize2fs_setup_tdb(const char *device, char *undo_file, |
03f9fd2a DW |
171 | io_manager *io_ptr) |
172 | { | |
173 | errcode_t retval = ENOMEM; | |
62f9bd0e TT |
174 | const char *tdb_dir = NULL; |
175 | char *tdb_file = NULL; | |
03f9fd2a | 176 | char *dev_name, *tmp_name; |
03f9fd2a DW |
177 | |
178 | /* (re)open a specific undo file */ | |
179 | if (undo_file && undo_file[0] != 0) { | |
b0851392 DW |
180 | retval = set_undo_io_backing_manager(*io_ptr); |
181 | if (retval) | |
182 | goto err; | |
03f9fd2a DW |
183 | *io_ptr = undo_io_manager; |
184 | retval = set_undo_io_backup_file(undo_file); | |
185 | if (retval) | |
186 | goto err; | |
187 | printf(_("Overwriting existing filesystem; this can be undone " | |
188 | "using the command:\n" | |
189 | " e2undo %s %s\n\n"), | |
62f9bd0e | 190 | undo_file, device); |
b0851392 | 191 | return retval; |
03f9fd2a DW |
192 | } |
193 | ||
194 | /* | |
195 | * Configuration via a conf file would be | |
196 | * nice | |
197 | */ | |
198 | tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); | |
b0851392 DW |
199 | if (!tdb_dir) |
200 | tdb_dir = "/var/lib/e2fsprogs"; | |
03f9fd2a | 201 | |
b0851392 DW |
202 | if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || |
203 | access(tdb_dir, W_OK)) | |
03f9fd2a | 204 | return 0; |
03f9fd2a | 205 | |
62f9bd0e | 206 | tmp_name = strdup(device); |
03f9fd2a DW |
207 | if (!tmp_name) |
208 | goto errout; | |
209 | dev_name = basename(tmp_name); | |
b0851392 | 210 | tdb_file = malloc(strlen(tdb_dir) + 11 + strlen(dev_name) + 7 + 1); |
03f9fd2a DW |
211 | if (!tdb_file) { |
212 | free(tmp_name); | |
213 | goto errout; | |
214 | } | |
215 | sprintf(tdb_file, "%s/resize2fs-%s.e2undo", tdb_dir, dev_name); | |
216 | free(tmp_name); | |
217 | ||
218 | if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { | |
219 | retval = errno; | |
b0851392 DW |
220 | com_err(program_name, retval, |
221 | _("while trying to delete %s"), tdb_file); | |
03f9fd2a DW |
222 | goto errout; |
223 | } | |
224 | ||
b0851392 DW |
225 | retval = set_undo_io_backing_manager(*io_ptr); |
226 | if (retval) | |
227 | goto errout; | |
03f9fd2a DW |
228 | *io_ptr = undo_io_manager; |
229 | retval = set_undo_io_backup_file(tdb_file); | |
230 | if (retval) | |
231 | goto errout; | |
232 | printf(_("Overwriting existing filesystem; this can be undone " | |
233 | "using the command:\n" | |
62f9bd0e | 234 | " e2undo %s %s\n\n"), tdb_file, device); |
03f9fd2a | 235 | |
03f9fd2a DW |
236 | free(tdb_file); |
237 | return 0; | |
03f9fd2a | 238 | errout: |
03f9fd2a DW |
239 | free(tdb_file); |
240 | err: | |
241 | com_err(program_name, retval, "%s", | |
242 | _("while trying to setup undo file\n")); | |
243 | return retval; | |
244 | } | |
245 | ||
0a617317 | 246 | int main (int argc, char ** argv) |
24b2c7a7 TT |
247 | { |
248 | errcode_t retval; | |
249 | ext2_filsys fs; | |
250 | int c; | |
05e112a1 | 251 | int flags = 0; |
c762c8e6 | 252 | int flush = 0; |
f4b2a6db | 253 | int force = 0; |
5d2ef12f | 254 | int io_flags = 0; |
199ddaaa JB |
255 | int force_min_size = 0; |
256 | int print_min_size = 0; | |
fe07357f | 257 | int fd, ret; |
8728d506 VAH |
258 | blk64_t new_size = 0; |
259 | blk64_t max_size = 0; | |
260 | blk64_t min_size = 0; | |
24b2c7a7 | 261 | io_manager io_ptr; |
55f4cbd9 | 262 | char *new_size_str = 0; |
46c5490d | 263 | int use_stride = -1; |
7270fbe7 | 264 | ext2fs_struct_stat st_buf; |
fe07357f | 265 | __s64 new_file_size; |
54434927 | 266 | unsigned int sys_page_size = 4096; |
deae5e80 | 267 | unsigned int blocksize; |
a7ccdff8 | 268 | long sysval; |
bf69235a | 269 | int len, mount_flags; |
03f9fd2a | 270 | char *mtpt, *undo_file = NULL; |
ddc32a04 TT |
271 | |
272 | #ifdef ENABLE_NLS | |
273 | setlocale(LC_MESSAGES, ""); | |
274 | setlocale(LC_CTYPE, ""); | |
275 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); | |
276 | textdomain(NLS_CAT_NAME); | |
9d4507c5 | 277 | set_com_err_gettext(gettext); |
ddc32a04 TT |
278 | #endif |
279 | ||
a6d8302b | 280 | add_error_table(&et_ext2_error_table); |
24b2c7a7 | 281 | |
f35fd3d5 | 282 | fprintf (stderr, "resize2fs %s (%s)\n", |
ba0af756 | 283 | E2FSPROGS_VERSION, E2FSPROGS_DATE); |
24b2c7a7 TT |
284 | if (argc && *argv) |
285 | program_name = *argv; | |
2e561e02 | 286 | |
03f9fd2a | 287 | while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) { |
24b2c7a7 TT |
288 | switch (c) { |
289 | case 'h': | |
290 | usage(program_name); | |
291 | break; | |
f4b2a6db TT |
292 | case 'f': |
293 | force = 1; | |
294 | break; | |
c762c8e6 TT |
295 | case 'F': |
296 | flush = 1; | |
297 | break; | |
199ddaaa JB |
298 | case 'M': |
299 | force_min_size = 1; | |
300 | break; | |
301 | case 'P': | |
302 | print_min_size = 1; | |
303 | break; | |
05e112a1 TT |
304 | case 'd': |
305 | flags |= atoi(optarg); | |
306 | break; | |
307 | case 'p': | |
308 | flags |= RESIZE_PERCENT_COMPLETE; | |
309 | break; | |
46c5490d TT |
310 | case 'S': |
311 | use_stride = atoi(optarg); | |
312 | break; | |
fe12931f DW |
313 | case 'b': |
314 | flags |= RESIZE_ENABLE_64BIT; | |
315 | break; | |
316 | case 's': | |
317 | flags |= RESIZE_DISABLE_64BIT; | |
318 | break; | |
03f9fd2a DW |
319 | case 'z': |
320 | undo_file = optarg; | |
321 | break; | |
24b2c7a7 | 322 | default: |
f4b2a6db | 323 | usage(program_name); |
24b2c7a7 TT |
324 | } |
325 | } | |
f4b2a6db TT |
326 | if (optind == argc) |
327 | usage(program_name); | |
2e561e02 | 328 | |
24b2c7a7 | 329 | device_name = argv[optind++]; |
55f4cbd9 TT |
330 | if (optind < argc) |
331 | new_size_str = argv[optind++]; | |
f4b2a6db TT |
332 | if (optind < argc) |
333 | usage(program_name); | |
efc6f628 | 334 | |
2e8ca9a2 TT |
335 | io_options = strchr(device_name, '?'); |
336 | if (io_options) | |
337 | *io_options++ = 0; | |
338 | ||
bf69235a TT |
339 | /* |
340 | * Figure out whether or not the device is mounted, and if it is | |
341 | * where it is mounted. | |
342 | */ | |
343 | len=80; | |
344 | while (1) { | |
345 | mtpt = malloc(len); | |
346 | if (!mtpt) | |
347 | return ENOMEM; | |
348 | mtpt[len-1] = 0; | |
efc6f628 | 349 | retval = ext2fs_check_mount_point(device_name, &mount_flags, |
bf69235a TT |
350 | mtpt, len); |
351 | if (retval) { | |
352 | com_err("ext2fs_check_mount_point", retval, | |
353 | _("while determining whether %s is mounted."), | |
354 | device_name); | |
355 | exit(1); | |
356 | } | |
3a4d9869 | 357 | if (!(mount_flags & EXT2_MF_MOUNTED) || (mtpt[len-1] == 0)) |
bf69235a TT |
358 | break; |
359 | free(mtpt); | |
360 | len = 2 * len; | |
361 | } | |
fe07357f | 362 | |
c4012e5a | 363 | fd = ext2fs_open_file(device_name, O_RDWR, 0); |
fe07357f TT |
364 | if (fd < 0) { |
365 | com_err("open", errno, _("while opening %s"), | |
366 | device_name); | |
367 | exit(1); | |
368 | } | |
369 | ||
7270fbe7 | 370 | ret = ext2fs_fstat(fd, &st_buf); |
fe07357f | 371 | if (ret < 0) { |
efc6f628 | 372 | com_err("open", errno, |
fe07357f TT |
373 | _("while getting stat information for %s"), |
374 | device_name); | |
375 | exit(1); | |
376 | } | |
efc6f628 | 377 | |
c762c8e6 | 378 | if (flush) { |
48e08e03 TT |
379 | retval = ext2fs_sync_device(fd, 1); |
380 | if (retval) { | |
efc6f628 | 381 | com_err(argv[0], retval, |
a13575f4 | 382 | _("while trying to flush %s"), |
c762c8e6 TT |
383 | device_name); |
384 | exit(1); | |
385 | } | |
fe07357f TT |
386 | } |
387 | ||
388 | if (!S_ISREG(st_buf.st_mode )) { | |
c762c8e6 | 389 | close(fd); |
fe07357f | 390 | fd = -1; |
c762c8e6 TT |
391 | } |
392 | ||
f38cf3cb TT |
393 | #ifdef CONFIG_TESTIO_DEBUG |
394 | if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { | |
05e112a1 TT |
395 | io_ptr = test_io_manager; |
396 | test_io_backing_manager = unix_io_manager; | |
efc6f628 | 397 | } else |
f38cf3cb | 398 | #endif |
05e112a1 TT |
399 | io_ptr = unix_io_manager; |
400 | ||
5d2ef12f TT |
401 | if (!(mount_flags & EXT2_MF_MOUNTED)) |
402 | io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE; | |
04cb6f58 SL |
403 | |
404 | io_flags |= EXT2_FLAG_64BITS; | |
03f9fd2a DW |
405 | if (undo_file) { |
406 | retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr); | |
407 | if (retval) | |
408 | exit(1); | |
409 | } | |
efc6f628 | 410 | retval = ext2fs_open2(device_name, io_options, io_flags, |
2e8ca9a2 | 411 | 0, 0, io_ptr, &fs); |
24b2c7a7 | 412 | if (retval) { |
45ff69ff AD |
413 | com_err(program_name, retval, _("while trying to open %s"), |
414 | device_name); | |
415 | printf("%s", _("Couldn't find valid filesystem superblock.\n")); | |
24b2c7a7 TT |
416 | exit (1); |
417 | } | |
baab9f43 | 418 | fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; |
236efede | 419 | |
0462fd6d ES |
420 | /* |
421 | * Before acting on an unmounted filesystem, make sure it's ok, | |
422 | * unless the user is forcing it. | |
423 | * | |
424 | * We do ERROR and VALID checks even if we're only printing the | |
425 | * minimimum size, because traversal of a badly damaged filesystem | |
426 | * can cause issues as well. We don't require it to be fscked after | |
427 | * the last mount time in this case, though, as this is a bit less | |
428 | * risky. | |
429 | */ | |
430 | if (!force && !(mount_flags & EXT2_MF_MOUNTED)) { | |
431 | int checkit = 0; | |
432 | ||
433 | if (fs->super->s_state & EXT2_ERROR_FS) | |
434 | checkit = 1; | |
435 | ||
436 | if ((fs->super->s_state & EXT2_VALID_FS) == 0) | |
437 | checkit = 1; | |
438 | ||
439 | if ((fs->super->s_lastcheck < fs->super->s_mtime) && | |
440 | !print_min_size) | |
441 | checkit = 1; | |
442 | ||
7f5ba7cc TT |
443 | if ((fs->super->s_free_blocks_count > fs->super->s_blocks_count) || |
444 | (fs->super->s_free_inodes_count > fs->super->s_inodes_count)) | |
445 | checkit = 1; | |
446 | ||
0462fd6d | 447 | if (checkit) { |
7d7a8fe4 ES |
448 | fprintf(stderr, |
449 | _("Please run 'e2fsck -f %s' first.\n\n"), | |
450 | device_name); | |
451 | exit(1); | |
452 | } | |
453 | } | |
454 | ||
101c84f2 TT |
455 | /* |
456 | * Check for compatibility with the feature sets. We need to | |
457 | * be more stringent than ext2fs_open(). | |
458 | */ | |
76dd5e5c | 459 | if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) { |
101c84f2 TT |
460 | com_err(program_name, EXT2_ET_UNSUPP_FEATURE, |
461 | "(%s)", device_name); | |
462 | exit(1); | |
463 | } | |
a8d632a4 | 464 | |
e231f175 | 465 | min_size = calculate_minimum_resize_size(fs, flags); |
0d04d88a | 466 | |
199ddaaa | 467 | if (print_min_size) { |
8728d506 | 468 | printf(_("Estimated minimum size of the filesystem: %llu\n"), |
0d04d88a | 469 | min_size); |
199ddaaa JB |
470 | exit(0); |
471 | } | |
472 | ||
a7ccdff8 TT |
473 | /* Determine the system page size if possible */ |
474 | #ifdef HAVE_SYSCONF | |
475 | #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) | |
476 | #define _SC_PAGESIZE _SC_PAGE_SIZE | |
477 | #endif | |
478 | #ifdef _SC_PAGESIZE | |
479 | sysval = sysconf(_SC_PAGESIZE); | |
480 | if (sysval > 0) | |
481 | sys_page_size = sysval; | |
482 | #endif /* _SC_PAGESIZE */ | |
483 | #endif /* HAVE_SYSCONF */ | |
484 | ||
f4b2a6db TT |
485 | /* |
486 | * Get the size of the containing partition, and use this for | |
fe07357f | 487 | * defaults and for making sure the new filesystem doesn't |
f4b2a6db TT |
488 | * exceed the partition size. |
489 | */ | |
deae5e80 TT |
490 | blocksize = fs->blocksize; |
491 | retval = ext2fs_get_device_size2(device_name, blocksize, | |
8728d506 | 492 | &max_size); |
f4b2a6db | 493 | if (retval) { |
45ff69ff | 494 | com_err(program_name, retval, "%s", |
a13575f4 | 495 | _("while trying to determine filesystem size")); |
f4b2a6db TT |
496 | exit(1); |
497 | } | |
199ddaaa | 498 | if (force_min_size) |
1d8af189 | 499 | new_size = min_size; |
199ddaaa | 500 | else if (new_size_str) { |
8728d506 VAH |
501 | new_size = parse_num_blocks2(new_size_str, |
502 | fs->super->s_log_block_size); | |
279a000f ES |
503 | if (new_size == 0) { |
504 | com_err(program_name, 0, | |
505 | _("Invalid new size: %s\n"), new_size_str); | |
506 | exit(1); | |
507 | } | |
55f4cbd9 | 508 | } else { |
f4b2a6db | 509 | new_size = max_size; |
a7ccdff8 | 510 | /* Round down to an even multiple of a pagesize */ |
deae5e80 | 511 | if (sys_page_size > blocksize) |
1e19b01b | 512 | new_size &= ~((blk64_t)((sys_page_size / blocksize)-1)); |
a7ccdff8 | 513 | } |
fe12931f DW |
514 | /* If changing 64bit, don't change the filesystem size. */ |
515 | if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { | |
516 | new_size = ext2fs_blocks_count(fs->super); | |
517 | } | |
21e37be6 | 518 | if (!ext2fs_has_feature_64bit(fs->super)) { |
ea38e503 TT |
519 | /* Take 16T down to 2^32-1 blocks */ |
520 | if (new_size == (1ULL << 32)) | |
521 | new_size--; | |
522 | else if (new_size > (1ULL << 32)) { | |
45ff69ff | 523 | com_err(program_name, 0, "%s", |
ea38e503 TT |
524 | _("New size too large to be " |
525 | "expressed in 32 bits\n")); | |
526 | exit(1); | |
527 | } | |
528 | } | |
46c5490d | 529 | |
0d04d88a ES |
530 | if (!force && new_size < min_size) { |
531 | com_err(program_name, 0, | |
8728d506 | 532 | _("New size smaller than minimum (%llu)\n"), min_size); |
0d04d88a ES |
533 | exit(1); |
534 | } | |
46c5490d | 535 | if (use_stride >= 0) { |
de8f3a76 | 536 | if (use_stride >= (int) fs->super->s_blocks_per_group) { |
45ff69ff | 537 | com_err(program_name, 0, "%s", |
46c5490d TT |
538 | _("Invalid stride length")); |
539 | exit(1); | |
540 | } | |
96c6a3ac TT |
541 | fs->stride = fs->super->s_raid_stride = use_stride; |
542 | ext2fs_mark_super_dirty(fs); | |
46c5490d TT |
543 | } else |
544 | determine_fs_stride(fs); | |
efc6f628 | 545 | |
116db1b5 TT |
546 | /* |
547 | * If we are resizing a plain file, and it's not big enough, | |
548 | * automatically extend it in a sparse fashion by writing the | |
549 | * last requested block. | |
550 | */ | |
deae5e80 | 551 | new_file_size = ((__u64) new_size) * blocksize; |
efc6f628 | 552 | if ((__u64) new_file_size > |
fe07357f TT |
553 | (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1) |
554 | fd = -1; | |
555 | if ((new_file_size > st_buf.st_size) && | |
556 | (fd > 0)) { | |
557 | if ((ext2fs_llseek(fd, new_file_size-1, SEEK_SET) >= 0) && | |
558 | (write(fd, "0", 1) == 1)) | |
116db1b5 | 559 | max_size = new_size; |
116db1b5 | 560 | } |
f4b2a6db | 561 | if (!force && (new_size > max_size)) { |
a13575f4 | 562 | fprintf(stderr, _("The containing partition (or device)" |
8728d506 VAH |
563 | " is only %llu (%dk) blocks.\nYou requested a new size" |
564 | " of %llu blocks.\n\n"), max_size, | |
deae5e80 | 565 | blocksize / 1024, new_size); |
f4b2a6db TT |
566 | exit(1); |
567 | } | |
fe12931f DW |
568 | if ((flags & RESIZE_DISABLE_64BIT) && (flags & RESIZE_ENABLE_64BIT)) { |
569 | fprintf(stderr, _("Cannot set and unset 64bit feature.\n")); | |
570 | exit(1); | |
571 | } else if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { | |
572 | if (new_size >= (1ULL << 32)) { | |
573 | fprintf(stderr, _("Cannot change the 64bit feature " | |
574 | "on a filesystem that is larger than " | |
575 | "2^32 blocks.\n")); | |
576 | exit(1); | |
577 | } | |
578 | if (mount_flags & EXT2_MF_MOUNTED) { | |
579 | fprintf(stderr, _("Cannot change the 64bit feature " | |
580 | "while the filesystem is mounted.\n")); | |
581 | exit(1); | |
582 | } | |
583 | if (flags & RESIZE_ENABLE_64BIT && | |
21e37be6 | 584 | !ext2fs_has_feature_extents(fs->super)) { |
fe12931f DW |
585 | fprintf(stderr, _("Please enable the extents feature " |
586 | "with tune2fs before enabling the 64bit " | |
587 | "feature.\n")); | |
588 | exit(1); | |
589 | } | |
590 | } else if (new_size == ext2fs_blocks_count(fs->super)) { | |
77255cf3 TT |
591 | fprintf(stderr, _("The filesystem is already %llu (%dk) " |
592 | "blocks long. Nothing to do!\n\n"), new_size, | |
deae5e80 | 593 | blocksize / 1024); |
f4b2a6db TT |
594 | exit(0); |
595 | } | |
fe12931f | 596 | if ((flags & RESIZE_ENABLE_64BIT) && |
21e37be6 | 597 | ext2fs_has_feature_64bit(fs->super)) { |
fe12931f DW |
598 | fprintf(stderr, _("The filesystem is already 64-bit.\n")); |
599 | exit(0); | |
600 | } | |
601 | if ((flags & RESIZE_DISABLE_64BIT) && | |
21e37be6 | 602 | !ext2fs_has_feature_64bit(fs->super)) { |
fe12931f DW |
603 | fprintf(stderr, _("The filesystem is already 32-bit.\n")); |
604 | exit(0); | |
605 | } | |
bf69235a | 606 | if (mount_flags & EXT2_MF_MOUNTED) { |
a713a7fe | 607 | bigalloc_check(fs, force); |
bf69235a TT |
608 | retval = online_resize_fs(fs, mtpt, &new_size, flags); |
609 | } else { | |
a713a7fe | 610 | bigalloc_check(fs, force); |
fe12931f DW |
611 | if (flags & RESIZE_ENABLE_64BIT) |
612 | printf(_("Converting the filesystem to 64-bit.\n")); | |
613 | else if (flags & RESIZE_DISABLE_64BIT) | |
614 | printf(_("Converting the filesystem to 32-bit.\n")); | |
615 | else | |
616 | printf(_("Resizing the filesystem on " | |
617 | "%s to %llu (%dk) blocks.\n"), | |
618 | device_name, new_size, blocksize / 1024); | |
bf69235a TT |
619 | retval = resize_fs(fs, &new_size, flags, |
620 | ((flags & RESIZE_PERCENT_COMPLETE) ? | |
621 | resize_progress_func : 0)); | |
f4b2a6db | 622 | } |
3a4d9869 | 623 | free(mtpt); |
1e1da29f | 624 | if (retval) { |
a13575f4 | 625 | com_err(program_name, retval, _("while trying to resize %s"), |
1e1da29f | 626 | device_name); |
96cdb37e TT |
627 | fprintf(stderr, |
628 | _("Please run 'e2fsck -fy %s' to fix the filesystem\n" | |
629 | "after the aborted resize operation.\n"), | |
630 | device_name); | |
47fee2ef | 631 | ext2fs_close_free(&fs); |
16082112 | 632 | exit(1); |
1e1da29f | 633 | } |
77255cf3 | 634 | printf(_("The filesystem on %s is now %llu (%dk) blocks long.\n\n"), |
deae5e80 | 635 | device_name, new_size, blocksize / 1024); |
fe07357f TT |
636 | |
637 | if ((st_buf.st_size > new_file_size) && | |
638 | (fd > 0)) { | |
261cd396 | 639 | #ifdef HAVE_FTRUNCATE64 |
fb72556a | 640 | retval = ftruncate64(fd, new_file_size); |
fe07357f | 641 | #else |
fb72556a | 642 | retval = 0; |
98dca6c5 TT |
643 | /* Only truncate if new_file_size doesn't overflow off_t */ |
644 | if (((off_t) new_file_size) == new_file_size) | |
fb72556a | 645 | retval = ftruncate(fd, (off_t) new_file_size); |
fe07357f | 646 | #endif |
fb72556a TT |
647 | if (retval) |
648 | com_err(program_name, retval, | |
649 | _("while trying to truncate %s"), | |
650 | device_name); | |
fe07357f TT |
651 | } |
652 | if (fd > 0) | |
653 | close(fd); | |
a6d8302b | 654 | remove_error_table(&et_ext2_error_table); |
0a617317 | 655 | return (0); |
24b2c7a7 | 656 | } |