Whamcloud - gitweb
Fix up configure so it finds mkinstalldirs
[tools/e2fsprogs.git] / resize / main.c
index 7db4ebc..e4b4435 100644 (file)
@@ -5,7 +5,7 @@
  *     PowerQuest, Inc.
  *
  * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 by Theodore Ts'o
- * 
+ *
  * %Begin-Header%
  * This file may be redistributed under the terms of the GNU Public
  * License.
@@ -15,6 +15,7 @@
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
 
+#include "config.h"
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #else
@@ -22,6 +23,9 @@ extern char *optarg;
 extern int optind;
 #endif
 #include <unistd.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -32,12 +36,13 @@ extern int optind;
 
 #include "../version.h"
 
-char *program_name, *device_name, *io_options;
+char *program_name;
+static char *device_name, *io_options;
 
 static void usage (char *prog)
 {
-       fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-p] "
-                          "device [new_size]\n\n"), prog);
+       fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] "
+                          "[-p] device [new_size]\n\n"), prog);
 
        exit (1);
 }
@@ -98,7 +103,7 @@ static void determine_fs_stride(ext2_filsys fs)
 {
        unsigned int    group;
        unsigned long long sum;
-       unsigned int    has_sb, prev_has_sb, num;
+       unsigned int    has_sb, prev_has_sb = 0, num;
        int             i_stride, b_stride;
 
        if (fs->stride)
@@ -108,11 +113,11 @@ static void determine_fs_stride(ext2_filsys fs)
                has_sb = ext2fs_bg_has_super(fs, group);
                if (group == 0 || has_sb != prev_has_sb)
                        goto next;
-               b_stride = fs->group_desc[group].bg_block_bitmap - 
-                       fs->group_desc[group-1].bg_block_bitmap - 
+               b_stride = ext2fs_block_bitmap_loc(fs, group) -
+                       ext2fs_block_bitmap_loc(fs, group - 1) -
                        fs->super->s_blocks_per_group;
-               i_stride = fs->group_desc[group].bg_inode_bitmap - 
-                       fs->group_desc[group-1].bg_inode_bitmap - 
+               i_stride = ext2fs_inode_bitmap_loc(fs, group) -
+                       ext2fs_inode_bitmap_loc(fs, group - 1) -
                        fs->super->s_blocks_per_group;
                if (b_stride != i_stride ||
                    b_stride < 0)
@@ -121,7 +126,7 @@ static void determine_fs_stride(ext2_filsys fs)
                /* printf("group %d has stride %d\n", group, b_stride); */
                sum += b_stride;
                num++;
-                       
+
        next:
                prev_has_sb = has_sb;
        }
@@ -143,6 +148,18 @@ static void determine_fs_stride(ext2_filsys fs)
 #endif
 }
 
+static void bigalloc_check(ext2_filsys fs, int force)
+{
+       if (!force && EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+               fprintf(stderr, "%s", _("\nResizing bigalloc file systems has "
+                                       "not been fully tested.  Proceed at\n"
+                                       "your own risk!  Use the force option "
+                                       "if you want to go ahead anyway.\n\n"));
+               exit(1);
+       }
+}
+
 int main (int argc, char ** argv)
 {
        errcode_t       retval;
@@ -152,17 +169,16 @@ int main (int argc, char ** argv)
        int             flush = 0;
        int             force = 0;
        int             io_flags = 0;
+       int             force_min_size = 0;
+       int             print_min_size = 0;
        int             fd, ret;
-       blk_t           new_size = 0;
-       blk_t           max_size = 0;
+       blk64_t         new_size = 0;
+       blk64_t         max_size = 0;
+       blk64_t         min_size = 0;
        io_manager      io_ptr;
        char            *new_size_str = 0;
        int             use_stride = -1;
-#ifdef HAVE_FSTAT64
-       struct stat64   st_buf;
-#else
-       struct stat     st_buf;
-#endif
+       ext2fs_struct_stat st_buf;
        __s64           new_file_size;
        unsigned int    sys_page_size = 4096;
        long            sysval;
@@ -174,6 +190,7 @@ int main (int argc, char ** argv)
        setlocale(LC_CTYPE, "");
        bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
        textdomain(NLS_CAT_NAME);
+       set_com_err_gettext(gettext);
 #endif
 
        add_error_table(&et_ext2_error_table);
@@ -183,7 +200,7 @@ int main (int argc, char ** argv)
        if (argc && *argv)
                program_name = *argv;
 
-       while ((c = getopt (argc, argv, "d:fFhpS:")) != EOF) {
+       while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) {
                switch (c) {
                case 'h':
                        usage(program_name);
@@ -194,6 +211,12 @@ int main (int argc, char ** argv)
                case 'F':
                        flush = 1;
                        break;
+               case 'M':
+                       force_min_size = 1;
+                       break;
+               case 'P':
+                       print_min_size = 1;
+                       break;
                case 'd':
                        flags |= atoi(optarg);
                        break;
@@ -215,7 +238,7 @@ int main (int argc, char ** argv)
                new_size_str = argv[optind++];
        if (optind < argc)
                usage(program_name);
-       
+
        io_options = strchr(device_name, '?');
        if (io_options)
                *io_options++ = 0;
@@ -230,7 +253,7 @@ int main (int argc, char ** argv)
                if (!mtpt)
                        return ENOMEM;
                mtpt[len-1] = 0;
-               retval = ext2fs_check_mount_point(device_name, &mount_flags, 
+               retval = ext2fs_check_mount_point(device_name, &mount_flags,
                                                  mtpt, len);
                if (retval) {
                        com_err("ext2fs_check_mount_point", retval,
@@ -244,33 +267,25 @@ int main (int argc, char ** argv)
                len = 2 * len;
        }
 
-#ifdef HAVE_OPEN64
-       fd = open64(device_name, O_RDWR);
-#else
-       fd = open(device_name, O_RDWR);
-#endif
+       fd = ext2fs_open_file(device_name, O_RDWR, 0);
        if (fd < 0) {
                com_err("open", errno, _("while opening %s"),
                        device_name);
                exit(1);
        }
 
-#ifdef HAVE_FSTAT64
-       ret = fstat64(fd, &st_buf);
-#else
-       ret = fstat(fd, &st_buf);
-#endif
+       ret = ext2fs_fstat(fd, &st_buf);
        if (ret < 0) {
-               com_err("open", errno, 
+               com_err("open", errno,
                        _("while getting stat information for %s"),
                        device_name);
                exit(1);
        }
-       
+
        if (flush) {
                retval = ext2fs_sync_device(fd, 1);
                if (retval) {
-                       com_err(argv[0], retval, 
+                       com_err(argv[0], retval,
                                _("while trying to flush %s"),
                                device_name);
                        exit(1);
@@ -282,22 +297,39 @@ int main (int argc, char ** argv)
                fd = -1;
        }
 
-       if (flags & RESIZE_DEBUG_IO) {
+#ifdef CONFIG_TESTIO_DEBUG
+       if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
                io_ptr = test_io_manager;
                test_io_backing_manager = unix_io_manager;
-       } else 
+       } else
+#endif
                io_ptr = unix_io_manager;
 
        if (!(mount_flags & EXT2_MF_MOUNTED))
                io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
-       retval = ext2fs_open2(device_name, io_options, io_flags, 
+
+       io_flags |= EXT2_FLAG_64BITS;
+
+       retval = ext2fs_open2(device_name, io_options, io_flags,
                              0, 0, io_ptr, &fs);
        if (retval) {
-               com_err (program_name, retval, _("while trying to open %s"),
-                        device_name);
-               printf (_("Couldn't find valid filesystem superblock.\n"));
+               com_err(program_name, retval, _("while trying to open %s"),
+                       device_name);
+               printf("%s", _("Couldn't find valid filesystem superblock.\n"));
                exit (1);
        }
+
+       if (!(mount_flags & EXT2_MF_MOUNTED)) {
+               if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) ||
+                              (fs->super->s_state & EXT2_ERROR_FS) ||
+                              ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
+                       fprintf(stderr,
+                               _("Please run 'e2fsck -f %s' first.\n\n"),
+                               device_name);
+                       exit(1);
+               }
+       }
+
        /*
         * Check for compatibility with the feature sets.  We need to
         * be more stringent than ext2fs_open().
@@ -307,7 +339,15 @@ int main (int argc, char ** argv)
                        "(%s)", device_name);
                exit(1);
        }
-       
+
+       min_size = calculate_minimum_resize_size(fs, flags);
+
+       if (print_min_size) {
+               printf(_("Estimated minimum size of the filesystem: %llu\n"),
+                      min_size);
+               exit(0);
+       }
+
        /* Determine the system page size if possible */
 #ifdef HAVE_SYSCONF
 #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
@@ -325,19 +365,21 @@ int main (int argc, char ** argv)
         * defaults and for making sure the new filesystem doesn't
         * exceed the partition size.
         */
-       retval = ext2fs_get_device_size(device_name, fs->blocksize,
-                                       &max_size);
+       retval = ext2fs_get_device_size2(device_name, fs->blocksize,
+                                        &max_size);
        if (retval) {
-               com_err(program_name, retval,
+               com_err(program_name, retval, "%s",
                        _("while trying to determine filesystem size"));
                exit(1);
        }
-       if (new_size_str) {
-               new_size = parse_num_blocks(new_size_str, 
-                                           fs->super->s_log_block_size);
-               if (!new_size) {
-                       com_err(program_name, 0, _("bad filesystem size - %s"),
-                               new_size_str);
+       if (force_min_size)
+               new_size = min_size;
+       else if (new_size_str) {
+               new_size = parse_num_blocks2(new_size_str,
+                                            fs->super->s_log_block_size);
+               if (new_size == 0) {
+                       com_err(program_name, 0,
+                               _("Invalid new size: %s\n"), new_size_str);
                        exit(1);
                }
        } else {
@@ -346,10 +388,27 @@ int main (int argc, char ** argv)
                if (sys_page_size > fs->blocksize)
                        new_size &= ~((sys_page_size / fs->blocksize)-1);
        }
+       if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_INCOMPAT_64BIT)) {
+               /* Take 16T down to 2^32-1 blocks */
+               if (new_size == (1ULL << 32))
+                       new_size--;
+               else if (new_size > (1ULL << 32)) {
+                       com_err(program_name, 0, "%s",
+                               _("New size too large to be "
+                                 "expressed in 32 bits\n"));
+                       exit(1);
+               }
+       }
 
+       if (!force && new_size < min_size) {
+               com_err(program_name, 0,
+                       _("New size smaller than minimum (%llu)\n"), min_size);
+               exit(1);
+       }
        if (use_stride >= 0) {
                if (use_stride >= (int) fs->super->s_blocks_per_group) {
-                       com_err(program_name, 0, 
+                       com_err(program_name, 0, "%s",
                                _("Invalid stride length"));
                        exit(1);
                }
@@ -357,14 +416,14 @@ int main (int argc, char ** argv)
                ext2fs_mark_super_dirty(fs);
        } else
                  determine_fs_stride(fs);
-       
+
        /*
         * If we are resizing a plain file, and it's not big enough,
         * automatically extend it in a sparse fashion by writing the
         * last requested block.
         */
        new_file_size = ((__u64) new_size) * fs->blocksize;
-       if ((__u64) new_file_size > 
+       if ((__u64) new_file_size >
            (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1)
                fd = -1;
        if ((new_file_size > st_buf.st_size) &&
@@ -375,49 +434,56 @@ int main (int argc, char ** argv)
        }
        if (!force && (new_size > max_size)) {
                fprintf(stderr, _("The containing partition (or device)"
-                       " is only %u (%dk) blocks.\nYou requested a new size"
-                       " of %u blocks.\n\n"), max_size,
+                       " is only %llu (%dk) blocks.\nYou requested a new size"
+                       " of %llu blocks.\n\n"), max_size,
                        fs->blocksize / 1024, new_size);
                exit(1);
        }
-       if (new_size == fs->super->s_blocks_count) {
-               fprintf(stderr, _("The filesystem is already %u blocks "
+       if (new_size == ext2fs_blocks_count(fs->super)) {
+               fprintf(stderr, _("The filesystem is already %llu blocks "
                        "long.  Nothing to do!\n\n"), new_size);
                exit(0);
        }
        if (mount_flags & EXT2_MF_MOUNTED) {
+               bigalloc_check(fs, force);
                retval = online_resize_fs(fs, mtpt, &new_size, flags);
        } else {
-               if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) ||
-                              (fs->super->s_state & EXT2_ERROR_FS) ||
-                              ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
-                       fprintf(stderr, 
-                               _("Please run 'e2fsck -f %s' first.\n\n"),
-                               device_name);
-                       exit(1);
-               }
-       printf("Resizing the filesystem on %s to %u (%dk) blocks.\n",
+               bigalloc_check(fs, force);
+               printf(_("Resizing the filesystem on "
+                        "%s to %llu (%dk) blocks.\n"),
                       device_name, new_size, fs->blocksize / 1024);
                retval = resize_fs(fs, &new_size, flags,
                                   ((flags & RESIZE_PERCENT_COMPLETE) ?
                                    resize_progress_func : 0));
        }
+       free(mtpt);
        if (retval) {
                com_err(program_name, retval, _("while trying to resize %s"),
                        device_name);
-               ext2fs_close (fs);
+               fprintf(stderr,
+                       _("Please run 'e2fsck -fy %s' to fix the filesystem\n"
+                         "after the aborted resize operation.\n"),
+                       device_name);
+               ext2fs_close_free(&fs);
                exit(1);
        }
-       printf(_("The filesystem on %s is now %u blocks long.\n\n"),
+       printf(_("The filesystem on %s is now %llu blocks long.\n\n"),
               device_name, new_size);
 
        if ((st_buf.st_size > new_file_size) &&
            (fd > 0)) {
-#ifdef HAVE_FSTAT64
-               ftruncate64(fd, new_file_size);
+#ifdef HAVE_FTRUNCATE64
+               retval = ftruncate64(fd, new_file_size);
 #else
-               ftruncate(fd, (off_t) new_file_size);
+               retval = 0;
+               /* Only truncate if new_file_size doesn't overflow off_t */
+               if (((off_t) new_file_size) == new_file_size)
+                       retval = ftruncate(fd, (off_t) new_file_size);
 #endif
+               if (retval)
+                       com_err(program_name, retval,
+                               _("while trying to truncate %s"),
+                               device_name);
        }
        if (fd > 0)
                close(fd);