mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
growfs: add option parsing and --help/--version/--dry-run
v2: - use arg_target
This commit is contained in:
parent
995fa2e5e1
commit
385de88a68
@ -20,6 +20,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/magic.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user