From 385de88a687728ae8149a332896ff78dd58d2809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 24 Nov 2017 21:34:36 +0100 Subject: [PATCH] growfs: add option parsing and --help/--version/--dry-run v2: - use arg_target --- src/partition/growfs.c | 109 ++++++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 18 deletions(-) diff --git a/src/partition/growfs.c b/src/partition/growfs.c index e5dd1d54d25..f9c604ca6f5 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -40,9 +41,15 @@ #include "path-util.h" #include "strv.h" +const char *arg_target = NULL; +bool arg_dry_run = false; + static int resize_ext4(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) { assert((uint64_t) (int) blocksize == blocksize); + if (arg_dry_run) + return 0; + if (ioctl(mountfd, EXT4_IOC_RESIZE_FS, &numblocks) != 0) return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (ext4): %m", path, numblocks); @@ -66,6 +73,9 @@ static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numbl /* The buffer is large enough for any number to fit... */ assert((size_t) r < sizeof(args.name)); + if (arg_dry_run) + return 0; + if (ioctl(mountfd, BTRFS_IOC_RESIZE, &args) != 0) return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (btrfs): %m", path, numblocks); @@ -102,6 +112,9 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_ if (r < 0) return log_debug_errno(r, "Failed to load LUKS metadata for %s: %m", devpath); + if (arg_dry_run) + return 0; + r = crypt_resize(cd, main_devpath, 0); if (r < 0) return log_error_errno(r, "crypt_resize() of %s failed: %m", devpath); @@ -148,6 +161,65 @@ static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) { return 0; } +static void help(void) { + printf("%s [OPTIONS...] /path/to/mountpoint\n\n" + "Grow filesystem or encrypted payload to device size.\n\n" + "Options:\n" + " -h --help Show this help and exit\n" + " --version Print version string and exit\n" + " -n --dry-run Just print what would be done\n" + , program_invocation_short_name); +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + }; + + int c; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "dry-run", no_argument, NULL, 'n' }, + {} + }; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hn", options, NULL)) >= 0) + switch(c) { + case 'h': + help(); + return 0; + + case ARG_VERSION: + version(); + return 0; + + case 'n': + arg_dry_run = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (optind + 1 != argc) { + log_error("%s excepts exactly one argument (the mount point).", + program_invocation_short_name); + return -EINVAL; + } + + arg_target = argv[optind]; + + return 1; +} + int main(int argc, char *argv[]) { dev_t devno; _cleanup_close_ int mountfd = -1, devfd = -1; @@ -157,38 +229,39 @@ int main(int argc, char *argv[]) { struct statfs sfs; int r; - if (argc != 2) { - log_error("This program requires one argument (the mountpoint)."); - return EXIT_FAILURE; - } - log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); - r = path_is_mount_point(argv[1], NULL, 0); + r = parse_argv(argc, argv); + if (r < 0) + return EXIT_FAILURE; + if (r == 0) + return EXIT_SUCCESS; + + r = path_is_mount_point(arg_target, NULL, 0); if (r < 0) { - log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", argv[1]); + log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", arg_target); return EXIT_FAILURE; } if (r == 0) { - log_error_errno(r, "\"%s\" is not a mount point: %m", argv[1]); + log_error_errno(r, "\"%s\" is not a mount point: %m", arg_target); return EXIT_FAILURE; } - r = get_block_device(argv[1], &devno); + r = get_block_device(arg_target, &devno); if (r < 0) { - log_error_errno(r, "Failed to determine block device of \"%s\": %m", argv[1]); + log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target); return EXIT_FAILURE; } - r = maybe_resize_slave_device(argv[1], devno); + r = maybe_resize_slave_device(arg_target, devno); if (r < 0) return EXIT_FAILURE; - mountfd = open(argv[1], O_RDONLY|O_CLOEXEC); + mountfd = open(arg_target, O_RDONLY|O_CLOEXEC); if (mountfd < 0) { - log_error_errno(errno, "Failed to open \"%s\": %m", argv[1]); + log_error_errno(errno, "Failed to open \"%s\": %m", arg_target); return EXIT_FAILURE; } @@ -216,20 +289,20 @@ int main(int argc, char *argv[]) { numblocks = size / blocksize; if (fstatfs(mountfd, &sfs) < 0) { - log_error_errno(errno, "Failed to stat file system \"%s\": %m", argv[1]); + log_error_errno(errno, "Failed to stat file system \"%s\": %m", arg_target); return EXIT_FAILURE; } switch(sfs.f_type) { case EXT4_SUPER_MAGIC: - r = resize_ext4(argv[1], mountfd, devfd, numblocks, blocksize); + r = resize_ext4(arg_target, mountfd, devfd, numblocks, blocksize); break; case BTRFS_SUPER_MAGIC: - r = resize_btrfs(argv[1], mountfd, devfd, numblocks, blocksize); + r = resize_btrfs(arg_target, mountfd, devfd, numblocks, blocksize); break; default: log_error("Don't know how to resize fs %llx on \"%s\"", - (long long unsigned) sfs.f_type, argv[1]); + (long long unsigned) sfs.f_type, arg_target); return EXIT_FAILURE; } @@ -237,6 +310,6 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" blocks of %d bytes).", - argv[1], format_bytes(fb, sizeof fb, size), numblocks, blocksize); + arg_target, format_bytes(fb, sizeof fb, size), numblocks, blocksize); return EXIT_SUCCESS; }