main.c revision 76dd5e5c2842fb1a7b858aad3e68b5e9c16890c9
1/* 2 * main.c --- ext2 resizer main program 3 * 4 * Copyright (C) 1997, 1998 by Theodore Ts'o and 5 * PowerQuest, Inc. 6 * 7 * Copyright (C) 1999, 2000, 2001 by Theosore Ts'o 8 * 9 * %Begin-Header% 10 * This file may be redistributed under the terms of the GNU Public 11 * License. 12 * %End-Header% 13 */ 14 15#ifdef HAVE_GETOPT_H 16#include <getopt.h> 17#else 18extern char *optarg; 19extern int optind; 20#endif 21#include <fcntl.h> 22#include <sys/stat.h> 23 24#include "resize2fs.h" 25 26#include "../version.h" 27 28char *program_name, *device_name; 29 30static void usage (char *prog) 31{ 32 fprintf (stderr, _("usage: %s [-d debug_flags] [-f] [-F] [-p] device [new-size]\n\n"), prog); 33 34 exit (1); 35} 36 37static errcode_t resize_progress_func(ext2_resize_t rfs, int pass, 38 unsigned long cur, unsigned long max) 39{ 40 ext2_sim_progmeter progress; 41 const char *label; 42 errcode_t retval; 43 44 progress = (ext2_sim_progmeter) rfs->prog_data; 45 if (max == 0) 46 return 0; 47 if (cur == 0) { 48 if (progress) 49 ext2fs_progress_close(progress); 50 progress = 0; 51 switch (pass) { 52 case E2_RSZ_EXTEND_ITABLE_PASS: 53 label = _("Extending the inode table"); 54 break; 55 case E2_RSZ_BLOCK_RELOC_PASS: 56 label = _("Relocating blocks"); 57 break; 58 case E2_RSZ_INODE_SCAN_PASS: 59 label = _("Scanning inode table"); 60 break; 61 case E2_RSZ_INODE_REF_UPD_PASS: 62 label = _("Updating inode references"); 63 break; 64 case E2_RSZ_MOVE_ITABLE_PASS: 65 label = _("Moving inode table"); 66 break; 67 default: 68 label = _("Unknown pass?!?"); 69 break; 70 } 71 printf(_("Begin pass %d (max = %lu)\n"), pass, max); 72 retval = ext2fs_progress_init(&progress, label, 30, 73 40, max, 0); 74 if (retval) 75 progress = 0; 76 rfs->prog_data = (void *) progress; 77 } 78 if (progress) 79 ext2fs_progress_update(progress, cur); 80 if (cur >= max) { 81 if (progress) 82 ext2fs_progress_close(progress); 83 progress = 0; 84 rfs->prog_data = 0; 85 } 86 return 0; 87} 88 89static void check_mount(char *device) 90{ 91 errcode_t retval; 92 int mount_flags; 93 94 retval = ext2fs_check_if_mounted(device, &mount_flags); 95 if (retval) { 96 com_err(_("ext2fs_check_if_mount"), retval, 97 _("while determining whether %s is mounted."), 98 device); 99 return; 100 } 101 if (!(mount_flags & EXT2_MF_MOUNTED)) 102 return; 103 104 fprintf(stderr, _("%s is mounted; can't resize a " 105 "mounted filesystem!\n\n"), device); 106 exit(1); 107} 108 109 110int main (int argc, char ** argv) 111{ 112 errcode_t retval; 113 ext2_filsys fs; 114 int c; 115 int flags = 0; 116 int flush = 0; 117 int force = 0; 118 int fd; 119 blk_t new_size = 0; 120 blk_t max_size = 0; 121 io_manager io_ptr; 122 char *tmp; 123 struct stat st_buf; 124 125 initialize_ext2_error_table(); 126 127 fprintf (stderr, _("resize2fs %s (%s)\n"), 128 E2FSPROGS_VERSION, E2FSPROGS_DATE); 129 if (argc && *argv) 130 program_name = *argv; 131 132 while ((c = getopt (argc, argv, "d:fFhp")) != EOF) { 133 switch (c) { 134 case 'h': 135 usage(program_name); 136 break; 137 case 'f': 138 force = 1; 139 break; 140 case 'F': 141 flush = 1; 142 break; 143 case 'd': 144 flags |= atoi(optarg); 145 break; 146 case 'p': 147 flags |= RESIZE_PERCENT_COMPLETE; 148 break; 149 default: 150 usage(program_name); 151 } 152 } 153 if (optind == argc) 154 usage(program_name); 155 156 device_name = argv[optind++]; 157 if (optind < argc) { 158 new_size = strtoul(argv[optind++], &tmp, 0); 159 if (*tmp) { 160 com_err(program_name, 0, _("bad filesystem size - %s"), 161 argv[optind - 1]); 162 exit(1); 163 } 164 } 165 if (optind < argc) 166 usage(program_name); 167 168 check_mount(device_name); 169 170 if (flush) { 171 fd = open(device_name, O_RDONLY, 0); 172 173 if (fd < 0) { 174 com_err("open", errno, 175 _("while opening %s for flushing"), 176 device_name); 177 exit(1); 178 } 179 retval = ext2fs_sync_device(fd, 1); 180 if (retval) { 181 com_err(argv[0], retval, 182 _("while trying to flush %s"), 183 device_name); 184 exit(1); 185 } 186 close(fd); 187 } 188 189 if (flags & RESIZE_DEBUG_IO) { 190 io_ptr = test_io_manager; 191 test_io_backing_manager = unix_io_manager; 192 } else 193 io_ptr = unix_io_manager; 194 195 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 196 io_ptr, &fs); 197 if (retval) { 198 com_err (program_name, retval, _("while trying to open %s"), 199 device_name); 200 printf (_("Couldn't find valid filesystem superblock.\n")); 201 exit (1); 202 } 203 /* 204 * Check for compatibility with the feature sets. We need to 205 * be more stringent than ext2fs_open(). 206 */ 207 if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) { 208 com_err(program_name, EXT2_ET_UNSUPP_FEATURE, 209 "(%s)", device_name); 210 exit(1); 211 } 212 213 /* 214 * Get the size of the containing partition, and use this for 215 * defaults and for making sure the new filesystme doesn't 216 * exceed the partition size. 217 */ 218 retval = ext2fs_get_device_size(device_name, fs->blocksize, 219 &max_size); 220 if (retval) { 221 com_err(program_name, retval, 222 _("while trying to determine filesystem size")); 223 exit(1); 224 } 225 if (!new_size) 226 new_size = max_size; 227 /* 228 * If we are resizing a plain file, and it's not big enough, 229 * automatically extend it in a sparse fashion by writing the 230 * last requested block. 231 */ 232 if ((new_size > max_size) && 233 (stat(device_name, &st_buf) == 0) && 234 S_ISREG(st_buf.st_mode) && 235 ((tmp = malloc(fs->blocksize)) != 0)) { 236 memset(tmp, 0, fs->blocksize); 237 retval = io_channel_write_blk(fs->io, new_size-1, 1, tmp); 238 if (retval == 0) 239 max_size = new_size; 240 free(tmp); 241 } 242 if (!force && (new_size > max_size)) { 243 fprintf(stderr, _("The containing partition (or device)" 244 " is only %d blocks.\nYou requested a new size" 245 " of %d blocks.\n\n"), max_size, 246 new_size); 247 exit(1); 248 } 249 if (new_size == fs->super->s_blocks_count) { 250 fprintf(stderr, _("The filesystem is already %d blocks " 251 "long. Nothing to do!\n\n"), new_size); 252 exit(0); 253 } 254 if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) || 255 (fs->super->s_state & EXT2_ERROR_FS) || 256 ((fs->super->s_state & EXT2_VALID_FS) == 0))) { 257 fprintf(stderr, _("Please run 'e2fsck -f %s' first.\n\n"), 258 device_name); 259 exit(1); 260 } 261 retval = resize_fs(fs, &new_size, flags, 262 ((flags & RESIZE_PERCENT_COMPLETE) ? 263 resize_progress_func : 0)); 264 if (retval) { 265 com_err(program_name, retval, _("while trying to resize %s"), 266 device_name); 267 ext2fs_close (fs); 268 exit(1); 269 } 270 printf(_("The filesystem on %s is now %d blocks long.\n\n"), 271 device_name, new_size); 272 return (0); 273} 274