]>
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 |
24b2c7a7 TT |
8 | * |
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 | ||
fe07357f TT |
15 | #define _LARGEFILE_SOURCE |
16 | #define _LARGEFILE64_SOURCE | |
17 | ||
c762c8e6 TT |
18 | #ifdef HAVE_GETOPT_H |
19 | #include <getopt.h> | |
373b8337 TT |
20 | #else |
21 | extern char *optarg; | |
22 | extern int optind; | |
c762c8e6 | 23 | #endif |
fe07357f TT |
24 | #include <unistd.h> |
25 | #include <sys/types.h> | |
116db1b5 | 26 | #include <sys/stat.h> |
fe07357f | 27 | #include <fcntl.h> |
c762c8e6 | 28 | |
55f4cbd9 TT |
29 | #include "e2p/e2p.h" |
30 | ||
24b2c7a7 TT |
31 | #include "resize2fs.h" |
32 | ||
0cee8a5c | 33 | #include "../version.h" |
2e561e02 | 34 | |
2e8ca9a2 | 35 | char *program_name, *device_name, *io_options; |
24b2c7a7 | 36 | |
dfcdc32f | 37 | static void usage (char *prog) |
24b2c7a7 | 38 | { |
f35fd3d5 TT |
39 | fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-p] " |
40 | "device [new_size]\n\n"), prog); | |
2e561e02 | 41 | |
24b2c7a7 TT |
42 | exit (1); |
43 | } | |
44 | ||
3b627e8d TT |
45 | static errcode_t resize_progress_func(ext2_resize_t rfs, int pass, |
46 | unsigned long cur, unsigned long max) | |
63b44fbe TT |
47 | { |
48 | ext2_sim_progmeter progress; | |
49 | const char *label; | |
50 | errcode_t retval; | |
51 | ||
52 | progress = (ext2_sim_progmeter) rfs->prog_data; | |
f4b2a6db | 53 | if (max == 0) |
3b627e8d | 54 | return 0; |
63b44fbe TT |
55 | if (cur == 0) { |
56 | if (progress) | |
57 | ext2fs_progress_close(progress); | |
58 | progress = 0; | |
59 | switch (pass) { | |
a8519a2d | 60 | case E2_RSZ_EXTEND_ITABLE_PASS: |
a13575f4 | 61 | label = _("Extending the inode table"); |
63b44fbe TT |
62 | break; |
63 | case E2_RSZ_BLOCK_RELOC_PASS: | |
a13575f4 | 64 | label = _("Relocating blocks"); |
63b44fbe | 65 | break; |
a8519a2d | 66 | case E2_RSZ_INODE_SCAN_PASS: |
a13575f4 | 67 | label = _("Scanning inode table"); |
63b44fbe TT |
68 | break; |
69 | case E2_RSZ_INODE_REF_UPD_PASS: | |
a13575f4 | 70 | label = _("Updating inode references"); |
63b44fbe TT |
71 | break; |
72 | case E2_RSZ_MOVE_ITABLE_PASS: | |
a13575f4 | 73 | label = _("Moving inode table"); |
63b44fbe | 74 | break; |
a8519a2d | 75 | default: |
a13575f4 | 76 | label = _("Unknown pass?!?"); |
a8519a2d | 77 | break; |
63b44fbe | 78 | } |
a13575f4 | 79 | printf(_("Begin pass %d (max = %lu)\n"), pass, max); |
63b44fbe TT |
80 | retval = ext2fs_progress_init(&progress, label, 30, |
81 | 40, max, 0); | |
82 | if (retval) | |
83 | progress = 0; | |
84 | rfs->prog_data = (void *) progress; | |
85 | } | |
86 | if (progress) | |
87 | ext2fs_progress_update(progress, cur); | |
88 | if (cur >= max) { | |
89 | if (progress) | |
90 | ext2fs_progress_close(progress); | |
91 | progress = 0; | |
92 | rfs->prog_data = 0; | |
93 | } | |
3b627e8d | 94 | return 0; |
63b44fbe TT |
95 | } |
96 | ||
0a617317 | 97 | int main (int argc, char ** argv) |
24b2c7a7 TT |
98 | { |
99 | errcode_t retval; | |
100 | ext2_filsys fs; | |
101 | int c; | |
05e112a1 | 102 | int flags = 0; |
c762c8e6 | 103 | int flush = 0; |
f4b2a6db | 104 | int force = 0; |
fe07357f | 105 | int fd, ret; |
f4b2a6db TT |
106 | blk_t new_size = 0; |
107 | blk_t max_size = 0; | |
24b2c7a7 | 108 | io_manager io_ptr; |
55f4cbd9 | 109 | char *new_size_str = 0; |
fe07357f TT |
110 | #ifdef HAVE_FSTAT64 |
111 | struct stat64 st_buf; | |
112 | #else | |
116db1b5 | 113 | struct stat st_buf; |
fe07357f TT |
114 | #endif |
115 | __s64 new_file_size; | |
54434927 | 116 | unsigned int sys_page_size = 4096; |
a7ccdff8 | 117 | long sysval; |
bf69235a TT |
118 | int len, mount_flags; |
119 | char *mtpt; | |
ddc32a04 TT |
120 | |
121 | #ifdef ENABLE_NLS | |
122 | setlocale(LC_MESSAGES, ""); | |
123 | setlocale(LC_CTYPE, ""); | |
124 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); | |
125 | textdomain(NLS_CAT_NAME); | |
126 | #endif | |
127 | ||
f4b2a6db | 128 | initialize_ext2_error_table(); |
24b2c7a7 | 129 | |
f35fd3d5 | 130 | fprintf (stderr, "resize2fs %s (%s)\n", |
ba0af756 | 131 | E2FSPROGS_VERSION, E2FSPROGS_DATE); |
24b2c7a7 TT |
132 | if (argc && *argv) |
133 | program_name = *argv; | |
2e561e02 | 134 | |
f4b2a6db | 135 | while ((c = getopt (argc, argv, "d:fFhp")) != EOF) { |
24b2c7a7 TT |
136 | switch (c) { |
137 | case 'h': | |
138 | usage(program_name); | |
139 | break; | |
f4b2a6db TT |
140 | case 'f': |
141 | force = 1; | |
142 | break; | |
c762c8e6 TT |
143 | case 'F': |
144 | flush = 1; | |
145 | break; | |
05e112a1 TT |
146 | case 'd': |
147 | flags |= atoi(optarg); | |
148 | break; | |
149 | case 'p': | |
150 | flags |= RESIZE_PERCENT_COMPLETE; | |
151 | break; | |
24b2c7a7 | 152 | default: |
f4b2a6db | 153 | usage(program_name); |
24b2c7a7 TT |
154 | } |
155 | } | |
f4b2a6db TT |
156 | if (optind == argc) |
157 | usage(program_name); | |
2e561e02 | 158 | |
24b2c7a7 | 159 | device_name = argv[optind++]; |
55f4cbd9 TT |
160 | if (optind < argc) |
161 | new_size_str = argv[optind++]; | |
f4b2a6db TT |
162 | if (optind < argc) |
163 | usage(program_name); | |
164 | ||
2e8ca9a2 TT |
165 | io_options = strchr(device_name, '?'); |
166 | if (io_options) | |
167 | *io_options++ = 0; | |
168 | ||
bf69235a TT |
169 | /* |
170 | * Figure out whether or not the device is mounted, and if it is | |
171 | * where it is mounted. | |
172 | */ | |
173 | len=80; | |
174 | while (1) { | |
175 | mtpt = malloc(len); | |
176 | if (!mtpt) | |
177 | return ENOMEM; | |
178 | mtpt[len-1] = 0; | |
179 | retval = ext2fs_check_mount_point(device_name, &mount_flags, | |
180 | mtpt, len); | |
181 | if (retval) { | |
182 | com_err("ext2fs_check_mount_point", retval, | |
183 | _("while determining whether %s is mounted."), | |
184 | device_name); | |
185 | exit(1); | |
186 | } | |
187 | if (!(mount_flags & EXT2_MF_MOUNTED) || (mtpt[len-1] == 0)) | |
188 | break; | |
189 | free(mtpt); | |
190 | len = 2 * len; | |
191 | } | |
fe07357f TT |
192 | |
193 | #ifdef HAVE_OPEN64 | |
194 | fd = open64(device_name, O_RDWR); | |
195 | #else | |
196 | fd = open(device_name, O_RDWR); | |
197 | #endif | |
198 | if (fd < 0) { | |
199 | com_err("open", errno, _("while opening %s"), | |
200 | device_name); | |
201 | exit(1); | |
202 | } | |
203 | ||
204 | #ifdef HAVE_FSTAT64 | |
205 | ret = fstat64(fd, &st_buf); | |
206 | #else | |
207 | ret = fstat(fd, &st_buf); | |
208 | #endif | |
209 | if (ret < 0) { | |
210 | com_err("open", errno, | |
211 | _("while getting stat information for %s"), | |
212 | device_name); | |
213 | exit(1); | |
214 | } | |
f4b2a6db | 215 | |
c762c8e6 | 216 | if (flush) { |
48e08e03 TT |
217 | retval = ext2fs_sync_device(fd, 1); |
218 | if (retval) { | |
219 | com_err(argv[0], retval, | |
a13575f4 | 220 | _("while trying to flush %s"), |
c762c8e6 TT |
221 | device_name); |
222 | exit(1); | |
223 | } | |
fe07357f TT |
224 | } |
225 | ||
226 | if (!S_ISREG(st_buf.st_mode )) { | |
c762c8e6 | 227 | close(fd); |
fe07357f | 228 | fd = -1; |
c762c8e6 TT |
229 | } |
230 | ||
05e112a1 TT |
231 | if (flags & RESIZE_DEBUG_IO) { |
232 | io_ptr = test_io_manager; | |
233 | test_io_backing_manager = unix_io_manager; | |
234 | } else | |
235 | io_ptr = unix_io_manager; | |
236 | ||
2e8ca9a2 TT |
237 | retval = ext2fs_open2(device_name, io_options, EXT2_FLAG_RW, |
238 | 0, 0, io_ptr, &fs); | |
24b2c7a7 | 239 | if (retval) { |
a13575f4 | 240 | com_err (program_name, retval, _("while trying to open %s"), |
24b2c7a7 | 241 | device_name); |
a13575f4 | 242 | printf (_("Couldn't find valid filesystem superblock.\n")); |
24b2c7a7 TT |
243 | exit (1); |
244 | } | |
101c84f2 TT |
245 | /* |
246 | * Check for compatibility with the feature sets. We need to | |
247 | * be more stringent than ext2fs_open(). | |
248 | */ | |
76dd5e5c | 249 | if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) { |
101c84f2 TT |
250 | com_err(program_name, EXT2_ET_UNSUPP_FEATURE, |
251 | "(%s)", device_name); | |
252 | exit(1); | |
253 | } | |
254 | ||
a7ccdff8 TT |
255 | /* Determine the system page size if possible */ |
256 | #ifdef HAVE_SYSCONF | |
257 | #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) | |
258 | #define _SC_PAGESIZE _SC_PAGE_SIZE | |
259 | #endif | |
260 | #ifdef _SC_PAGESIZE | |
261 | sysval = sysconf(_SC_PAGESIZE); | |
262 | if (sysval > 0) | |
263 | sys_page_size = sysval; | |
264 | #endif /* _SC_PAGESIZE */ | |
265 | #endif /* HAVE_SYSCONF */ | |
266 | ||
f4b2a6db TT |
267 | /* |
268 | * Get the size of the containing partition, and use this for | |
fe07357f | 269 | * defaults and for making sure the new filesystem doesn't |
f4b2a6db TT |
270 | * exceed the partition size. |
271 | */ | |
272 | retval = ext2fs_get_device_size(device_name, fs->blocksize, | |
273 | &max_size); | |
274 | if (retval) { | |
275 | com_err(program_name, retval, | |
a13575f4 | 276 | _("while trying to determine filesystem size")); |
f4b2a6db TT |
277 | exit(1); |
278 | } | |
55f4cbd9 TT |
279 | if (new_size_str) { |
280 | new_size = parse_num_blocks(new_size_str, | |
281 | fs->super->s_log_block_size); | |
282 | if (!new_size) { | |
283 | com_err(program_name, 0, _("bad filesystem size - %s"), | |
284 | new_size_str); | |
285 | exit(1); | |
286 | } | |
287 | } else { | |
f4b2a6db | 288 | new_size = max_size; |
a7ccdff8 TT |
289 | /* Round down to an even multiple of a pagesize */ |
290 | if (sys_page_size > fs->blocksize) | |
291 | new_size &= ~((sys_page_size / fs->blocksize)-1); | |
292 | } | |
792a0881 | 293 | |
116db1b5 TT |
294 | /* |
295 | * If we are resizing a plain file, and it's not big enough, | |
296 | * automatically extend it in a sparse fashion by writing the | |
297 | * last requested block. | |
298 | */ | |
fe07357f TT |
299 | new_file_size = ((__u64) new_size) * fs->blocksize; |
300 | if ((__u64) new_file_size > | |
301 | (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1) | |
302 | fd = -1; | |
303 | if ((new_file_size > st_buf.st_size) && | |
304 | (fd > 0)) { | |
305 | if ((ext2fs_llseek(fd, new_file_size-1, SEEK_SET) >= 0) && | |
306 | (write(fd, "0", 1) == 1)) | |
116db1b5 | 307 | max_size = new_size; |
116db1b5 | 308 | } |
f4b2a6db | 309 | if (!force && (new_size > max_size)) { |
a13575f4 | 310 | fprintf(stderr, _("The containing partition (or device)" |
792a0881 | 311 | " is only %d (%dk) blocks.\nYou requested a new size" |
a13575f4 | 312 | " of %d blocks.\n\n"), max_size, |
792a0881 | 313 | fs->blocksize / 1024, new_size); |
f4b2a6db TT |
314 | exit(1); |
315 | } | |
316 | if (new_size == fs->super->s_blocks_count) { | |
a13575f4 TT |
317 | fprintf(stderr, _("The filesystem is already %d blocks " |
318 | "long. Nothing to do!\n\n"), new_size); | |
f4b2a6db TT |
319 | exit(0); |
320 | } | |
bf69235a TT |
321 | if (mount_flags & EXT2_MF_MOUNTED) { |
322 | retval = online_resize_fs(fs, mtpt, &new_size, flags); | |
323 | } else { | |
324 | if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) || | |
325 | (fs->super->s_state & EXT2_ERROR_FS) || | |
326 | ((fs->super->s_state & EXT2_VALID_FS) == 0))) { | |
327 | fprintf(stderr, | |
328 | _("Please run 'e2fsck -f %s' first.\n\n"), | |
329 | device_name); | |
330 | exit(1); | |
331 | } | |
332 | printf("Resizing the filesystem on %s to %d (%dk) blocks.\n", | |
333 | device_name, new_size, fs->blocksize / 1024); | |
334 | retval = resize_fs(fs, &new_size, flags, | |
335 | ((flags & RESIZE_PERCENT_COMPLETE) ? | |
336 | resize_progress_func : 0)); | |
f4b2a6db | 337 | } |
1e1da29f | 338 | if (retval) { |
a13575f4 | 339 | com_err(program_name, retval, _("while trying to resize %s"), |
1e1da29f TT |
340 | device_name); |
341 | ext2fs_close (fs); | |
16082112 | 342 | exit(1); |
1e1da29f | 343 | } |
a13575f4 | 344 | printf(_("The filesystem on %s is now %d blocks long.\n\n"), |
7e71e4c5 | 345 | device_name, new_size); |
fe07357f TT |
346 | |
347 | if ((st_buf.st_size > new_file_size) && | |
348 | (fd > 0)) { | |
349 | #ifdef HAVE_FSTAT64 | |
350 | ftruncate64(fd, new_file_size); | |
351 | #else | |
352 | ftruncate(fd, (off_t) new_file_size); | |
353 | #endif | |
354 | } | |
355 | if (fd > 0) | |
356 | close(fd); | |
0a617317 | 357 | return (0); |
24b2c7a7 | 358 | } |