diff --git a/meson.build b/meson.build index 94917ca667..031776c41f 100644 --- a/meson.build +++ b/meson.build @@ -1940,6 +1940,7 @@ executable('systemd-growfs', 'src/partition/growfs.c', include_directories : includes, link_with : [libshared], + dependencies : [libcryptsetup], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) diff --git a/src/partition/growfs.c b/src/partition/growfs.c index bebbda1bf3..e5dd1d54d2 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -27,7 +27,9 @@ #include #include +#include "crypt-util.h" #include "device-nodes.h" +#include "dissect-image.h" #include "escape.h" #include "fd-util.h" #include "format-util.h" @@ -71,6 +73,81 @@ static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numbl return 0; } +static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) { + char devpath[DEV_NUM_PATH_MAX], main_devpath[DEV_NUM_PATH_MAX]; + _cleanup_close_ int main_devfd = -1; + _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + uint64_t size; + int r; + + xsprintf_dev_num_path(main_devpath, "block", main_devno); + main_devfd = open(main_devpath, O_RDONLY|O_CLOEXEC); + if (main_devfd < 0) + return log_error_errno(errno, "Failed to open \"%s\": %m", main_devpath); + + if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0) + return log_error_errno(errno, "Failed to query size of \"%s\" (before resize): %m", + main_devpath); + + log_debug("%s is %"PRIu64" bytes", main_devpath, size); + + xsprintf_dev_num_path(devpath, "block", devno); + r = crypt_init(&cd, devpath); + if (r < 0) + return log_error_errno(r, "crypt_init(\"%s\") failed: %m", devpath); + + crypt_set_log_callback(cd, cryptsetup_log_glue, NULL); + + r = crypt_load(cd, CRYPT_LUKS, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to load LUKS metadata for %s: %m", devpath); + + r = crypt_resize(cd, main_devpath, 0); + if (r < 0) + return log_error_errno(r, "crypt_resize() of %s failed: %m", devpath); + + if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0) + log_warning_errno(errno, "Failed to query size of \"%s\" (after resize): %m", + devpath); + else + log_debug("%s is now %"PRIu64" bytes", main_devpath, size); + + return 1; +} + +static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) { + dev_t devno; + char devpath[DEV_NUM_PATH_MAX]; + _cleanup_free_ char *fstype = NULL; + int r; + + crypt_set_log_callback(NULL, cryptsetup_log_glue, NULL); + crypt_set_debug_level(1); + + r = get_block_device_harder(mountpath, &devno); + if (r < 0) + return log_error_errno(r, "Failed to determine underlying block device of \"%s\": %m", + mountpath); + + log_debug("Underlying device %d:%d, main dev %d:%d, %s", + major(devno), minor(devno), + major(main_devno), minor(main_devno), + devno == main_devno ? "same" : "different"); + if (devno == main_devno) + return 0; + + xsprintf_dev_num_path(devpath, "block", devno); + r = probe_filesystem(devpath, &fstype); + if (r < 0) + return log_warning_errno(r, "Failed to probe \"%s\": %m", devpath); + + if (streq_ptr(fstype, "crypto_LUKS")) + return resize_crypt_luks_device(devno, fstype, main_devno); + + log_debug("Don't know how to resize %s of type %s, ignoring", devpath, strnull(fstype)); + return 0; +} + int main(int argc, char *argv[]) { dev_t devno; _cleanup_close_ int mountfd = -1, devfd = -1; @@ -105,6 +182,10 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + r = maybe_resize_slave_device(argv[1], devno); + if (r < 0) + return EXIT_FAILURE; + mountfd = open(argv[1], O_RDONLY|O_CLOEXEC); if (mountfd < 0) { log_error_errno(errno, "Failed to open \"%s\": %m", argv[1]); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 6f294ed0bf..a7679a1423 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -51,7 +51,7 @@ #include "udev-util.h" #include "xattr-util.h" -_unused_ static int probe_filesystem(const char *node, char **ret_fstype) { +int probe_filesystem(const char *node, char **ret_fstype) { #if HAVE_BLKID _cleanup_blkid_free_probe_ blkid_probe b = NULL; const char *fstype; diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 30a12cb540..7c7ce46015 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -86,6 +86,7 @@ struct DissectedImage { char **os_release; }; +int probe_filesystem(const char *node, char **ret_fstype); int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m);