From: Lennart Poettering Date: Thu, 22 Feb 2024 08:43:01 +0000 (+0100) Subject: importd: add support for downloading sysext/confext/portable images too X-Git-Tag: v256-rc1~671^2~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7af5785d77ced29a01fdf636274ac883aa9ff2d0;p=thirdparty%2Fsystemd.git importd: add support for downloading sysext/confext/portable images too This adds "Ex" versions of all bus calls import implements, that make two changes: 1. A "class" parameter is added that allows choosing between machine/sysext/confext/portable images to download. Depending on the chose class the target directory is selected differently (i.e. not just /var/lib/machines/, but alternatively /var/lib/portables/, /var/lib/extensions/, /var/lib/confexts/. 2. The boolean flags are replaced by a 64bit flags parameter. --- diff --git a/src/import/export.c b/src/import/export.c index ee65cc8d362..ac81b2fbabc 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -23,6 +23,7 @@ #include "verbs.h" static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN; +static ImageClass arg_class = IMAGE_MACHINE; static void determine_compression_from_filename(const char *p) { @@ -63,7 +64,7 @@ static int export_tar(int argc, char *argv[], void *userdata) { int r, fd; if (hostname_is_valid(argv[1], 0)) { - r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); + r = image_find(arg_class, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) @@ -135,7 +136,7 @@ static int export_raw(int argc, char *argv[], void *userdata) { int r, fd; if (hostname_is_valid(argv[1], 0)) { - r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); + r = image_find(arg_class, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) @@ -190,14 +191,16 @@ static int export_raw(int argc, char *argv[], void *userdata) { static int help(int argc, char *argv[], void *userdata) { printf("%1$s [OPTIONS...] {COMMAND} ...\n" - "\n%4$sExport container or virtual machine images.%5$s\n" + "\n%4$sExport disk images.%5$s\n" "\n%2$sCommands:%3$s\n" " tar NAME [FILE] Export a TAR image\n" " raw NAME [FILE] Export a RAW image\n" "\n%2$sOptions:%3$s\n" " -h --help Show this help\n" " --version Show package version\n" - " --format=FORMAT Select format\n", + " --format=FORMAT Select format\n" + " --class=CLASS Select image class (machine, sysext, confext,\n" + " portable)\n", program_invocation_short_name, ansi_underline(), ansi_normal(), @@ -212,12 +215,14 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_FORMAT, + ARG_CLASS, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "format", required_argument, NULL, ARG_FORMAT }, + { "class", required_argument, NULL, ARG_CLASS }, {} }; @@ -250,6 +255,13 @@ static int parse_argv(int argc, char *argv[]) { "Unknown format: %s", optarg); break; + case ARG_CLASS: + arg_class = image_class_from_string(optarg); + if (arg_class < 0) + return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg); + + break; + case '?': return -EINVAL; diff --git a/src/import/import-common.h b/src/import/import-common.h index edde7fd8bd2..2bb20754624 100644 --- a/src/import/import-common.h +++ b/src/import/import-common.h @@ -27,6 +27,8 @@ typedef enum ImportFlags { /* The supported flags for the tar and the raw pulling */ IMPORT_PULL_FLAGS_MASK_TAR = IMPORT_FLAGS_MASK_TAR|IMPORT_PULL_SETTINGS, IMPORT_PULL_FLAGS_MASK_RAW = IMPORT_FLAGS_MASK_RAW|IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY, + + _IMPORT_FLAGS_INVALID = -EINVAL, } ImportFlags; int import_fork_tar_c(const char *path, pid_t *ret); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index a89c835f573..e37fd7b41d2 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -31,7 +31,8 @@ static bool arg_btrfs_subvol = true; static bool arg_btrfs_quota = true; static bool arg_sync = true; static bool arg_direct = false; -static const char *arg_image_root = "/var/lib/machines"; +static const char *arg_image_root = NULL; +static ImageClass arg_class = IMAGE_MACHINE; typedef struct ProgressInfo { RateLimit limit; @@ -143,7 +144,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { return log_oom(); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL, NULL); + r = image_find(arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -266,7 +267,9 @@ static int help(int argc, char *argv[], void *userdata) { " instead of a directory\n" " --btrfs-quota=BOOL Controls whether to set up quota for btrfs\n" " subvolume\n" - " --sync=BOOL Controls whether to sync() before completing\n", + " --sync=BOOL Controls whether to sync() before completing\n" + " --class=CLASS Select image class (machine, sysext, confext,\n" + " portable)\n", program_invocation_short_name, ansi_underline(), ansi_normal(), @@ -287,6 +290,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_BTRFS_SUBVOL, ARG_BTRFS_QUOTA, ARG_SYNC, + ARG_CLASS, }; static const struct option options[] = { @@ -299,6 +303,7 @@ static int parse_argv(int argc, char *argv[]) { { "btrfs-subvol", required_argument, NULL, ARG_BTRFS_SUBVOL }, { "btrfs-quota", required_argument, NULL, ARG_BTRFS_QUOTA }, { "sync", required_argument, NULL, ARG_SYNC }, + { "class", required_argument, NULL, ARG_CLASS }, {} }; @@ -354,6 +359,13 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_CLASS: + arg_class = image_class_from_string(optarg); + if (arg_class < 0) + return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg); + + break; + case '?': return -EINVAL; @@ -361,6 +373,9 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } + if (!arg_image_root) + arg_image_root = image_root_to_string(arg_class); + return 1; } diff --git a/src/import/import-raw.c b/src/import/import-raw.c index f7ed163d864..ee9b297bfeb 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -95,8 +95,9 @@ int raw_import_new( int r; assert(ret); + assert(image_root); - root = strdup(image_root ?: "/var/lib/machines"); + root = strdup(image_root); if (!root) return -ENOMEM; diff --git a/src/import/import-tar.c b/src/import/import-tar.c index 90202709ecc..39df11b5ff6 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -97,8 +97,9 @@ int tar_import_new( int r; assert(ret); + assert(image_root); - root = strdup(image_root ?: "/var/lib/machines"); + root = strdup(image_root); if (!root) return -ENOMEM; diff --git a/src/import/import.c b/src/import/import.c index 50059870a07..22ce6f5aaa7 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -25,9 +25,10 @@ #include "terminal-util.h" #include "verbs.h" -static const char *arg_image_root = "/var/lib/machines"; +static const char *arg_image_root = NULL; static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC; static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX; +static ImageClass arg_class = IMAGE_MACHINE; static int normalize_local(const char *local, char **ret) { _cleanup_free_ char *ll = NULL; @@ -61,7 +62,7 @@ static int normalize_local(const char *local, char **ret) { local = "imported"; if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { - r = image_find(IMAGE_MACHINE, local, NULL, NULL); + r = image_find(arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -266,7 +267,7 @@ static int import_raw(int argc, char *argv[], void *userdata) { static int help(int argc, char *argv[], void *userdata) { printf("%1$s [OPTIONS...] {COMMAND} ...\n" - "\n%4$sImport container or virtual machine images.%5$s\n" + "\n%4$sImport disk images.%5$s\n" "\n%2$sCommands:%3$s\n" " tar FILE [NAME] Import a TAR image\n" " raw FILE [NAME] Import a RAW image\n" @@ -285,7 +286,9 @@ static int help(int argc, char *argv[], void *userdata) { " regular disk images\n" " --sync=BOOL Controls whether to sync() before completing\n" " --offset=BYTES Offset to seek to in destination\n" - " --size-max=BYTES Maximum number of bytes to write to destination\n", + " --size-max=BYTES Maximum number of bytes to write to destination\n" + " --class=CLASS Select image class (machine, sysext, confext,\n" + " portable)\n", program_invocation_short_name, ansi_underline(), ansi_normal(), @@ -309,6 +312,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SYNC, ARG_OFFSET, ARG_SIZE_MAX, + ARG_CLASS, }; static const struct option options[] = { @@ -324,6 +328,7 @@ static int parse_argv(int argc, char *argv[]) { { "sync", required_argument, NULL, ARG_SYNC }, { "offset", required_argument, NULL, ARG_OFFSET }, { "size-max", required_argument, NULL, ARG_SIZE_MAX }, + { "class", required_argument, NULL, ARG_CLASS }, {} }; @@ -416,6 +421,13 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_CLASS: + arg_class = image_class_from_string(optarg); + if (arg_class < 0) + return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg); + + break; + case '?': return -EINVAL; @@ -432,6 +444,9 @@ static int parse_argv(int argc, char *argv[]) { if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_import_flags, IMPORT_DIRECT)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset only supported in --direct mode."); + if (!arg_image_root) + arg_image_root = image_root_to_string(arg_class); + return 1; } diff --git a/src/import/importd.c b/src/import/importd.c index dbf2fba4ab6..47dfb2dfafc 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -14,16 +14,19 @@ #include "common-signal.h" #include "constants.h" #include "daemon-util.h" +#include "discover-image.h" #include "env-util.h" #include "event-util.h" #include "fd-util.h" #include "float.h" #include "hostname-util.h" +#include "import-common.h" #include "import-util.h" #include "machine-pool.h" #include "main-func.h" #include "missing_capability.h" #include "mkdir-label.h" +#include "os-util.h" #include "parse-util.h" #include "path-util.h" #include "percent-util.h" @@ -64,9 +67,8 @@ struct Transfer { char *remote; char *local; - bool force_local; - bool read_only; - + ImageClass class; + ImportFlags flags; char *format; PidRef pidref; @@ -382,6 +384,8 @@ static int transfer_start(Transfer *t) { NULL, /* tar, raw */ NULL, /* --verify= */ NULL, /* verify argument */ + NULL, /* --class= */ + NULL, /* class argument */ NULL, /* maybe --force */ NULL, /* maybe --read-only */ NULL, /* if so: the actual URL */ @@ -457,9 +461,14 @@ static int transfer_start(Transfer *t) { cmd[k++] = import_verify_to_string(t->verify); } - if (t->force_local) + if (t->class != IMAGE_MACHINE) { + cmd[k++] = "--class"; + cmd[k++] = image_class_to_string(t->class); + } + + if (FLAGS_SET(t->flags, IMPORT_FORCE)) cmd[k++] = "--force"; - if (t->read_only) + if (FLAGS_SET(t->flags, IMPORT_READ_ONLY)) cmd[k++] = "--read-only"; if (t->format) { @@ -702,12 +711,13 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *remote) static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(transfer_unrefp) Transfer *t = NULL; - int fd, force, read_only, r; - const char *local, *object; + ImageClass class = _IMAGE_CLASS_INVALID; Manager *m = ASSERT_PTR(userdata); + const char *local; TransferType type; struct stat st; - uint32_t id; + uint64_t flags; + int fd, r; assert(msg); @@ -722,9 +732,34 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r == 0) return 1; /* Will call us back */ - r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); - if (r < 0) - return r; + if (endswith(sd_bus_message_get_member(msg), "Ex")) { + const char *sclass; + + r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags); + if (r < 0) + return r; + + class = image_class_from_string(sclass); + if (class < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Image class '%s' not known", sclass); + + if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Flags 0x%" PRIx64 " invalid", flags); + } else { + int force, read_only; + + r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); + if (r < 0) + return r; + + class = IMAGE_MACHINE; + + flags = 0; + SET_FLAG(flags, IMPORT_FORCE, force); + SET_FLAG(flags, IMPORT_READ_ONLY, read_only); + } if (fstat(fd, &st) < 0) return -errno; @@ -736,11 +771,13 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); - if (r < 0) - return r; + if (class == IMAGE_MACHINE) { + r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); + if (r < 0) + return r; + } - type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? + type = startswith(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW; r = transfer_new(m, &t); @@ -748,8 +785,8 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ return r; t->type = type; - t->force_local = force; - t->read_only = read_only; + t->class = class; + t->flags = flags; t->local = strdup(local); if (!t->local) @@ -763,19 +800,21 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r < 0) return r; - object = t->object_path; - id = t->id; - t = NULL; + r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); + if (r < 0) + return r; - return sd_bus_reply_method_return(msg, "uo", id, object); + TAKE_PTR(t); + return 1; } static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(transfer_unrefp) Transfer *t = NULL; - int fd, force, read_only, r; - const char *local, *object; + ImageClass class = _IMAGE_CLASS_INVALID; Manager *m = ASSERT_PTR(userdata); - uint32_t id; + const char *local; + uint64_t flags; + int fd, r; assert(msg); @@ -790,9 +829,34 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e if (r == 0) return 1; /* Will call us back */ - r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); - if (r < 0) - return r; + if (endswith(sd_bus_message_get_member(msg), "Ex")) { + const char *sclass; + + r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags); + if (r < 0) + return r; + + class = image_class_from_string(sclass); + if (class < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Image class '%s' not known", sclass); + + if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Flags 0x%" PRIx64 " invalid", flags); + } else { + int force, read_only; + + r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); + if (r < 0) + return r; + + class = IMAGE_MACHINE; + + flags = 0; + SET_FLAG(flags, IMPORT_FORCE, force); + SET_FLAG(flags, IMPORT_READ_ONLY, read_only); + } r = fd_verify_directory(fd); if (r < 0) @@ -802,17 +866,19 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); - if (r < 0) - return r; + if (class == IMAGE_MACHINE) { + r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); + if (r < 0) + return r; + } r = transfer_new(m, &t); if (r < 0) return r; t->type = TRANSFER_IMPORT_FS; - t->force_local = force; - t->read_only = read_only; + t->class = class; + t->flags = flags; t->local = strdup(local); if (!t->local) @@ -826,21 +892,23 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e if (r < 0) return r; - object = t->object_path; - id = t->id; - t = NULL; + r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); + if (r < 0) + return r; - return sd_bus_reply_method_return(msg, "uo", id, object); + TAKE_PTR(t); + return 1; } static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(transfer_unrefp) Transfer *t = NULL; - int fd, r; - const char *local, *object, *format; + ImageClass class = _IMAGE_CLASS_INVALID; Manager *m = ASSERT_PTR(userdata); + const char *local, *format; TransferType type; + uint64_t flags; struct stat st; - uint32_t id; + int fd, r; assert(msg); @@ -855,9 +923,29 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r == 0) return 1; /* Will call us back */ - r = sd_bus_message_read(msg, "shs", &local, &fd, &format); - if (r < 0) - return r; + if (endswith(sd_bus_message_get_member(msg), "Ex")) { + const char *sclass; + + r = sd_bus_message_read(msg, "sshst", &local, &sclass, &fd, &format, &flags); + if (r < 0) + return r; + + class = image_class_from_string(sclass); + if (class < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Image class '%s' not known", sclass); + + if (flags != 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Flags 0x%" PRIx64 " invalid", flags); + } else { + r = sd_bus_message_read(msg, "shs", &local, &fd, &format); + if (r < 0) + return r; + + class = IMAGE_MACHINE; + flags = 0; + } if (!hostname_is_valid(local, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, @@ -869,7 +957,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) return -EINVAL; - type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? + type = startswith(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW; r = transfer_new(m, &t); @@ -877,6 +965,8 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ return r; t->type = type; + t->class = class; + t->flags = flags; if (!isempty(format)) { t->format = strdup(format); @@ -896,21 +986,23 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r < 0) return r; - object = t->object_path; - id = t->id; - t = NULL; + r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); + if (r < 0) + return r; - return sd_bus_reply_method_return(msg, "uo", id, object); + TAKE_PTR(t); + return 1; } static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(transfer_unrefp) Transfer *t = NULL; - const char *remote, *local, *verify, *object; + ImageClass class = _IMAGE_CLASS_INVALID; + const char *remote, *local, *verify; Manager *m = ASSERT_PTR(userdata); - ImportVerify v; TransferType type; - int force, r; - uint32_t id; + uint64_t flags; + ImportVerify v; + int r; assert(msg); @@ -925,9 +1017,33 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (r == 0) return 1; /* Will call us back */ - r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force); - if (r < 0) - return r; + if (endswith(sd_bus_message_get_member(msg), "Ex")) { + const char *sclass; + + r = sd_bus_message_read(msg, "sssst", &remote, &local, &sclass, &verify, &flags); + if (r < 0) + return r; + + class = image_class_from_string(sclass); + if (class < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Image class '%s' not known", sclass); + + if (flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Flags 0x%" PRIx64 " invalid", flags); + } else { + int force; + + r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force); + if (r < 0) + return r; + + class = IMAGE_MACHINE; + + flags = 0; + SET_FLAG(flags, IMPORT_FORCE, force); + } if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, @@ -947,11 +1063,13 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); - r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); - if (r < 0) - return r; + if (class == IMAGE_MACHINE) { + r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); + if (r < 0) + return r; + } - type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? + type = startswith(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW; if (manager_find(m, type, remote)) @@ -964,7 +1082,8 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er t->type = type; t->verify = v; - t->force_local = force; + t->flags = flags; + t->class = class; t->remote = strdup(remote); if (!t->remote) @@ -980,40 +1099,81 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (r < 0) return r; - object = t->object_path; - id = t->id; - t = NULL; + r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); + if (r < 0) + return r; - return sd_bus_reply_method_return(msg, "uo", id, object); + TAKE_PTR(t); + return 1; } static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = ASSERT_PTR(userdata); + ImageClass class = _IMAGE_CLASS_INVALID; Transfer *t; int r; assert(msg); + bool ex = endswith(sd_bus_message_get_member(msg), "Ex"); + if (ex) { + const char *sclass; + uint64_t flags; + + r = sd_bus_message_read(msg, "st", &sclass, &flags); + if (r < 0) + return bus_log_parse_error(r); + + if (!isempty(sclass)) { + class = image_class_from_string(sclass); + if (class < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Image class '%s' not known", sclass); + } + + if (flags != 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Flags 0x%" PRIx64 " invalid", flags); + } + r = sd_bus_message_new_method_return(msg, &reply); if (r < 0) return r; - r = sd_bus_message_open_container(reply, 'a', "(usssdo)"); + if (ex) + r = sd_bus_message_open_container(reply, 'a', "(ussssdo)"); + else + r = sd_bus_message_open_container(reply, 'a', "(usssdo)"); if (r < 0) return r; HASHMAP_FOREACH(t, m->transfers) { - r = sd_bus_message_append( - reply, - "(usssdo)", - t->id, - transfer_type_to_string(t->type), - t->remote, - t->local, - transfer_percent_as_double(t), - t->object_path); + if (class >= 0 && class != t->class) + continue; + + if (ex) + r = sd_bus_message_append( + reply, + "(ussssdo)", + t->id, + transfer_type_to_string(t->type), + t->remote, + t->local, + image_class_to_string(t->class), + transfer_percent_as_double(t), + t->object_path); + else + r = sd_bus_message_append( + reply, + "(usssdo)", + t->id, + transfer_type_to_string(t->type), + t->remote, + t->local, + transfer_percent_as_double(t), + t->object_path); if (r < 0) return r; } @@ -1059,7 +1219,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er r = bus_verify_polkit_async( msg, - "org.freedesktop.import1.pull", + "org.freedesktop.import1.cancel", /* details= */ NULL, &m->polkit_registry, error); @@ -1212,6 +1372,17 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ImportTarEx", + "hsst", + SD_BUS_PARAM(fd) + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_import_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ImportRaw", "hsbb", SD_BUS_PARAM(fd) @@ -1223,6 +1394,17 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ImportRawEx", + "hsst", + SD_BUS_PARAM(fd) + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_import_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ImportFileSystem", "hsbb", SD_BUS_PARAM(fd) @@ -1234,6 +1416,17 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_import_fs, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ImportFileSystemEx", + "hsst", + SD_BUS_PARAM(fd) + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_import_fs, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ExportTar", "shs", SD_BUS_PARAM(local_name) @@ -1244,6 +1437,18 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ExportTarEx", + "sshst", + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(fd) + SD_BUS_PARAM(format) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_export_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ExportRaw", "shs", SD_BUS_PARAM(local_name) @@ -1254,6 +1459,18 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ExportRawEx", + "sshst", + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(fd) + SD_BUS_PARAM(format) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_export_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("PullTar", "sssb", SD_BUS_PARAM(url) @@ -1265,6 +1482,18 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("PullTarEx", + "sssst", + SD_BUS_PARAM(url) + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(verify_mode) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_pull_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("PullRaw", "sssb", SD_BUS_PARAM(url) @@ -1276,12 +1505,32 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PARAM(transfer_path), method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("PullRawEx", + "sssst", + SD_BUS_PARAM(url) + SD_BUS_PARAM(local_name) + SD_BUS_PARAM(class) + SD_BUS_PARAM(verify_mode) + SD_BUS_PARAM(flags), + "uo", + SD_BUS_PARAM(transfer_id) + SD_BUS_PARAM(transfer_path), + method_pull_tar_or_raw, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ListTransfers", NULL,, "a(usssdo)", SD_BUS_PARAM(transfers), method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("ListTransfersEx", + "st", + SD_BUS_PARAM(class) + SD_BUS_PARAM(flags), + "a(ussssdo)", + SD_BUS_PARAM(transfers), + method_list_transfers, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("CancelTransfer", "u", SD_BUS_PARAM(transfer_id), diff --git a/src/import/org.freedesktop.import1.conf b/src/import/org.freedesktop.import1.conf index d252ff64606..f775aa061c1 100644 --- a/src/import/org.freedesktop.import1.conf +++ b/src/import/org.freedesktop.import1.conf @@ -42,6 +42,10 @@ send_interface="org.freedesktop.import1.Manager" send_member="ListTransfers"/> + + @@ -50,30 +54,58 @@ send_interface="org.freedesktop.import1.Manager" send_member="ImportTar"/> + + + + + + + + + + + + + + diff --git a/src/import/org.freedesktop.import1.policy b/src/import/org.freedesktop.import1.policy index 88e436dc3af..45c11def674 100644 --- a/src/import/org.freedesktop.import1.policy +++ b/src/import/org.freedesktop.import1.policy @@ -19,8 +19,8 @@ https://systemd.io - Import a VM or container image - Authentication is required to import a VM or container image + Import a disk image + Authentication is required to import an image auth_admin auth_admin @@ -29,8 +29,8 @@ - Export a VM or container image - Authentication is required to export a VM or container image + Export a disk image + Authentication is required to export disk image auth_admin auth_admin @@ -39,8 +39,18 @@ - Download a VM or container image - Authentication is required to download a VM or container image + Download a disk image + Authentication is required to download a disk image + + auth_admin + auth_admin + auth_admin_keep + + + + + Cancel transfer of a disk image + Authentication is required to cancel the ongoing transfer of a disk image auth_admin auth_admin diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 78390577695..4fca08437c2 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -37,11 +37,9 @@ int pull_find_old_etags( int r; assert(url); + assert(image_root); assert(etags); - if (!image_root) - image_root = "/var/lib/machines"; - _cleanup_free_ char *escaped_url = xescape(url, FILENAME_ESCAPE); if (!escaped_url) return -ENOMEM; @@ -128,11 +126,9 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co char *path; assert(url); + assert(image_root); assert(ret); - if (!image_root) - image_root = "/var/lib/machines"; - escaped_url = xescape(url, FILENAME_ESCAPE); if (!escaped_url) return -ENOMEM; diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index ebe479fb802..50785fe431c 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -60,7 +60,7 @@ struct RawPull { void *userdata; char *local; /* In PULL_DIRECT mode the path we are supposed to place things in, otherwise the - * machine name of the final copy we make */ + * image name of the final copy we make */ char *final_path; char *temp_path; @@ -127,8 +127,9 @@ int raw_pull_new( int r; assert(ret); + assert(image_root); - root = strdup(image_root ?: "/var/lib/machines"); + root = strdup(image_root); if (!root) return -ENOMEM; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 99d8ff0553c..ae573f1b540 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -106,9 +106,10 @@ int tar_pull_new( _cleanup_free_ char *root = NULL; int r; + assert(image_root); assert(ret); - root = strdup(image_root ?: "/var/lib/machines"); + root = strdup(image_root); if (!root) return -ENOMEM; diff --git a/src/import/pull.c b/src/import/pull.c index 518755b61df..f281ab04fdd 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -26,11 +26,12 @@ #include "verbs.h" #include "web-util.h" -static const char *arg_image_root = "/var/lib/machines"; +static const char *arg_image_root = NULL; static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHASH | IMPORT_PULL_ROOTHASH_SIGNATURE | IMPORT_PULL_VERITY | IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC; static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX; static char *arg_checksum = NULL; +static ImageClass arg_class = IMAGE_MACHINE; STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep); @@ -64,7 +65,7 @@ static int normalize_local(const char *local, const char *url, char **ret) { local); if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { - r = image_find(IMAGE_MACHINE, local, NULL, NULL); + r = image_find(arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -241,7 +242,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { static int help(int argc, char *argv[], void *userdata) { printf("%1$s [OPTIONS...] {COMMAND} ...\n" - "\n%4$sDownload container or virtual machine images.%5$s\n" + "\n%4$sDownload disk images.%5$s\n" "\n%2$sCommands:%3$s\n" " tar URL [NAME] Download a TAR image\n" " raw URL [NAME] Download a RAW image\n" @@ -267,7 +268,9 @@ static int help(int argc, char *argv[], void *userdata) { " regular disk images\n" " --sync=BOOL Controls whether to sync() before completing\n" " --offset=BYTES Offset to seek to in destination\n" - " --size-max=BYTES Maximum number of bytes to write to destination\n", + " --size-max=BYTES Maximum number of bytes to write to destination\n" + " --class=CLASS Select image class (machine, sysext, confext,\n" + " portable)\n", program_invocation_short_name, ansi_underline(), ansi_normal(), @@ -296,6 +299,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SYNC, ARG_OFFSET, ARG_SIZE_MAX, + ARG_CLASS, }; static const struct option options[] = { @@ -316,10 +320,12 @@ static int parse_argv(int argc, char *argv[]) { { "sync", required_argument, NULL, ARG_SYNC }, { "offset", required_argument, NULL, ARG_OFFSET }, { "size-max", required_argument, NULL, ARG_SIZE_MAX }, + { "class", required_argument, NULL, ARG_CLASS }, {} }; int c, r; + bool auto_settings = true; assert(argc >= 0); assert(argv); @@ -381,6 +387,7 @@ static int parse_argv(int argc, char *argv[]) { return r; SET_FLAG(arg_import_flags, IMPORT_PULL_SETTINGS, r); + auto_settings = false; break; case ARG_ROOTHASH: @@ -478,6 +485,13 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_CLASS: + arg_class = image_class_from_string(optarg); + if (arg_class < 0) + return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg); + + break; + case '?': return -EINVAL; @@ -497,6 +511,13 @@ static int parse_argv(int argc, char *argv[]) { if (arg_checksum && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Literal checksum verification only supported if no associated files are downloaded."); + if (!arg_image_root) + arg_image_root = image_root_to_string(arg_class); + + /* .nspawn settings files only really make sense for machine images, not for sysext/confext/portable */ + if (auto_settings && arg_class != IMAGE_MACHINE) + arg_import_flags &= ~IMPORT_PULL_SETTINGS; + return 1; } diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 72f20c8eb7e..00d32a9c876 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -99,6 +99,15 @@ static const char* image_class_suffix_table[_IMAGE_CLASS_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(image_class_suffix, ImageClass); +static const char *const image_root_table[_IMAGE_CLASS_MAX] = { + [IMAGE_MACHINE] = "/var/lib/machines", + [IMAGE_PORTABLE] = "/var/lib/portables", + [IMAGE_SYSEXT] = "/var/lib/extensions", + [IMAGE_CONFEXT] = "/var/lib/confexts", +}; + +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(image_root, ImageClass); + static Image *image_free(Image *i) { assert(i); diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h index a30a3d92ba0..350c3a22cc0 100644 --- a/src/shared/discover-image.h +++ b/src/shared/discover-image.h @@ -119,4 +119,6 @@ static inline bool IMAGE_IS_HOST(const struct Image *i) { int image_to_json(const struct Image *i, JsonVariant **ret); +const char *image_root_to_string(ImageClass c) _const_; + extern const struct hash_ops image_hash_ops;