summaryrefslogtreecommitdiffstats
path: root/src/import
diff options
context:
space:
mode:
Diffstat (limited to 'src/import')
-rw-r--r--src/import/curl-util.c45
-rw-r--r--src/import/curl-util.h1
-rw-r--r--src/import/export.c60
-rw-r--r--src/import/import-common.c7
-rw-r--r--src/import/import-common.h37
-rw-r--r--src/import/import-fs.c28
-rw-r--r--src/import/import-raw.c3
-rw-r--r--src/import/import-tar.c3
-rw-r--r--src/import/import.c42
-rw-r--r--src/import/importctl.c1245
-rw-r--r--src/import/importd.c673
-rw-r--r--src/import/meson.build30
-rw-r--r--src/import/org.freedesktop.import1.conf36
-rw-r--r--src/import/org.freedesktop.import1.policy22
-rw-r--r--src/import/pull-common.c19
-rw-r--r--src/import/pull-common.h21
-rw-r--r--src/import/pull-job.c6
-rw-r--r--src/import/pull-raw.c168
-rw-r--r--src/import/pull-raw.h2
-rw-r--r--src/import/pull-tar.c137
-rw-r--r--src/import/pull-tar.h2
-rw-r--r--src/import/pull.c119
-rw-r--r--src/import/qcow2-util.c2
23 files changed, 2262 insertions, 446 deletions
diff --git a/src/import/curl-util.c b/src/import/curl-util.c
index 94f718d..1628f83 100644
--- a/src/import/curl-util.c
+++ b/src/import/curl-util.c
@@ -10,20 +10,28 @@
#include "version.h"
static void curl_glue_check_finished(CurlGlue *g) {
- CURLMsg *msg;
- int k = 0;
+ int r;
assert(g);
+ /* sd_event_get_exit_code() returns -ENODATA if no exit was scheduled yet */
+ r = sd_event_get_exit_code(g->event, /* ret_code= */ NULL);
+ if (r >= 0)
+ return; /* exit scheduled? Then don't process this anymore */
+ if (r != -ENODATA)
+ log_debug_errno(r, "Unexpected error while checking for event loop exit code, ignoring: %m");
+
+ CURLMsg *msg;
+ int k = 0;
msg = curl_multi_info_read(g->curl, &k);
if (!msg)
return;
- if (msg->msg != CURLMSG_DONE)
- return;
-
- if (g->on_finished)
+ if (msg->msg == CURLMSG_DONE && g->on_finished)
g->on_finished(g, msg->easy_handle, msg->data.result);
+
+ /* This is a queue, process another item soon, but do so in a later event loop iteration. */
+ (void) sd_event_source_set_enabled(g->defer, SD_EVENT_ONESHOT);
}
static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -126,6 +134,13 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
assert(curl);
+ /* Don't configure timer anymore when the event loop is dead already. */
+ if (g->timer) {
+ sd_event *event_loop = sd_event_source_get_event(g->timer);
+ if (event_loop && sd_event_get_state(event_loop) == SD_EVENT_FINISHED)
+ return 0;
+ }
+
if (timeout_ms < 0) {
if (g->timer) {
if (sd_event_source_set_enabled(g->timer, SD_EVENT_OFF) < 0)
@@ -153,6 +168,15 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
return 0;
}
+static int curl_glue_on_defer(sd_event_source *s, void *userdata) {
+ CurlGlue *g = ASSERT_PTR(userdata);
+
+ assert(s);
+
+ curl_glue_check_finished(g);
+ return 0;
+}
+
CurlGlue *curl_glue_unref(CurlGlue *g) {
sd_event_source *io;
@@ -167,7 +191,8 @@ CurlGlue *curl_glue_unref(CurlGlue *g) {
hashmap_free(g->ios);
- sd_event_source_unref(g->timer);
+ sd_event_source_disable_unref(g->timer);
+ sd_event_source_disable_unref(g->defer);
sd_event_unref(g->event);
return mfree(g);
}
@@ -211,6 +236,12 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
if (curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback) != CURLM_OK)
return -EINVAL;
+ r = sd_event_add_defer(g->event, &g->defer, curl_glue_on_defer, g);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(g->defer, "curl-defer");
+
*glue = TAKE_PTR(g);
return 0;
diff --git a/src/import/curl-util.h b/src/import/curl-util.h
index 6b4f992..cef0b26 100644
--- a/src/import/curl-util.h
+++ b/src/import/curl-util.h
@@ -16,6 +16,7 @@ struct CurlGlue {
CURLM *curl;
sd_event_source *timer;
Hashmap *ios;
+ sd_event_source *defer;
void (*on_finished)(CurlGlue *g, CURL *curl, CURLcode code);
void *userdata;
diff --git a/src/import/export.c b/src/import/export.c
index 7e941a2..cdb1d62 100644
--- a/src/import/export.c
+++ b/src/import/export.c
@@ -14,6 +14,7 @@
#include "fd-util.h"
#include "fs-util.h"
#include "hostname-util.h"
+#include "import-common.h"
#include "import-util.h"
#include "main-func.h"
#include "signal-util.h"
@@ -22,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) {
@@ -43,12 +45,6 @@ static void determine_compression_from_filename(const char *p) {
arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
}
-static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- log_notice("Transfer aborted.");
- sd_event_exit(sd_event_source_get_event(s), EINTR);
- return 0;
-}
-
static void on_tar_finished(TarExport *export, int error, void *userdata) {
sd_event *event = userdata;
assert(export);
@@ -67,12 +63,13 @@ static int export_tar(int argc, char *argv[], void *userdata) {
_cleanup_close_ int open_fd = -EBADF;
int r, fd;
- if (hostname_is_valid(argv[1], 0)) {
- r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
+ local = argv[1];
+ if (image_name_is_valid(local)) {
+ r = image_find(arg_class, local, NULL, &image);
if (r == -ENOENT)
- return log_error_errno(r, "Machine image %s not found.", argv[1]);
+ return log_error_errno(r, "Image %s not found.", local);
if (r < 0)
- return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
+ return log_error_errno(r, "Failed to look for image %s: %m", local);
local = image->path;
} else
@@ -101,13 +98,9 @@ static int export_tar(int argc, char *argv[], void *userdata) {
log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
}
- r = sd_event_default(&event);
+ r = import_allocate_event_with_signals(&event);
if (r < 0)
- return log_error_errno(r, "Failed to allocate event loop: %m");
-
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
- (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
- (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+ return r;
r = tar_export_new(&export, event, on_tar_finished, event);
if (r < 0)
@@ -143,12 +136,13 @@ static int export_raw(int argc, char *argv[], void *userdata) {
_cleanup_close_ int open_fd = -EBADF;
int r, fd;
- if (hostname_is_valid(argv[1], 0)) {
- r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
+ local = argv[1];
+ if (image_name_is_valid(local)) {
+ r = image_find(arg_class, local, NULL, &image);
if (r == -ENOENT)
- return log_error_errno(r, "Machine image %s not found.", argv[1]);
+ return log_error_errno(r, "Image %s not found.", local);
if (r < 0)
- return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
+ return log_error_errno(r, "Failed to look for image %s: %m", local);
local = image->path;
} else
@@ -177,13 +171,9 @@ static int export_raw(int argc, char *argv[], void *userdata) {
log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
}
- r = sd_event_default(&event);
+ r = import_allocate_event_with_signals(&event);
if (r < 0)
- return log_error_errno(r, "Failed to allocate event loop: %m");
-
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
- (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
- (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+ return r;
r = raw_export_new(&export, event, on_raw_finished, event);
if (r < 0)
@@ -203,14 +193,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\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(),
@@ -225,12 +217,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 },
{}
};
@@ -263,6 +257,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;
@@ -288,8 +289,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
- log_open();
+ log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/import/import-common.c b/src/import/import-common.c
index 319aa07..09faf16 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -276,7 +276,7 @@ bool import_validate_local(const char *name, ImportFlags flags) {
if (FLAGS_SET(flags, IMPORT_DIRECT))
return path_is_valid(name);
- return hostname_is_valid(name, 0);
+ return image_name_is_valid(name);
}
static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
@@ -295,9 +295,8 @@ int import_allocate_event_with_signals(sd_event **ret) {
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
- (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
- (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+ (void) sd_event_add_signal(event, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, interrupt_signal_handler, NULL);
+ (void) sd_event_add_signal(event, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK, interrupt_signal_handler, NULL);
*ret = TAKE_PTR(event);
return 0;
diff --git a/src/import/import-common.h b/src/import/import-common.h
index 97fc16d..2198024 100644
--- a/src/import/import-common.h
+++ b/src/import/import-common.h
@@ -6,16 +6,33 @@
#include "sd-event.h"
typedef enum ImportFlags {
- IMPORT_FORCE = 1 << 0, /* replace existing image */
- IMPORT_READ_ONLY = 1 << 1, /* make generated image read-only */
- IMPORT_BTRFS_SUBVOL = 1 << 2, /* tar: preferably create images as btrfs subvols */
- IMPORT_BTRFS_QUOTA = 1 << 3, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
- IMPORT_CONVERT_QCOW2 = 1 << 4, /* raw: if we detect a qcow2 image, unpack it */
- IMPORT_DIRECT = 1 << 5, /* import without rename games */
- IMPORT_SYNC = 1 << 6, /* fsync() right before we are done */
-
- IMPORT_FLAGS_MASK_TAR = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_BTRFS_SUBVOL|IMPORT_BTRFS_QUOTA|IMPORT_DIRECT|IMPORT_SYNC,
- IMPORT_FLAGS_MASK_RAW = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_CONVERT_QCOW2|IMPORT_DIRECT|IMPORT_SYNC,
+ /* Public Flags (i.e. accessible via D-Bus, must stay stable! */
+ IMPORT_FORCE = 1 << 0, /* replace existing image */
+ IMPORT_READ_ONLY = 1 << 1, /* make generated image read-only */
+ IMPORT_PULL_KEEP_DOWNLOAD = 1 << 2, /* keep a pristine copy of the downloaded file around */
+
+ /* Private flags */
+ IMPORT_BTRFS_SUBVOL = 1 << 3, /* tar: preferably create images as btrfs subvols */
+ IMPORT_BTRFS_QUOTA = 1 << 4, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
+ IMPORT_CONVERT_QCOW2 = 1 << 5, /* raw: if we detect a qcow2 image, unpack it */
+ IMPORT_DIRECT = 1 << 6, /* import without rename games */
+ IMPORT_SYNC = 1 << 7, /* fsync() right before we are done */
+
+ /* When pulling these flags are defined too */
+ IMPORT_PULL_SETTINGS = 1 << 8, /* download .nspawn settings file */
+ IMPORT_PULL_ROOTHASH = 1 << 9, /* only for raw: download .roothash file for verity */
+ IMPORT_PULL_ROOTHASH_SIGNATURE = 1 << 10, /* only for raw: download .roothash.p7s file for verity */
+ IMPORT_PULL_VERITY = 1 << 11, /* only for raw: download .verity file for verity */
+
+ /* The supported flags for the tar and the raw importing */
+ IMPORT_FLAGS_MASK_TAR = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_BTRFS_SUBVOL|IMPORT_BTRFS_QUOTA|IMPORT_DIRECT|IMPORT_SYNC,
+ IMPORT_FLAGS_MASK_RAW = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_CONVERT_QCOW2|IMPORT_DIRECT|IMPORT_SYNC,
+
+ /* The supported flags for the tar and the raw pulling */
+ IMPORT_PULL_FLAGS_MASK_TAR = IMPORT_FLAGS_MASK_TAR|IMPORT_PULL_KEEP_DOWNLOAD|IMPORT_PULL_SETTINGS,
+ IMPORT_PULL_FLAGS_MASK_RAW = IMPORT_FLAGS_MASK_RAW|IMPORT_PULL_KEEP_DOWNLOAD|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 fd79c8f..44fc5be 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;
@@ -132,7 +133,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
"Local path name '%s' is not valid.", final_path);
} else {
if (local) {
- if (!hostname_is_valid(local, 0))
+ if (!image_name_is_valid(local))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.", local);
} else
@@ -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);
@@ -170,6 +171,8 @@ static int import_fs(int argc, char *argv[], void *userdata) {
log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
}
+ log_info("Operating on image directory '%s'.", arg_image_root);
+
if (!arg_sync)
log_info("File system synchronization on completion is off.");
@@ -266,7 +269,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 +292,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 +305,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 +361,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 +375,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;
}
@@ -379,8 +396,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
- log_open();
+ log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index f7ed163..ee9b297 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 9020270..39df11b 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 a81617d..889cd63 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;
@@ -53,7 +54,7 @@ static int normalize_local(const char *local, char **ret) {
"Local path name '%s' is not valid.", local);
} else {
if (local) {
- if (!hostname_is_valid(local, 0))
+ if (!image_name_is_valid(local))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
@@ -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);
@@ -113,6 +114,12 @@ static int open_source(const char *path, const char *local, int *ret_open_fd) {
log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
}
+ if (!FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
+ log_info("Operating on image directory '%s'.", arg_image_root);
+
+ if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
+ log_info("File system synchronization on completion is off.");
+
*ret_open_fd = TAKE_FD(open_fd);
return retval;
}
@@ -160,15 +167,12 @@ static int import_tar(int argc, char *argv[], void *userdata) {
fd = open_source(path, normalized, &open_fd);
if (fd < 0)
- return r;
+ return fd;
r = import_allocate_event_with_signals(&event);
if (r < 0)
return r;
- if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
- log_info("File system synchronization on completion is off.");
-
r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate importer: %m");
@@ -238,9 +242,6 @@ static int import_raw(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
- log_info("File system synchronization on completion is off.");
-
r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate importer: %m");
@@ -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;
}
@@ -475,8 +490,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
- log_open();
+ log_setup();
parse_env();
diff --git a/src/import/importctl.c b/src/import/importctl.c
new file mode 100644
index 0000000..f939d80
--- /dev/null
+++ b/src/import/importctl.c
@@ -0,0 +1,1245 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <getopt.h>
+
+#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "build.h"
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-util.h"
+#include "discover-image.h"
+#include "fd-util.h"
+#include "format-table.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
+#include "locale-util.h"
+#include "log.h"
+#include "macro.h"
+#include "main-func.h"
+#include "os-util.h"
+#include "pager.h"
+#include "parse-argument.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "signal-util.h"
+#include "sort-util.h"
+#include "spawn-polkit-agent.h"
+#include "string-table.h"
+#include "verbs.h"
+#include "web-util.h"
+
+static PagerFlags arg_pager_flags = 0;
+static bool arg_legend = true;
+static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+static const char *arg_host = NULL;
+static ImportFlags arg_import_flags = 0;
+static ImportFlags arg_import_flags_mask = 0; /* Indicates which flags have been explicitly set to on or to off */
+static bool arg_quiet = false;
+static bool arg_ask_password = true;
+static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
+static const char* arg_format = NULL;
+static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
+static ImageClass arg_image_class = _IMAGE_CLASS_INVALID;
+
+#define PROGRESS_PREFIX "Total: "
+
+static int settle_image_class(void) {
+
+ if (arg_image_class < 0) {
+ _cleanup_free_ char *j = NULL;
+
+ for (ImageClass class = 0; class < _IMAGE_CLASS_MAX; class++)
+ if (strextendf_with_separator(&j, ", ", "%s (downloads to %s/)",
+ image_class_to_string(class),
+ image_root_to_string(class)) < 0)
+ return log_oom();
+
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "No image class specified, retry with --class= set to one of: %s.", j);
+ }
+
+ /* Keep the original pristine downloaded file as a copy only when dealing with machine images,
+ * because unlike sysext/confext/portable they are typically modified during runtime. */
+ if (!FLAGS_SET(arg_import_flags_mask, IMPORT_PULL_KEEP_DOWNLOAD))
+ SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_image_class == IMAGE_MACHINE);
+
+ return 0;
+}
+
+typedef struct Context {
+ const char *object_path;
+ double progress;
+} Context;
+
+static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ Context *c = ASSERT_PTR(userdata);
+ const char *line;
+ unsigned priority;
+ int r;
+
+ assert(m);
+
+ if (!streq_ptr(c->object_path, sd_bus_message_get_path(m)))
+ return 0;
+
+ r = sd_bus_message_read(m, "us", &priority, &line);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
+ return 0;
+
+ if (!arg_quiet)
+ clear_progress_bar(PROGRESS_PREFIX);
+
+ log_full(priority, "%s", line);
+
+ if (!arg_quiet)
+ draw_progress_bar(PROGRESS_PREFIX, c->progress * 100);
+
+ return 0;
+}
+
+static int match_progress_update(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ Context *c = ASSERT_PTR(userdata);
+ int r;
+
+ assert(m);
+
+ if (!streq_ptr(c->object_path, sd_bus_message_get_path(m)))
+ return 0;
+
+ r = sd_bus_message_read(m, "d", &c->progress);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ if (!arg_quiet)
+ draw_progress_bar(PROGRESS_PREFIX, c->progress * 100);
+
+ return 0;
+}
+
+static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ Context *c = ASSERT_PTR(userdata);
+ const char *path, *result;
+ uint32_t id;
+ int r;
+
+ assert(m);
+
+ if (!arg_quiet)
+ clear_progress_bar(PROGRESS_PREFIX);
+
+ r = sd_bus_message_read(m, "uos", &id, &path, &result);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ if (!streq_ptr(c->object_path, path))
+ return 0;
+
+ sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done"));
+ return 0;
+}
+
+static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ assert(s);
+ assert(si);
+
+ if (!arg_quiet)
+ clear_progress_bar(PROGRESS_PREFIX);
+
+ if (!arg_quiet)
+ log_info("Continuing download in the background. Use \"%s cancel-transfer %" PRIu32 "\" to abort transfer.",
+ program_invocation_short_name,
+ PTR_TO_UINT32(userdata));
+
+ sd_event_exit(sd_event_source_get_event(s), EINTR);
+ return 0;
+}
+
+static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
+ _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL, *slot_progress_update = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_event_unrefp) sd_event* event = NULL;
+ Context c = {};
+ uint32_t id;
+ int r;
+
+ assert(bus);
+ assert(m);
+
+ polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get event loop: %m");
+
+ r = sd_bus_attach_event(bus, event, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
+
+ r = bus_match_signal_async(
+ bus,
+ &slot_job_removed,
+ bus_import_mgr,
+ "TransferRemoved",
+ match_transfer_removed,
+ /* add_callback= */ NULL,
+ &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match: %m");
+
+ r = sd_bus_match_signal_async(
+ bus,
+ &slot_log_message,
+ "org.freedesktop.import1",
+ /* object_path= */ NULL,
+ "org.freedesktop.import1.Transfer",
+ "LogMessage",
+ match_log_message,
+ /* add_callback= */ NULL,
+ &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match: %m");
+
+ r = sd_bus_match_signal_async(
+ bus,
+ &slot_progress_update,
+ "org.freedesktop.import1",
+ /* object_path= */ NULL,
+ "org.freedesktop.import1.Transfer",
+ "ProgressUpdate",
+ match_progress_update,
+ /* add_callback= */ NULL,
+ &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match: %m");
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0)
+ return log_error_errno(r, "Failed to transfer image: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_read(reply, "uo", &id, &c.object_path);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (!arg_quiet) {
+ clear_progress_bar(PROGRESS_PREFIX);
+ log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
+ draw_progress_bar(PROGRESS_PREFIX, c.progress);
+ }
+
+ (void) sd_event_add_signal(event, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK, transfer_signal_handler, UINT32_TO_PTR(id));
+ (void) sd_event_add_signal(event, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, transfer_signal_handler, UINT32_TO_PTR(id));
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ return -r;
+}
+
+static int import_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_free_ char *ll = NULL, *fn = NULL;
+ const char *local = NULL, *path = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ if (argc >= 2)
+ path = empty_or_dash_to_null(argv[1]);
+
+ if (argc >= 3)
+ local = empty_or_dash_to_null(argv[2]);
+ else if (path) {
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return log_error_errno(r, "Cannot extract container name from filename: %m");
+ if (r == O_DIRECTORY)
+ return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
+ "Path '%s' refers to directory, but we need a regular file: %m", path);
+
+ local = fn;
+ }
+ if (!local)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Need either path or local name.");
+
+ r = tar_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Local name %s is not a suitable image name.",
+ local);
+
+ if (path) {
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && (arg_import_flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY)) == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportTar");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsbb",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ FLAGS_SET(arg_import_flags, IMPORT_FORCE),
+ FLAGS_SET(arg_import_flags, IMPORT_READ_ONLY));
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportTarEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsst",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ image_class_to_string(arg_image_class),
+ (uint64_t) arg_import_flags & (IMPORT_FORCE|IMPORT_READ_ONLY));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int import_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_free_ char *ll = NULL, *fn = NULL;
+ const char *local = NULL, *path = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ if (argc >= 2)
+ path = empty_or_dash_to_null(argv[1]);
+
+ if (argc >= 3)
+ local = empty_or_dash_to_null(argv[2]);
+ else if (path) {
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return log_error_errno(r, "Cannot extract container name from filename: %m");
+ if (r == O_DIRECTORY)
+ return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
+ "Path '%s' refers to directory, but we need a regular file: %m", path);
+
+ local = fn;
+ }
+ if (!local)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Need either path or local name.");
+
+ r = raw_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Local name %s is not a suitable image name.",
+ local);
+
+ if (path) {
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && (arg_import_flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY)) == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportRaw");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsbb",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ FLAGS_SET(arg_import_flags, IMPORT_FORCE),
+ FLAGS_SET(arg_import_flags, IMPORT_READ_ONLY));
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportRawEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsst",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ image_class_to_string(arg_image_class),
+ (uint64_t) arg_import_flags & (IMPORT_FORCE|IMPORT_READ_ONLY));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int import_fs(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ const char *local = NULL, *path = NULL;
+ _cleanup_free_ char *fn = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ if (argc >= 2)
+ path = empty_or_dash_to_null(argv[1]);
+
+ if (argc >= 3)
+ local = empty_or_dash_to_null(argv[2]);
+ else if (path) {
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return log_error_errno(r, "Cannot extract container name from filename: %m");
+
+ local = fn;
+ }
+ if (!local)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Need either path or local name.");
+
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Local name %s is not a suitable image name.",
+ local);
+
+ if (path) {
+ fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open directory '%s': %m", path);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && (arg_import_flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY)) == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportFileSystem");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsbb",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ FLAGS_SET(arg_import_flags, IMPORT_FORCE),
+ FLAGS_SET(arg_import_flags, IMPORT_READ_ONLY));
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportFileSystemEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsst",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ image_class_to_string(arg_image_class),
+ (uint64_t) arg_import_flags & (IMPORT_FORCE|IMPORT_READ_ONLY));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+
+ return transfer_image_common(bus, m);
+}
+
+static void determine_compression_from_filename(const char *p) {
+ if (arg_format)
+ return;
+
+ if (!p)
+ return;
+
+ if (endswith(p, ".xz"))
+ arg_format = "xz";
+ else if (endswith(p, ".gz"))
+ arg_format = "gzip";
+ else if (endswith(p, ".bz2"))
+ arg_format = "bzip2";
+}
+
+static int export_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ local = argv[1];
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Image name %s is not valid.", local);
+
+ if (argc >= 3)
+ path = argv[2];
+ path = empty_or_dash_to_null(path);
+
+ if (path) {
+ determine_compression_from_filename(path);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && arg_import_flags == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportTar");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "shs",
+ local,
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format);
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportTarEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sshst",
+ local,
+ image_class_to_string(arg_image_class),
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format,
+ /* flags= */ UINT64_C(0));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int export_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ local = argv[1];
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Image name %s is not valid.", local);
+
+ if (argc >= 3)
+ path = argv[2];
+ path = empty_or_dash_to_null(path);
+
+ if (path) {
+ determine_compression_from_filename(path);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && arg_import_flags == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportRaw");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "shs",
+ local,
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format);
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportRawEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sshst",
+ local,
+ image_class_to_string(arg_image_class),
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format,
+ /* flags= */ UINT64_C(0));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int pull_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_free_ char *l = NULL, *ll = NULL;
+ const char *local, *remote;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ remote = argv[1];
+ if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "URL '%s' is not valid.", remote);
+
+ if (argc >= 3)
+ local = argv[2];
+ else {
+ r = import_url_last_component(remote, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get final component of URL: %m");
+
+ local = l;
+ }
+
+ local = empty_or_dash_to_null(local);
+
+ if (local) {
+ r = tar_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Local name %s is not a suitable image name.",
+ local);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && (arg_import_flags & ~IMPORT_FORCE) == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTar");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sssb",
+ remote,
+ local,
+ import_verify_to_string(arg_verify),
+ FLAGS_SET(arg_import_flags, IMPORT_FORCE));
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTarEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sssst",
+ remote,
+ local,
+ image_class_to_string(arg_image_class),
+ import_verify_to_string(arg_verify),
+ (uint64_t) arg_import_flags & (IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_PULL_KEEP_DOWNLOAD));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int pull_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_free_ char *l = NULL, *ll = NULL;
+ const char *local, *remote;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ r = settle_image_class();
+ if (r < 0)
+ return r;
+
+ remote = argv[1];
+ if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "URL '%s' is not valid.", remote);
+
+ if (argc >= 3)
+ local = argv[2];
+ else {
+ r = import_url_last_component(remote, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get final component of URL: %m");
+
+ local = l;
+ }
+
+ local = empty_or_dash_to_null(local);
+
+ if (local) {
+ r = raw_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!image_name_is_valid(local))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Local name %s is not a suitable image name.",
+ local);
+ }
+
+ if (arg_image_class == IMAGE_MACHINE && (arg_import_flags & ~IMPORT_FORCE) == 0) {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRaw");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sssb",
+ remote,
+ local,
+ import_verify_to_string(arg_verify),
+ FLAGS_SET(arg_import_flags, IMPORT_FORCE));
+ } else {
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRawEx");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "sssst",
+ remote,
+ local,
+ image_class_to_string(arg_image_class),
+ import_verify_to_string(arg_verify),
+ (uint64_t) arg_import_flags & (IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_PULL_KEEP_DOWNLOAD));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int list_transfers(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(table_unrefp) Table *t = NULL;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ pager_open(arg_pager_flags);
+
+ bool ex;
+ r = bus_call_method(bus, bus_import_mgr, "ListTransfersEx", &error, &reply, "st", image_class_to_string(arg_image_class), UINT64_C(0));
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ sd_bus_error_free(&error);
+
+ r = bus_call_method(bus, bus_import_mgr, "ListTransfers", &error, &reply, NULL);
+ }
+ if (r < 0)
+ return log_error_errno(r, "Could not get transfers: %s", bus_error_message(&error, r));
+
+ ex = false;
+ r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
+ } else {
+ ex = true;
+ r = sd_bus_message_enter_container(reply, 'a', "(ussssdo)");
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ t = table_new("id", "progress", "type", "class", "local", "remote");
+ if (!t)
+ return log_oom();
+
+ (void) table_set_sort(t, (size_t) 4, (size_t) 0);
+ table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
+
+ for (;;) {
+ const char *type, *remote, *local, *class = "machine";
+ double progress;
+ uint32_t id;
+
+ if (ex)
+ r = sd_bus_message_read(reply, "(ussssdo)", &id, &type, &remote, &local, &class, &progress, NULL);
+ else
+ r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, NULL);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ if (r == 0)
+ break;
+
+ /* Ideally we use server-side filtering. But if the server can't do it, we need to do it client side */
+ if (arg_image_class >= 0 && image_class_from_string(class) != arg_image_class)
+ continue;
+
+ r = table_add_many(
+ t,
+ TABLE_UINT32, id,
+ TABLE_SET_ALIGN_PERCENT, 100);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (progress < 0)
+ r = table_add_many(
+ t,
+ TABLE_EMPTY,
+ TABLE_SET_ALIGN_PERCENT, 100);
+ else
+ r = table_add_many(
+ t,
+ TABLE_PERCENT, (int) (progress * 100),
+ TABLE_SET_ALIGN_PERCENT, 100);
+ if (r < 0)
+ return table_log_add_error(r);
+ r = table_add_many(
+ t,
+ TABLE_STRING, type,
+ TABLE_STRING, class,
+ TABLE_STRING, local,
+ TABLE_STRING, remote,
+ TABLE_SET_URL, remote);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (!table_isempty(t)) {
+ r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
+ if (r < 0)
+ return log_error_errno(r, "Failed to output table: %m");
+ }
+
+ if (arg_legend) {
+ if (!table_isempty(t))
+ printf("\n%zu transfers listed.\n", table_get_rows(t) - 1);
+ else
+ printf("No transfers.\n");
+ }
+
+ return 0;
+}
+
+static int cancel_transfer(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+ for (int i = 1; i < argc; i++) {
+ uint32_t id;
+
+ r = safe_atou32(argv[i], &id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
+
+ r = bus_call_method(bus, bus_import_mgr, "CancelTransfer", &error, NULL, "u", id);
+ if (r < 0)
+ return log_error_errno(r, "Could not cancel transfer: %s", bus_error_message(&error, r));
+ }
+
+ return 0;
+}
+
+static int list_images(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(table_unrefp) Table *t = NULL;
+ sd_bus *bus = ASSERT_PTR(userdata);
+ int r;
+
+ pager_open(arg_pager_flags);
+
+ r = bus_call_method(bus, bus_import_mgr, "ListImages", &error, &reply, "st", image_class_to_string(arg_image_class), UINT64_C(0));
+ if (r < 0)
+ return log_error_errno(r, "Could not list images: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_enter_container(reply, 'a', "(ssssbtttttt)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ t = table_new("class", "name", "type", "path", "ro", "crtime", "mtime", "usage", "usage-exclusive", "limit", "limit-exclusive");
+ if (!t)
+ return log_oom();
+
+ (void) table_set_sort(t, (size_t) 0, (size_t) 1);
+ table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
+
+ /* Hide the exclusive columns for now */
+ (void) table_hide_column_from_display(t, 8);
+ (void) table_hide_column_from_display(t, 10);
+
+ for (;;) {
+ uint64_t crtime, mtime, usage, usage_exclusive, limit, limit_exclusive;
+ const char *class, *name, *type, *path;
+ int read_only;
+
+ r = sd_bus_message_read(reply, "(ssssbtttttt)", &class, &name, &type, &path, &read_only, &crtime, &mtime, &usage, &usage_exclusive, &limit, &limit_exclusive);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ if (r == 0)
+ break;
+
+ r = table_add_many(
+ t,
+ TABLE_STRING, class,
+ TABLE_STRING, name,
+ TABLE_STRING, type,
+ TABLE_PATH, path);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
+ r = table_add_many(
+ t,
+ TABLE_STRING, read_only ? "ro" : "rw",
+ TABLE_SET_COLOR, read_only ? ANSI_HIGHLIGHT_RED : ANSI_HIGHLIGHT_GREEN);
+ else
+ r = table_add_many(
+ t,
+ TABLE_BOOLEAN, read_only);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(
+ t,
+ TABLE_TIMESTAMP, crtime,
+ TABLE_TIMESTAMP, mtime,
+ TABLE_SIZE, usage,
+ TABLE_SIZE, usage_exclusive,
+ TABLE_SIZE, limit,
+ TABLE_SIZE, limit_exclusive);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (!table_isempty(t)) {
+ r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
+ if (r < 0)
+ return log_error_errno(r, "Failed to output table: %m");
+ }
+
+ if (arg_legend) {
+ if (!table_isempty(t))
+ printf("\n%zu images listed.\n", table_get_rows(t) - 1);
+ else
+ printf("No images.\n");
+ }
+
+ return 0;
+}
+
+static int help(int argc, char *argv[], void *userdata) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ pager_open(arg_pager_flags);
+
+ r = terminal_urlify_man("importctl", "1", &link);
+ if (r < 0)
+ return log_oom();
+
+ printf("%1$s [OPTIONS...] COMMAND ...\n\n"
+ "%5$sDownload, import or export disk images%6$s\n"
+ "\n%3$sCommands:%4$s\n"
+ " pull-tar URL [NAME] Download a TAR container image\n"
+ " pull-raw URL [NAME] Download a RAW container or VM image\n"
+ " import-tar FILE [NAME] Import a local TAR container image\n"
+ " import-raw FILE [NAME] Import a local RAW container or VM image\n"
+ " import-fs DIRECTORY [NAME] Import a local directory container image\n"
+ " export-tar NAME [FILE] Export a TAR container image locally\n"
+ " export-raw NAME [FILE] Export a RAW container or VM image locally\n"
+ " list-transfers Show list of transfers in progress\n"
+ " cancel-transfer [ID...] Cancel a transfer\n"
+ " list-images Show list of installed images\n"
+ "\n%3$sOptions:%4$s\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --no-pager Do not pipe output into a pager\n"
+ " --no-legend Do not show the headers and footers\n"
+ " --no-ask-password Do not ask for system passwords\n"
+ " -H --host=[USER@]HOST Operate on remote host\n"
+ " -M --machine=CONTAINER Operate on local container\n"
+ " --read-only Create read-only image\n"
+ " -q --quiet Suppress output\n"
+ " --json=pretty|short|off Generate JSON output\n"
+ " -j Equvilant to --json=pretty on TTY, --json=short\n"
+ " otherwise\n"
+ " --verify=MODE Verification mode for downloaded images (no,\n"
+ " checksum, signature)\n"
+ " --format=xz|gzip|bzip2 Desired output format for export\n"
+ " --force Install image even if already exists\n"
+ " -m --class=machine Install as machine image\n"
+ " -P --class=portable Install as portable service image\n"
+ " -S --class=sysext Install as system extension image\n"
+ " -C --class=confext Install as configuration extension image\n"
+ " --keep-download=BOOL Control whether to keep pristine copy of download\n"
+ " -N Shortcut for --keep-download=no\n"
+ "\nSee the %2$s for details.\n",
+ program_invocation_short_name,
+ link,
+ ansi_underline(),
+ ansi_normal(),
+ ansi_highlight(),
+ ansi_normal());
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_NO_PAGER,
+ ARG_NO_LEGEND,
+ ARG_NO_ASK_PASSWORD,
+ ARG_READ_ONLY,
+ ARG_JSON,
+ ARG_VERIFY,
+ ARG_FORCE,
+ ARG_FORMAT,
+ ARG_CLASS,
+ ARG_KEEP_DOWNLOAD,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
+ { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+ { "host", required_argument, NULL, 'H' },
+ { "machine", required_argument, NULL, 'M' },
+ { "read-only", no_argument, NULL, ARG_READ_ONLY },
+ { "json", required_argument, NULL, ARG_JSON },
+ { "quiet", no_argument, NULL, 'q' },
+ { "verify", required_argument, NULL, ARG_VERIFY },
+ { "force", no_argument, NULL, ARG_FORCE },
+ { "format", required_argument, NULL, ARG_FORMAT },
+ { "class", required_argument, NULL, ARG_CLASS },
+ { "keep-download", required_argument, NULL, ARG_KEEP_DOWNLOAD },
+ {}
+ };
+
+ int c, r;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ for (;;) {
+ c = getopt_long(argc, argv, "hH:M:jqmPSCN", options, NULL);
+ if (c < 0)
+ break;
+
+ switch (c) {
+
+ case 'h':
+ return help(0, NULL, NULL);
+
+ case ARG_VERSION:
+ return version();
+
+ case ARG_NO_PAGER:
+ arg_pager_flags |= PAGER_DISABLE;
+ break;
+
+ case ARG_NO_LEGEND:
+ arg_legend = false;
+ break;
+
+ case ARG_NO_ASK_PASSWORD:
+ arg_ask_password = false;
+ break;
+
+ case 'H':
+ arg_transport = BUS_TRANSPORT_REMOTE;
+ arg_host = optarg;
+ break;
+
+ case 'M':
+ arg_transport = BUS_TRANSPORT_MACHINE;
+ arg_host = optarg;
+ break;
+
+ case ARG_READ_ONLY:
+ arg_import_flags |= IMPORT_READ_ONLY;
+ arg_import_flags_mask |= IMPORT_READ_ONLY;
+ break;
+
+ case 'q':
+ arg_quiet = true;
+ break;
+
+ case ARG_VERIFY:
+ if (streq(optarg, "help")) {
+ DUMP_STRING_TABLE(import_verify, ImportVerify, _IMPORT_VERIFY_MAX);
+ return 0;
+ }
+
+ r = import_verify_from_string(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --verify= setting: %s", optarg);
+ arg_verify = r;
+ break;
+
+ case ARG_FORCE:
+ arg_import_flags |= IMPORT_FORCE;
+ arg_import_flags_mask |= IMPORT_FORCE;
+ break;
+
+ case ARG_FORMAT:
+ if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown format: %s", optarg);
+
+ arg_format = optarg;
+ break;
+
+ case ARG_JSON:
+ r = parse_json_argument(optarg, &arg_json_format_flags);
+ if (r <= 0)
+ return r;
+
+ arg_legend = false;
+ break;
+
+ case 'j':
+ arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO;
+ arg_legend = false;
+ break;
+
+ case ARG_CLASS:
+ arg_image_class = image_class_from_string(optarg);
+ if (arg_image_class < 0)
+ return log_error_errno(arg_image_class, "Failed to parse --class= parameter: %s", optarg);
+ break;
+
+ case 'm':
+ arg_image_class = IMAGE_MACHINE;
+ break;
+
+ case 'P':
+ arg_image_class = IMAGE_PORTABLE;
+ break;
+
+ case 'S':
+ arg_image_class = IMAGE_SYSEXT;
+ break;
+
+ case 'C':
+ arg_image_class = IMAGE_CONFEXT;
+ break;
+
+ case ARG_KEEP_DOWNLOAD:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --keep-download= value: %s", optarg);
+
+ SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, r);
+ arg_import_flags_mask |= IMPORT_PULL_KEEP_DOWNLOAD;
+ break;
+
+ case 'N':
+ arg_import_flags_mask &= ~IMPORT_PULL_KEEP_DOWNLOAD;
+ arg_import_flags_mask |= IMPORT_PULL_KEEP_DOWNLOAD;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached();
+ }
+ }
+
+ return 1;
+}
+
+static int importctl_main(int argc, char *argv[], sd_bus *bus) {
+
+ static const Verb verbs[] = {
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "import-tar", 2, 3, 0, import_tar },
+ { "import-raw", 2, 3, 0, import_raw },
+ { "import-fs", 2, 3, 0, import_fs },
+ { "export-tar", 2, 3, 0, export_tar },
+ { "export-raw", 2, 3, 0, export_raw },
+ { "pull-tar", 2, 3, 0, pull_tar },
+ { "pull-raw", 2, 3, 0, pull_raw },
+ { "list-transfers", VERB_ANY, 1, VERB_DEFAULT, list_transfers },
+ { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
+ { "list-images", VERB_ANY, 1, 0, list_images },
+ {}
+ };
+
+ return dispatch_verb(argc, argv, verbs, bus);
+}
+
+static int run(int argc, char *argv[]) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ int r;
+
+ setlocale(LC_ALL, "");
+ log_setup();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r;
+
+ r = bus_connect_transport(arg_transport, arg_host, RUNTIME_SCOPE_SYSTEM, &bus);
+ if (r < 0)
+ return bus_log_connect_error(r, arg_transport);
+
+ (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
+
+ return importctl_main(argc, argv, bus);
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/import/importd.c b/src/import/importd.c
index e1a1ddc..3bfa3cd 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -6,21 +6,27 @@
#include "sd-bus.h"
#include "alloc-util.h"
+#include "build-path.h"
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
#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"
@@ -61,12 +67,11 @@ struct Transfer {
char *remote;
char *local;
- bool force_local;
- bool read_only;
-
+ ImageClass class;
+ ImportFlags flags;
char *format;
- pid_t pid;
+ PidRef pidref;
int log_fd;
@@ -78,6 +83,7 @@ struct Transfer {
unsigned n_canceled;
unsigned progress_percent;
+ unsigned progress_percent_sent;
int stdin_fd;
int stdout_fd;
@@ -105,11 +111,11 @@ struct Manager {
static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
[TRANSFER_IMPORT_TAR] = "import-tar",
[TRANSFER_IMPORT_RAW] = "import-raw",
- [TRANSFER_IMPORT_FS] = "import-fs",
+ [TRANSFER_IMPORT_FS] = "import-fs",
[TRANSFER_EXPORT_TAR] = "export-tar",
[TRANSFER_EXPORT_RAW] = "export-raw",
- [TRANSFER_PULL_TAR] = "pull-tar",
- [TRANSFER_PULL_RAW] = "pull-raw",
+ [TRANSFER_PULL_TAR] = "pull-tar",
+ [TRANSFER_PULL_RAW] = "pull-raw",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
@@ -129,8 +135,7 @@ static Transfer *transfer_unref(Transfer *t) {
free(t->format);
free(t->object_path);
- if (t->pid > 1)
- sigkill_wait(t->pid);
+ pidref_done_sigkill_wait(&t->pidref);
safe_close(t->log_fd);
safe_close(t->stdin_fd);
@@ -162,7 +167,8 @@ static int transfer_new(Manager *m, Transfer **ret) {
.stdin_fd = -EBADF,
.stdout_fd = -EBADF,
.verify = _IMPORT_VERIFY_INVALID,
- .progress_percent= UINT_MAX,
+ .progress_percent = UINT_MAX,
+ .progress_percent_sent = UINT_MAX,
};
id = m->current_transfer_id + 1;
@@ -213,7 +219,28 @@ static void transfer_send_log_line(Transfer *t, const char *line) {
line);
if (r < 0)
log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
- }
+}
+
+static void transfer_send_progress_update(Transfer *t) {
+ int r;
+
+ assert(t);
+
+ if (t->progress_percent_sent == t->progress_percent)
+ return;
+
+ r = sd_bus_emit_signal(
+ t->manager->bus,
+ t->object_path,
+ "org.freedesktop.import1.Transfer",
+ "ProgressUpdate",
+ "d",
+ transfer_percent_as_double(t));
+ if (r < 0)
+ log_warning_errno(r, "Cannot emit progress update signal, ignoring: %m");
+
+ t->progress_percent_sent = t->progress_percent;
+}
static void transfer_send_logs(Transfer *t, bool flush) {
assert(t);
@@ -300,7 +327,7 @@ static int transfer_cancel(Transfer *t) {
assert(t);
- r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
+ r = pidref_kill_and_sigcont(&t->pidref, t->n_canceled < 3 ? SIGTERM : SIGKILL);
if (r < 0)
return r;
@@ -327,7 +354,7 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda
else
log_error("Transfer process failed due to unknown reason.");
- t->pid = 0;
+ pidref_done(&t->pidref);
return transfer_finalize(t, success);
}
@@ -361,15 +388,17 @@ static int transfer_start(Transfer *t) {
int r;
assert(t);
- assert(t->pid <= 0);
+ assert(!pidref_is_set(&t->pidref));
if (pipe2(pipefd, O_CLOEXEC) < 0)
return -errno;
- r = safe_fork_full("(sd-transfer)",
- (int[]) { t->stdin_fd, t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd, pipefd[1] },
- NULL, 0,
- FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO, &t->pid);
+ r = pidref_safe_fork_full(
+ "(sd-transfer)",
+ (int[]) { t->stdin_fd, t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd, pipefd[1] },
+ /* except_fds= */ NULL, /* n_except_fds= */ 0,
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG,
+ &t->pidref);
if (r < 0)
return r;
if (r == 0) {
@@ -378,6 +407,9 @@ static int transfer_start(Transfer *t) {
NULL, /* tar, raw */
NULL, /* --verify= */
NULL, /* verify argument */
+ NULL, /* --class= */
+ NULL, /* class argument */
+ NULL, /* --keep-download= */
NULL, /* maybe --force */
NULL, /* maybe --read-only */
NULL, /* if so: the actual URL */
@@ -387,7 +419,7 @@ static int transfer_start(Transfer *t) {
NULL, /* local */
NULL
};
- unsigned k = 0;
+ size_t k = 0;
/* Child */
@@ -397,6 +429,10 @@ static int transfer_start(Transfer *t) {
_exit(EXIT_FAILURE);
}
+ r = setenv_systemd_log_level();
+ if (r < 0)
+ log_warning_errno(r, "Failed to update $SYSTEMD_LOG_LEVEL, ignoring: %m");
+
r = setenv_systemd_exec_pid(true);
if (r < 0)
log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
@@ -453,9 +489,18 @@ 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 (IN_SET(t->type, TRANSFER_PULL_TAR, TRANSFER_PULL_RAW))
+ cmd[k++] = FLAGS_SET(t->flags, IMPORT_PULL_KEEP_DOWNLOAD) ?
+ "--keep-download=yes" : "--keep-download=no";
+
+ 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) {
@@ -474,8 +519,15 @@ static int transfer_start(Transfer *t) {
cmd[k++] = t->local;
cmd[k] = NULL;
- execv(cmd[0], (char * const *) cmd);
- log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
+ assert(k < ELEMENTSOF(cmd));
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *joined = strv_join((char**) cmd, " ");
+ log_debug("Calling: %s", strnull(joined));
+ }
+
+ r = invoke_callout_binary(cmd[0], (char * const *) cmd);
+ log_error_errno(r, "Failed to execute %s tool: %m", cmd[0]);
_exit(EXIT_FAILURE);
}
@@ -484,8 +536,13 @@ static int transfer_start(Transfer *t) {
t->stdin_fd = safe_close(t->stdin_fd);
- r = sd_event_add_child(t->manager->event, &t->pid_event_source,
- t->pid, WEXITED, transfer_on_pid, t);
+ r = event_add_child_pidref(
+ t->manager->event,
+ &t->pid_event_source,
+ &t->pidref,
+ WEXITED,
+ transfer_on_pid,
+ t);
if (r < 0)
return r;
@@ -527,7 +584,7 @@ static Manager *manager_unref(Manager *m) {
hashmap_free(m->transfers);
- bus_verify_polkit_async_registry_free(m->polkit_registry);
+ hashmap_free(m->polkit_registry);
m->bus = sd_bus_flush_close_unref(m->bus);
sd_event_unref(m->event);
@@ -580,7 +637,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
}
HASHMAP_FOREACH(t, m->transfers)
- if (ucred->pid == t->pid)
+ if (ucred->pid == t->pidref.pid)
break;
if (!t) {
@@ -605,6 +662,8 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
t->progress_percent = (unsigned) r;
log_debug("Got percentage from client: %u%%", t->progress_percent);
+
+ transfer_send_progress_update(t);
return 0;
}
@@ -631,17 +690,11 @@ static int manager_new(Manager **ret) {
if (r < 0)
return r;
- (void) sd_event_set_watchdog(m->event, true);
-
- r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
- if (r < 0)
- return r;
-
- r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
+ r = sd_event_set_signal_exit(m->event, true);
if (r < 0)
return r;
- r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
+ r = sd_event_add_signal(m->event, NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL);
if (r < 0)
return r;
@@ -649,6 +702,10 @@ static int manager_new(Manager **ret) {
if (r < 0)
log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
+ r = sd_event_set_watchdog(m->event, true);
+ if (r < 0)
+ log_debug_errno(r, "Failed to enable watchdog logic, ignoring: %m");
+
r = sd_bus_default_system(&m->bus);
if (r < 0)
return r;
@@ -693,22 +750,20 @@ 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);
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
"org.freedesktop.import1.import",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -716,7 +771,36 @@ 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 (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_safe_flags(fd);
if (r < 0)
return r;
@@ -726,15 +810,17 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
return -EINVAL;
- if (!hostname_is_valid(local, 0))
+ if (!image_name_is_valid(local))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Local name %s is invalid", local);
+ "Local image 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);
@@ -742,8 +828,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)
@@ -757,29 +843,28 @@ 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);
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
"org.freedesktop.import1.import",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -787,7 +872,36 @@ 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 (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_safe_flags_full(fd, O_DIRECTORY);
if (r < 0)
return r;
@@ -795,21 +909,23 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
if (r < 0)
return r;
- if (!hostname_is_valid(local, 0))
+ if (!image_name_is_valid(local))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Local name %s is invalid", local);
+ "Local image 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)
@@ -823,31 +939,30 @@ 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);
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
"org.freedesktop.import1.export",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -855,13 +970,37 @@ 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;
- if (!hostname_is_valid(local, 0))
+ 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 (!image_name_is_valid(local))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Local name %s is invalid", local);
+ "Local image name %s is invalid", local);
+
+ r = fd_verify_safe_flags(fd);
+ if (r < 0)
+ return r;
if (fstat(fd, &st) < 0)
return -errno;
@@ -869,7 +1008,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 +1016,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,31 +1037,30 @@ 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);
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -928,9 +1068,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|IMPORT_PULL_KEEP_DOWNLOAD))
+ 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,
@@ -938,9 +1102,9 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
if (isempty(local))
local = NULL;
- else if (!hostname_is_valid(local, 0))
+ else if (!image_name_is_valid(local))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Local name %s is invalid", local);
+ "Local image name %s is invalid", local);
if (isempty(verify))
v = IMPORT_VERIFY_SIGNATURE;
@@ -950,11 +1114,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))
@@ -967,7 +1133,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)
@@ -983,40 +1150,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;
}
@@ -1036,11 +1244,8 @@ static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *erro
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&t->manager->polkit_registry,
error);
if (r < 0)
@@ -1065,11 +1270,8 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
r = bus_verify_polkit_async(
msg,
- CAP_SYS_ADMIN,
- "org.freedesktop.import1.pull",
- NULL,
- false,
- UID_INVALID,
+ "org.freedesktop.import1.cancel",
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -1094,6 +1296,86 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
return sd_bus_reply_method_return(msg, NULL);
}
+static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ ImageClass class = _IMAGE_CLASS_INVALID;
+ int r;
+
+ assert(msg);
+
+ const char *sclass;
+ uint64_t flags;
+
+ r = sd_bus_message_read(msg, "st", &sclass, &flags);
+ if (r < 0)
+ return 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', "(ssssbtttttt)");
+ if (r < 0)
+ return r;
+
+ for (ImageClass c = class < 0 ? 0 : class;
+ class < 0 ? (c < _IMAGE_CLASS_MAX) : (c == class);
+ c++) {
+
+ _cleanup_(hashmap_freep) Hashmap *h = NULL;
+
+ h = hashmap_new(&image_hash_ops);
+ if (!h)
+ return -ENOMEM;
+
+ r = image_discover(c, /* root= */ NULL, h);
+ if (r < 0) {
+ if (class >= 0)
+ return r;
+
+ log_warning_errno(r, "Failed to discover images of type %s: %m", image_class_to_string(c));
+ continue;
+ }
+
+ Image *i;
+ HASHMAP_FOREACH(i, h) {
+ r = sd_bus_message_append(
+ reply,
+ "(ssssbtttttt)",
+ image_class_to_string(i->class),
+ i->name,
+ image_type_to_string(i->type),
+ i->path,
+ i->read_only,
+ i->crtime,
+ i->mtime,
+ i->usage,
+ i->usage_exclusive,
+ i->limit,
+ i->limit_exclusive);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int property_get_progress(
sd_bus *bus,
const char *path,
@@ -1196,6 +1478,10 @@ static const sd_bus_vtable transfer_vtable[] = {
SD_BUS_PARAM(priority)
SD_BUS_PARAM(line),
0),
+ SD_BUS_SIGNAL_WITH_NAMES("ProgressUpdate",
+ "d",
+ SD_BUS_PARAM(progress),
+ 0),
SD_BUS_VTABLE_END,
};
@@ -1221,6 +1507,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)
@@ -1232,6 +1529,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)
@@ -1243,6 +1551,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)
@@ -1253,6 +1572,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)
@@ -1263,6 +1594,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)
@@ -1274,6 +1617,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)
@@ -1285,18 +1640,46 @@ 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),
NULL,,
method_cancel_transfer,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("ListImages",
+ "st",
+ SD_BUS_PARAM(class)
+ SD_BUS_PARAM(flags),
+ "a(ssssbtttttt)",
+ SD_BUS_PARAM(images),
+ method_list_images,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
"uo",
@@ -1350,18 +1733,6 @@ static bool manager_check_idle(void *userdata) {
return hashmap_isempty(m->transfers);
}
-static int manager_run(Manager *m) {
- assert(m);
-
- return bus_event_loop_with_idle(
- m->event,
- m->bus,
- "org.freedesktop.import1",
- DEFAULT_EXIT_USEC,
- manager_check_idle,
- m);
-}
-
static void manager_parse_env(Manager *m) {
int r;
@@ -1400,7 +1771,7 @@ static int run(int argc, char *argv[]) {
umask(0022);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
@@ -1412,7 +1783,17 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
- r = manager_run(m);
+ r = sd_notify(false, NOTIFY_READY);
+ if (r < 0)
+ log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
+
+ r = bus_event_loop_with_idle(
+ m->event,
+ m->bus,
+ "org.freedesktop.import1",
+ DEFAULT_EXIT_USEC,
+ manager_check_idle,
+ m);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
diff --git a/src/import/meson.build b/src/import/meson.build
index 3f0acf8..184dd7b 100644
--- a/src/import/meson.build
+++ b/src/import/meson.build
@@ -1,5 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
+if conf.get('ENABLE_IMPORTD') != 1
+ subdir_done()
+endif
+
systemd_importd_sources = files(
'importd.c',
)
@@ -100,6 +104,12 @@ executables += [
'link_with' : common_libs,
'dependencies' : common_deps,
},
+ executable_template + {
+ 'name' : 'importctl',
+ 'public' : true,
+ 'conditions' : ['ENABLE_IMPORTD'],
+ 'sources' : files('importctl.c'),
+ },
test_template + {
'sources' : files(
'test-qcow2.c',
@@ -111,15 +121,13 @@ executables += [
},
]
-if conf.get('ENABLE_IMPORTD') == 1
- install_data('org.freedesktop.import1.conf',
- install_dir : dbuspolicydir)
- install_data('org.freedesktop.import1.service',
- install_dir : dbussystemservicedir)
- install_data('org.freedesktop.import1.policy',
- install_dir : polkitpolicydir)
+install_data('org.freedesktop.import1.conf',
+ install_dir : dbuspolicydir)
+install_data('org.freedesktop.import1.service',
+ install_dir : dbussystemservicedir)
+install_data('org.freedesktop.import1.policy',
+ install_dir : polkitpolicydir)
- install_data('import-pubring.gpg',
- install_dir : libexecdir)
- # TODO: shouldn't this be in pkgdatadir?
-endif
+install_data('import-pubring.gpg',
+ install_dir : libexecdir)
+# TODO: shouldn't this be in pkgdatadir?
diff --git a/src/import/org.freedesktop.import1.conf b/src/import/org.freedesktop.import1.conf
index d252ff6..f99ec56 100644
--- a/src/import/org.freedesktop.import1.conf
+++ b/src/import/org.freedesktop.import1.conf
@@ -44,6 +44,10 @@
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ListTransfersEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="CancelTransfer"/>
<allow send_destination="org.freedesktop.import1"
@@ -52,32 +56,64 @@
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ImportTarEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="ImportRaw"/>
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ImportRawEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="ImportFileSystem"/>
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ImportFileSystemEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="ExportTar"/>
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ExportTarEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="ExportRaw"/>
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="ExportRawEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="PullTar"/>
<allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Manager"
+ send_member="PullTarEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
send_member="PullRaw"/>
<allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Manager"
+ send_member="PullRawEx"/>
+
+ <allow send_destination="org.freedesktop.import1"
send_interface="org.freedesktop.import1.Transfer"
send_member="Cancel"/>
+ <allow send_destination="org.freedesktop.import1"
+ send_interface="org.freedesktop.import1.Transfer"
+ send_member="ListImages"/>
+
<allow receive_sender="org.freedesktop.import1"/>
</policy>
diff --git a/src/import/org.freedesktop.import1.policy b/src/import/org.freedesktop.import1.policy
index 88e436d..45c11de 100644
--- a/src/import/org.freedesktop.import1.policy
+++ b/src/import/org.freedesktop.import1.policy
@@ -19,8 +19,8 @@
<vendor_url>https://systemd.io</vendor_url>
<action id="org.freedesktop.import1.import">
- <description gettext-domain="systemd">Import a VM or container image</description>
- <message gettext-domain="systemd">Authentication is required to import a VM or container image</message>
+ <description gettext-domain="systemd">Import a disk image</description>
+ <message gettext-domain="systemd">Authentication is required to import an image</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
@@ -29,8 +29,8 @@
</action>
<action id="org.freedesktop.import1.export">
- <description gettext-domain="systemd">Export a VM or container image</description>
- <message gettext-domain="systemd">Authentication is required to export a VM or container image</message>
+ <description gettext-domain="systemd">Export a disk image</description>
+ <message gettext-domain="systemd">Authentication is required to export disk image</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
@@ -39,8 +39,18 @@
</action>
<action id="org.freedesktop.import1.pull">
- <description gettext-domain="systemd">Download a VM or container image</description>
- <message gettext-domain="systemd">Authentication is required to download a VM or container image</message>
+ <description gettext-domain="systemd">Download a disk image</description>
+ <message gettext-domain="systemd">Authentication is required to download a disk image</message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.import1.cancel">
+ <description gettext-domain="systemd">Cancel transfer of a disk image</description>
+ <message gettext-domain="systemd">Authentication is required to cancel the ongoing transfer of a disk image</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index 5e1ea20..9a2ced0 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -7,6 +7,7 @@
#include "capability-util.h"
#include "copy.h"
#include "dirent-util.h"
+#include "discover-image.h"
#include "escape.h"
#include "fd-util.h"
#include "hostname-util.h"
@@ -37,11 +38,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 +127,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;
@@ -550,7 +547,6 @@ int pull_verify(ImportVerify verify,
log_debug("Main download is a checksum file, can't validate its checksum with itself, skipping.");
verify_job = main_job;
} else {
- PullJob *j;
assert(main_job->calc_checksum);
assert(main_job->checksum);
assert(checksum_job);
@@ -560,7 +556,8 @@ int pull_verify(ImportVerify verify,
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
- FOREACH_POINTER(j, main_job, settings_job, roothash_job, roothash_signature_job, verity_job) {
+ PullJob *j;
+ FOREACH_ARGUMENT(j, main_job, settings_job, roothash_job, roothash_signature_job, verity_job) {
r = verify_one(checksum_job, j);
if (r < 0)
return r;
@@ -643,12 +640,12 @@ int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
return 1;
}
-bool pull_validate_local(const char *name, PullFlags flags) {
+bool pull_validate_local(const char *name, ImportFlags flags) {
- if (FLAGS_SET(flags, PULL_DIRECT))
+ if (FLAGS_SET(flags, IMPORT_DIRECT))
return path_is_valid(name);
- return hostname_is_valid(name, 0);
+ return image_name_is_valid(name);
}
int pull_url_needs_checksum(const char *url) {
diff --git a/src/import/pull-common.h b/src/import/pull-common.h
index 475613a..82e2526 100644
--- a/src/import/pull-common.h
+++ b/src/import/pull-common.h
@@ -3,27 +3,10 @@
#include <stdbool.h>
+#include "import-common.h"
#include "import-util.h"
#include "pull-job.h"
-typedef enum PullFlags {
- PULL_FORCE = 1 << 0, /* replace existing image */
- PULL_READ_ONLY = 1 << 1, /* make generated image read-only */
- PULL_SETTINGS = 1 << 2, /* download .nspawn settings file */
- PULL_ROOTHASH = 1 << 3, /* only for raw: download .roothash file for verity */
- PULL_ROOTHASH_SIGNATURE = 1 << 4, /* only for raw: download .roothash.p7s file for verity */
- PULL_VERITY = 1 << 5, /* only for raw: download .verity file for verity */
- PULL_BTRFS_SUBVOL = 1 << 6, /* tar: preferably create images as btrfs subvols */
- PULL_BTRFS_QUOTA = 1 << 7, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
- PULL_CONVERT_QCOW2 = 1 << 8, /* raw: if we detect a qcow2 image, unpack it */
- PULL_DIRECT = 1 << 9, /* download without rename games */
- PULL_SYNC = 1 << 10, /* fsync() right before we are done */
-
- /* The supported flags for the tar and the raw pulling */
- PULL_FLAGS_MASK_TAR = PULL_FORCE|PULL_READ_ONLY|PULL_SETTINGS|PULL_BTRFS_SUBVOL|PULL_BTRFS_QUOTA|PULL_DIRECT|PULL_SYNC,
- PULL_FLAGS_MASK_RAW = PULL_FORCE|PULL_READ_ONLY|PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY|PULL_CONVERT_QCOW2|PULL_DIRECT|PULL_SYNC,
-} PullFlags;
-
int pull_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags);
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
@@ -44,6 +27,6 @@ int verification_style_from_url(const char *url, VerificationStyle *style);
int pull_job_restart_with_sha256sum(PullJob *job, char **ret);
-bool pull_validate_local(const char *name, PullFlags flags);
+bool pull_validate_local(const char *name, ImportFlags flags);
int pull_url_needs_checksum(const char *url);
diff --git a/src/import/pull-job.c b/src/import/pull-job.c
index bed7e64..8482551 100644
--- a/src/import/pull-job.c
+++ b/src/import/pull-job.c
@@ -187,7 +187,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
}
}
- r = log_error_errno(
+ r = log_notice_errno(
status == 404 ? SYNTHETIC_ERRNO(ENOMEDIUM) : SYNTHETIC_ERRNO(EIO), /* Make the most common error recognizable */
"HTTP request to %s failed with code %li.", j->url, status);
goto finish;
@@ -431,7 +431,9 @@ static int pull_job_open_disk(PullJob *j) {
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to initialize hash context.");
#else
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load libgcrypt: %m");
if (gcry_md_open(&j->checksum_ctx, GCRY_MD_SHA256, 0) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index 66c3f65..f3e6b3a 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -42,7 +42,7 @@ struct RawPull {
sd_event *event;
CurlGlue *glue;
- PullFlags flags;
+ ImportFlags flags;
ImportVerify verify;
char *image_root;
@@ -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;
@@ -244,9 +245,9 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
assert(i);
assert(i->raw_job);
- assert(!FLAGS_SET(i->flags, PULL_DIRECT));
+ assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
- if (!FLAGS_SET(i->flags, PULL_CONVERT_QCOW2))
+ if (!FLAGS_SET(i->flags, IMPORT_CONVERT_QCOW2))
return 0;
assert(i->final_path);
@@ -310,7 +311,7 @@ static int raw_pull_copy_auxiliary_file(
const char *suffix,
char **path /* input + output (!) */) {
- const char *local;
+ _cleanup_free_ char *local = NULL;
int r;
assert(i);
@@ -321,21 +322,29 @@ static int raw_pull_copy_auxiliary_file(
if (r < 0)
return r;
- local = strjoina(i->image_root, "/", i->local, suffix);
+ local = strjoin(i->image_root, "/", i->local, suffix);
+ if (!local)
+ return log_oom();
- r = copy_file_atomic(
- *path,
- local,
- 0644,
- COPY_REFLINK |
- (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0) |
- (FLAGS_SET(i->flags, PULL_SYNC) ? COPY_FSYNC_FULL : 0));
+ if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD))
+ r = copy_file_atomic(
+ *path,
+ local,
+ 0644,
+ COPY_REFLINK |
+ (FLAGS_SET(i->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) |
+ (FLAGS_SET(i->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0));
+ else
+ r = install_file(AT_FDCWD, *path,
+ AT_FDCWD, local,
+ (i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
if (r == -EEXIST)
log_warning_errno(r, "File %s already exists, not replacing.", local);
else if (r == -ENOENT)
log_debug_errno(r, "Skipping creation of auxiliary file, since none was found.");
else if (r < 0)
- log_warning_errno(r, "Failed to copy file %s, ignoring: %m", local);
+ log_warning_errno(r, "Failed to install file %s, ignoring: %m", local);
else
log_info("Created new file %s.", local);
@@ -344,14 +353,12 @@ static int raw_pull_copy_auxiliary_file(
static int raw_pull_make_local_copy(RawPull *i) {
_cleanup_(unlink_and_freep) char *tp = NULL;
- _cleanup_free_ char *f = NULL;
- _cleanup_close_ int dfd = -EBADF;
- const char *p;
+ _cleanup_free_ char *p = NULL;
int r;
assert(i);
assert(i->raw_job);
- assert(!FLAGS_SET(i->flags, PULL_DIRECT));
+ assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
if (!i->local)
return 0;
@@ -374,62 +381,73 @@ static int raw_pull_make_local_copy(RawPull *i) {
return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
}
- p = strjoina(i->image_root, "/", i->local, ".raw");
-
- r = tempfn_random(p, NULL, &f);
- if (r < 0)
+ p = strjoin(i->image_root, "/", i->local, ".raw");
+ if (!p)
return log_oom();
- dfd = open(f, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
- if (dfd < 0)
- return log_error_errno(errno, "Failed to create writable copy of image: %m");
+ const char *source;
+ if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD)) {
+ _cleanup_close_ int dfd = -EBADF;
+ _cleanup_free_ char *f = NULL;
- tp = TAKE_PTR(f);
+ r = tempfn_random(p, NULL, &f);
+ if (r < 0)
+ return log_oom();
- /* Turn off COW writing. This should greatly improve performance on COW file systems like btrfs,
- * since it reduces fragmentation caused by not allowing in-place writes. */
- (void) import_set_nocow_and_log(dfd, tp);
+ dfd = open(f, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (dfd < 0)
+ return log_error_errno(errno, "Failed to create writable copy of image: %m");
- r = copy_bytes(i->raw_job->disk_fd, dfd, UINT64_MAX, COPY_REFLINK);
- if (r < 0)
- return log_error_errno(r, "Failed to make writable copy of image: %m");
+ tp = TAKE_PTR(f);
- (void) copy_times(i->raw_job->disk_fd, dfd, COPY_CRTIME);
- (void) copy_xattr(i->raw_job->disk_fd, NULL, dfd, NULL, 0);
+ /* Turn off COW writing. This should greatly improve performance on COW file systems like btrfs,
+ * since it reduces fragmentation caused by not allowing in-place writes. */
+ (void) import_set_nocow_and_log(dfd, tp);
- dfd = safe_close(dfd);
+ r = copy_bytes(i->raw_job->disk_fd, dfd, UINT64_MAX, COPY_REFLINK);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make writable copy of image: %m");
+
+ (void) copy_times(i->raw_job->disk_fd, dfd, COPY_CRTIME);
+ (void) copy_xattr(i->raw_job->disk_fd, NULL, dfd, NULL, 0);
+
+ dfd = safe_close(dfd);
+
+ source = tp;
+ } else
+ source = i->final_path;
- r = install_file(AT_FDCWD, tp,
+ r = install_file(AT_FDCWD, source,
AT_FDCWD, p,
- (i->flags & PULL_FORCE ? INSTALL_REPLACE : 0) |
- (i->flags & PULL_READ_ONLY ? INSTALL_READ_ONLY : 0) |
- (i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
+ (i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
+ (i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
if (r < 0)
- return log_error_errno(errno, "Failed to move local image into place '%s': %m", p);
+ return log_error_errno(r, "Failed to move local image into place '%s': %m", p);
tp = mfree(tp);
log_info("Created new local image '%s'.", i->local);
- if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
+ if (FLAGS_SET(i->flags, IMPORT_PULL_SETTINGS)) {
r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
if (r < 0)
return r;
}
- if (FLAGS_SET(i->flags, PULL_ROOTHASH)) {
+ if (FLAGS_SET(i->flags, IMPORT_PULL_ROOTHASH)) {
r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
if (r < 0)
return r;
}
- if (FLAGS_SET(i->flags, PULL_ROOTHASH_SIGNATURE)) {
+ if (FLAGS_SET(i->flags, IMPORT_PULL_ROOTHASH_SIGNATURE)) {
r = raw_pull_copy_auxiliary_file(i, ".roothash.p7s", &i->roothash_signature_path);
if (r < 0)
return r;
}
- if (FLAGS_SET(i->flags, PULL_VERITY)) {
+ if (FLAGS_SET(i->flags, IMPORT_PULL_VERITY)) {
r = raw_pull_copy_auxiliary_file(i, ".verity", &i->verity_path);
if (r < 0)
return r;
@@ -485,7 +503,7 @@ static int raw_pull_rename_auxiliary_file(
AT_FDCWD, *temp_path,
AT_FDCWD, *path,
INSTALL_READ_ONLY|
- (i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
+ (i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
if (r < 0)
return log_error_errno(r, "Failed to move '%s' into place: %m", *path);
@@ -495,7 +513,6 @@ static int raw_pull_rename_auxiliary_file(
static void raw_pull_job_on_finished(PullJob *j) {
RawPull *i;
- PullJob *jj;
int r;
assert(j);
@@ -568,8 +585,9 @@ static void raw_pull_job_on_finished(PullJob *j) {
}
}
+ PullJob *jj;
/* Let's close these auxiliary files now, we don't need access to them anymore. */
- FOREACH_POINTER(jj, i->settings_job, i->roothash_job, i->roothash_signature_job, i->verity_job)
+ FOREACH_ARGUMENT(jj, i->settings_job, i->roothash_job, i->roothash_signature_job, i->verity_job)
pull_job_close_disk_fd(jj);
if (!i->raw_job->etag_exists) {
@@ -588,7 +606,7 @@ static void raw_pull_job_on_finished(PullJob *j) {
goto finish;
}
- if (i->flags & PULL_DIRECT) {
+ if (i->flags & IMPORT_DIRECT) {
assert(!i->settings_job);
assert(!i->roothash_job);
assert(!i->roothash_signature_job);
@@ -599,8 +617,8 @@ static void raw_pull_job_on_finished(PullJob *j) {
if (i->local) {
r = install_file(AT_FDCWD, i->local,
AT_FDCWD, NULL,
- ((i->flags & PULL_READ_ONLY) && i->offset == UINT64_MAX ? INSTALL_READ_ONLY : 0) |
- (i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
+ ((i->flags & IMPORT_READ_ONLY) && i->offset == UINT64_MAX ? INSTALL_READ_ONLY : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
if (r < 0) {
log_error_errno(r, "Failed to finalize raw file to '%s': %m", i->local);
goto finish;
@@ -627,8 +645,8 @@ static void raw_pull_job_on_finished(PullJob *j) {
r = install_file(AT_FDCWD, i->temp_path,
AT_FDCWD, i->final_path,
- INSTALL_READ_ONLY|
- (i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
+ (i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
if (r < 0) {
log_error_errno(r, "Failed to move raw file to '%s': %m", i->final_path);
goto finish;
@@ -694,7 +712,7 @@ static int raw_pull_job_on_open_disk_generic(
assert(extra);
assert(temp_path);
- assert(!FLAGS_SET(i->flags, PULL_DIRECT));
+ assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
if (!*temp_path) {
r = tempfn_random_child(i->image_root, extra, temp_path);
@@ -722,7 +740,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
assert(i->raw_job == j);
assert(j->disk_fd < 0);
- if (i->flags & PULL_DIRECT) {
+ if (i->flags & IMPORT_DIRECT) {
if (!i->local) { /* If no local name specified, the pull job will write its data to stdout */
j->disk_fd = STDOUT_FILENO;
@@ -816,11 +834,10 @@ int raw_pull_start(
const char *local,
uint64_t offset,
uint64_t size_max,
- PullFlags flags,
+ ImportFlags flags,
ImportVerify verify,
const char *checksum) {
- PullJob *j;
int r;
assert(i);
@@ -828,10 +845,10 @@ int raw_pull_start(
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
- assert(!(flags & ~PULL_FLAGS_MASK_RAW));
- assert(offset == UINT64_MAX || FLAGS_SET(flags, PULL_DIRECT));
- assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !(flags & PULL_DIRECT));
- assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !checksum);
+ assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_RAW));
+ assert(offset == UINT64_MAX || FLAGS_SET(flags, IMPORT_DIRECT));
+ assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !(flags & IMPORT_DIRECT));
+ assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !checksum);
if (!http_url_is_valid(url) && !file_url_is_valid(url))
return -EINVAL;
@@ -881,7 +898,7 @@ int raw_pull_start(
if (offset != UINT64_MAX)
i->raw_job->offset = i->offset = offset;
- if (!FLAGS_SET(flags, PULL_DIRECT)) {
+ if (!FLAGS_SET(flags, IMPORT_DIRECT)) {
r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
if (r < 0)
return r;
@@ -899,7 +916,7 @@ int raw_pull_start(
if (r < 0)
return r;
- if (FLAGS_SET(flags, PULL_SETTINGS)) {
+ if (FLAGS_SET(flags, IMPORT_PULL_SETTINGS)) {
r = pull_make_auxiliary_job(
&i->settings_job,
url,
@@ -914,7 +931,7 @@ int raw_pull_start(
return r;
}
- if (FLAGS_SET(flags, PULL_ROOTHASH)) {
+ if (FLAGS_SET(flags, IMPORT_PULL_ROOTHASH)) {
r = pull_make_auxiliary_job(
&i->roothash_job,
url,
@@ -929,7 +946,7 @@ int raw_pull_start(
return r;
}
- if (FLAGS_SET(flags, PULL_ROOTHASH_SIGNATURE)) {
+ if (FLAGS_SET(flags, IMPORT_PULL_ROOTHASH_SIGNATURE)) {
r = pull_make_auxiliary_job(
&i->roothash_signature_job,
url,
@@ -944,7 +961,7 @@ int raw_pull_start(
return r;
}
- if (FLAGS_SET(flags, PULL_VERITY)) {
+ if (FLAGS_SET(flags, IMPORT_PULL_VERITY)) {
r = pull_make_auxiliary_job(
&i->verity_job,
url,
@@ -959,20 +976,21 @@ int raw_pull_start(
return r;
}
- FOREACH_POINTER(j,
- i->raw_job,
- i->checksum_job,
- i->signature_job,
- i->settings_job,
- i->roothash_job,
- i->roothash_signature_job,
- i->verity_job) {
+ PullJob *j;
+ FOREACH_ARGUMENT(j,
+ i->raw_job,
+ i->checksum_job,
+ i->signature_job,
+ i->settings_job,
+ i->roothash_job,
+ i->roothash_signature_job,
+ i->verity_job) {
if (!j)
continue;
j->on_progress = raw_pull_job_on_progress;
- j->sync = FLAGS_SET(flags, PULL_SYNC);
+ j->sync = FLAGS_SET(flags, IMPORT_SYNC);
r = pull_job_begin(j);
if (r < 0)
diff --git a/src/import/pull-raw.h b/src/import/pull-raw.h
index b39e4e2..e50ba32 100644
--- a/src/import/pull-raw.h
+++ b/src/import/pull-raw.h
@@ -16,4 +16,4 @@ RawPull* raw_pull_unref(RawPull *pull);
DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref);
-int raw_pull_start(RawPull *pull, const char *url, const char *local, uint64_t offset, uint64_t size_max, PullFlags flags, ImportVerify verify, const char *checksum);
+int raw_pull_start(RawPull *pull, const char *url, const char *local, uint64_t offset, uint64_t size_max, ImportFlags flags, ImportVerify verify, const char *checksum);
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index c32fc29..7fc71fe 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -41,7 +41,7 @@ struct TarPull {
sd_event *event;
CurlGlue *glue;
- PullFlags flags;
+ ImportFlags flags;
ImportVerify verify;
char *image_root;
@@ -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;
@@ -219,7 +220,8 @@ static int tar_pull_determine_path(
static int tar_pull_make_local_copy(TarPull *i) {
_cleanup_(rm_rf_subvolume_and_freep) char *t = NULL;
- const char *p;
+ _cleanup_free_ char *p = NULL;
+ const char *source;
int r;
assert(i);
@@ -230,30 +232,37 @@ static int tar_pull_make_local_copy(TarPull *i) {
assert(i->final_path);
- p = prefix_roota(i->image_root, i->local);
+ p = path_join(i->image_root, i->local);
+ if (!p)
+ return log_oom();
- r = tempfn_random(p, NULL, &t);
- if (r < 0)
- return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
-
- if (i->flags & PULL_BTRFS_SUBVOL)
- r = btrfs_subvol_snapshot_at(
- AT_FDCWD, i->final_path,
- AT_FDCWD, t,
- (i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
- BTRFS_SNAPSHOT_FALLBACK_COPY|
- BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
- BTRFS_SNAPSHOT_RECURSIVE);
- else
- r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to create local image: %m");
+ if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD)) {
+ r = tempfn_random(p, NULL, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
+
+ if (i->flags & IMPORT_BTRFS_SUBVOL)
+ r = btrfs_subvol_snapshot_at(
+ AT_FDCWD, i->final_path,
+ AT_FDCWD, t,
+ (i->flags & IMPORT_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
+ BTRFS_SNAPSHOT_FALLBACK_COPY|
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
+ BTRFS_SNAPSHOT_RECURSIVE);
+ else
+ r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create local image: %m");
- r = install_file(AT_FDCWD, t,
+ source = t;
+ } else
+ source = i->final_path;
+
+ r = install_file(AT_FDCWD, source,
AT_FDCWD, p,
- (i->flags & PULL_FORCE ? INSTALL_REPLACE : 0) |
- (i->flags & PULL_READ_ONLY ? INSTALL_READ_ONLY : 0) |
- (i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
+ (i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
+ (i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
if (r < 0)
return log_error_errno(r, "Failed to install local image '%s': %m", p);
@@ -261,29 +270,37 @@ static int tar_pull_make_local_copy(TarPull *i) {
log_info("Created new local image '%s'.", i->local);
- if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
- const char *local_settings;
+ if (FLAGS_SET(i->flags, IMPORT_PULL_SETTINGS)) {
+ _cleanup_free_ char *local_settings = NULL;
assert(i->settings_job);
r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
if (r < 0)
return r;
- local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
+ local_settings = strjoin(i->image_root, "/", i->local, ".nspawn");
+ if (!local_settings)
+ return log_oom();
- r = copy_file_atomic(
- i->settings_path,
- local_settings,
- 0664,
- COPY_REFLINK |
- (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0) |
- (FLAGS_SET(i->flags, PULL_SYNC) ? COPY_FSYNC_FULL : 0));
+ if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD))
+ r = copy_file_atomic(
+ i->settings_path,
+ local_settings,
+ 0664,
+ COPY_REFLINK |
+ (FLAGS_SET(i->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) |
+ (FLAGS_SET(i->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0));
+ else
+ r = install_file(AT_FDCWD, i->settings_path,
+ AT_FDCWD, local_settings,
+ (i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r == -ENOENT)
log_debug_errno(r, "Skipping creation of settings file, since none was found.");
else if (r < 0)
- log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
+ log_warning_errno(r, "Failed to install settings files %s, ignoring: %m", local_settings);
else
log_info("Created new settings file %s.", local_settings);
}
@@ -392,7 +409,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
goto finish;
}
- if (i->flags & PULL_DIRECT) {
+ if (i->flags & IMPORT_DIRECT) {
assert(!i->settings_job);
assert(i->local);
assert(!i->temp_path);
@@ -406,8 +423,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
r = install_file(
AT_FDCWD, i->local,
AT_FDCWD, NULL,
- (i->flags & PULL_READ_ONLY) ? INSTALL_READ_ONLY : 0 |
- (i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
+ (i->flags & IMPORT_READ_ONLY) ? INSTALL_READ_ONLY : 0 |
+ (i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
if (r < 0) {
log_error_errno(r, "Failed to finalize '%s': %m", i->local);
goto finish;
@@ -432,8 +449,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
r = install_file(
AT_FDCWD, i->temp_path,
AT_FDCWD, i->final_path,
- INSTALL_READ_ONLY|
- (i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
+ (i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY : 0) |
+ (i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
if (r < 0) {
log_error_errno(r, "Failed to rename to final image name to %s: %m", i->final_path);
goto finish;
@@ -460,7 +477,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
AT_FDCWD, i->settings_temp_path,
AT_FDCWD, i->settings_path,
INSTALL_READ_ONLY|
- (i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
+ (i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
if (r < 0) {
log_error_errno(r, "Failed to rename settings file to %s: %m", i->settings_path);
goto finish;
@@ -498,7 +515,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
assert(i->tar_job == j);
assert(i->tar_pid <= 0);
- if (i->flags & PULL_DIRECT)
+ if (i->flags & IMPORT_DIRECT)
where = i->local;
else {
if (!i->temp_path) {
@@ -512,20 +529,20 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
(void) mkdir_parents_label(where, 0700);
- if (FLAGS_SET(i->flags, PULL_DIRECT|PULL_FORCE))
+ if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
- if (i->flags & PULL_BTRFS_SUBVOL)
+ if (i->flags & IMPORT_BTRFS_SUBVOL)
r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
else
r = RET_NERRNO(mkdir(where, 0755));
- if (r == -EEXIST && (i->flags & PULL_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
+ if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
* because in that case our temporary path collided */
r = 0;
if (r < 0)
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", where);
- if (r > 0 && (i->flags & PULL_BTRFS_QUOTA)) { /* actually btrfs subvol */
- if (!(i->flags & PULL_DIRECT))
+ if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
+ if (!(i->flags & IMPORT_DIRECT))
(void) import_assign_pool_quota_and_warn(i->image_root);
(void) import_assign_pool_quota_and_warn(where);
}
@@ -577,20 +594,19 @@ int tar_pull_start(
TarPull *i,
const char *url,
const char *local,
- PullFlags flags,
+ ImportFlags flags,
ImportVerify verify,
const char *checksum) {
- PullJob *j;
int r;
assert(i);
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
- assert(!(flags & ~PULL_FLAGS_MASK_TAR));
- assert(!(flags & PULL_SETTINGS) || !(flags & PULL_DIRECT));
- assert(!(flags & PULL_SETTINGS) || !checksum);
+ assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_TAR));
+ assert(!(flags & IMPORT_PULL_SETTINGS) || !(flags & IMPORT_DIRECT));
+ assert(!(flags & IMPORT_PULL_SETTINGS) || !checksum);
if (!http_url_is_valid(url) && !file_url_is_valid(url))
return -EINVAL;
@@ -621,7 +637,7 @@ int tar_pull_start(
i->tar_job->on_open_disk = tar_pull_job_on_open_disk_tar;
i->tar_job->calc_checksum = checksum || IN_SET(verify, IMPORT_VERIFY_CHECKSUM, IMPORT_VERIFY_SIGNATURE);
- if (!FLAGS_SET(flags, PULL_DIRECT)) {
+ if (!FLAGS_SET(flags, IMPORT_DIRECT)) {
r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
if (r < 0)
return r;
@@ -641,7 +657,7 @@ int tar_pull_start(
return r;
/* Set up download job for the settings file (.nspawn) */
- if (FLAGS_SET(flags, PULL_SETTINGS)) {
+ if (FLAGS_SET(flags, IMPORT_PULL_SETTINGS)) {
r = pull_make_auxiliary_job(
&i->settings_job,
url,
@@ -656,17 +672,18 @@ int tar_pull_start(
return r;
}
- FOREACH_POINTER(j,
- i->tar_job,
- i->checksum_job,
- i->signature_job,
- i->settings_job) {
+ PullJob *j;
+ FOREACH_ARGUMENT(j,
+ i->tar_job,
+ i->checksum_job,
+ i->signature_job,
+ i->settings_job) {
if (!j)
continue;
j->on_progress = tar_pull_job_on_progress;
- j->sync = FLAGS_SET(flags, PULL_SYNC);
+ j->sync = FLAGS_SET(flags, IMPORT_SYNC);
r = pull_job_begin(j);
if (r < 0)
diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h
index e54c01c..1a5b740 100644
--- a/src/import/pull-tar.h
+++ b/src/import/pull-tar.h
@@ -16,4 +16,4 @@ TarPull* tar_pull_unref(TarPull *pull);
DEFINE_TRIVIAL_CLEANUP_FUNC(TarPull*, tar_pull_unref);
-int tar_pull_start(TarPull *pull, const char *url, const char *local, PullFlags flags, ImportVerify verify, const char *checksum);
+int tar_pull_start(TarPull *pull, const char *url, const char *local, ImportFlags flags, ImportVerify verify, const char *checksum);
diff --git a/src/import/pull.c b/src/import/pull.c
index 38821b5..7c838a5 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 PullFlags arg_pull_flags = PULL_SETTINGS | PULL_ROOTHASH | PULL_ROOTHASH_SIGNATURE | PULL_VERITY | PULL_BTRFS_SUBVOL | PULL_BTRFS_QUOTA | PULL_CONVERT_QCOW2 | PULL_SYNC;
+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);
@@ -38,7 +39,7 @@ static int normalize_local(const char *local, const char *url, char **ret) {
_cleanup_free_ char *ll = NULL;
int r;
- if (arg_pull_flags & PULL_DIRECT) {
+ if (arg_import_flags & IMPORT_DIRECT) {
if (!local)
log_debug("Writing downloaded data to STDOUT.");
@@ -58,13 +59,13 @@ static int normalize_local(const char *local, const char *url, char **ret) {
} else if (local) {
- if (!hostname_is_valid(local, 0))
+ if (!image_name_is_valid(local))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
- if (!FLAGS_SET(arg_pull_flags, PULL_FORCE)) {
- r = image_find(IMAGE_MACHINE, local, NULL, NULL);
+ if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
+ 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);
@@ -89,6 +90,12 @@ static int normalize_local(const char *local, const char *url, char **ret) {
} else
log_info("Pulling '%s'.", url);
+ if (!FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
+ log_info("Operating on image directory '%s'.", arg_image_root);
+
+ if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
+ log_info("File system synchronization on completion is off.");
+
*ret = TAKE_PTR(ll);
return 0;
}
@@ -130,7 +137,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
local = ll;
}
- if (!local && FLAGS_SET(arg_pull_flags, PULL_DIRECT))
+ if (!local && FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Pulling tar images to STDOUT is not supported.");
r = normalize_local(local, url, &normalized);
@@ -141,9 +148,6 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- if (!FLAGS_SET(arg_pull_flags, PULL_SYNC))
- log_info("File system synchronization on completion is off.");
-
r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate puller: %m");
@@ -152,7 +156,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
pull,
url,
normalized,
- arg_pull_flags & PULL_FLAGS_MASK_TAR,
+ arg_import_flags & IMPORT_PULL_FLAGS_MASK_TAR,
arg_verify,
arg_checksum);
if (r < 0)
@@ -211,9 +215,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- if (!FLAGS_SET(arg_pull_flags, PULL_SYNC))
- log_info("File system synchronization on completion is off.");
- r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
+ r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate puller: %m");
@@ -223,7 +225,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
normalized,
arg_offset,
arg_size_max,
- arg_pull_flags & PULL_FLAGS_MASK_RAW,
+ arg_import_flags & IMPORT_PULL_FLAGS_MASK_RAW,
arg_verify,
arg_checksum);
if (r < 0)
@@ -240,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"
@@ -255,7 +257,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --roothash-signature=BOOL\n"
" Download root hash signature file with image\n"
" --verity=BOOL Download verity file with image\n"
- " --image-root=PATH Image root directory\n\n"
+ " --image-root=PATH Image root directory\n"
" --read-only Create a read-only image\n"
" --direct Download directly to specified file\n"
" --btrfs-subvol=BOOL Controls whether to create a btrfs subvolume\n"
@@ -266,7 +268,11 @@ 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"
+ " --keep-download=BOOL Keep a copy pristine copy of the downloaded file\n"
+ " around\n",
program_invocation_short_name,
ansi_underline(),
ansi_normal(),
@@ -295,6 +301,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SYNC,
ARG_OFFSET,
ARG_SIZE_MAX,
+ ARG_CLASS,
+ ARG_KEEP_DOWNLOAD,
};
static const struct option options[] = {
@@ -315,10 +323,13 @@ 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 },
+ { "keep-download", required_argument, NULL, ARG_KEEP_DOWNLOAD },
{}
};
int c, r;
+ bool auto_settings = true, auto_keep_download = true;
assert(argc >= 0);
assert(argv);
@@ -334,7 +345,7 @@ static int parse_argv(int argc, char *argv[]) {
return version();
case ARG_FORCE:
- arg_pull_flags |= PULL_FORCE;
+ arg_import_flags |= IMPORT_FORCE;
break;
case ARG_IMAGE_ROOT:
@@ -353,7 +364,7 @@ static int parse_argv(int argc, char *argv[]) {
/* If this is not a valid verification mode, maybe it's a literally specified
* SHA256 hash? We can handle that too... */
- r = unhexmem(optarg, (size_t) -1, &h, &n);
+ r = unhexmem(optarg, &h, &n);
if (r < 0 || n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid verification setting: %s", optarg);
@@ -366,7 +377,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_oom();
free_and_replace(arg_checksum, hh);
- arg_pull_flags &= ~(PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY);
+ arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
arg_verify = _IMPORT_VERIFY_INVALID;
} else
arg_verify = v;
@@ -379,7 +390,8 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_SETTINGS, r);
+ SET_FLAG(arg_import_flags, IMPORT_PULL_SETTINGS, r);
+ auto_settings = false;
break;
case ARG_ROOTHASH:
@@ -387,11 +399,11 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_ROOTHASH, r);
+ SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH, r);
/* If we were asked to turn off the root hash, implicitly also turn off the root hash signature */
if (!r)
- SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, false);
+ SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, false);
break;
case ARG_ROOTHASH_SIGNATURE:
@@ -399,7 +411,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, r);
+ SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, r);
break;
case ARG_VERITY:
@@ -407,16 +419,16 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_VERITY, r);
+ SET_FLAG(arg_import_flags, IMPORT_PULL_VERITY, r);
break;
case ARG_READ_ONLY:
- arg_pull_flags |= PULL_READ_ONLY;
+ arg_import_flags |= IMPORT_READ_ONLY;
break;
case ARG_DIRECT:
- arg_pull_flags |= PULL_DIRECT;
- arg_pull_flags &= ~(PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY);
+ arg_import_flags |= IMPORT_DIRECT;
+ arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
break;
case ARG_BTRFS_SUBVOL:
@@ -424,7 +436,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_BTRFS_SUBVOL, r);
+ SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
break;
case ARG_BTRFS_QUOTA:
@@ -432,7 +444,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_BTRFS_QUOTA, r);
+ SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
break;
case ARG_CONVERT_QCOW2:
@@ -440,7 +452,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_CONVERT_QCOW2, r);
+ SET_FLAG(arg_import_flags, IMPORT_CONVERT_QCOW2, r);
break;
case ARG_SYNC:
@@ -448,7 +460,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
- SET_FLAG(arg_pull_flags, PULL_SYNC, r);
+ SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
break;
case ARG_OFFSET: {
@@ -477,6 +489,22 @@ 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 ARG_KEEP_DOWNLOAD:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --keep-download= argument: %s", optarg);
+
+ SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, r);
+ auto_keep_download = false;
+ break;
+
case '?':
return -EINVAL;
@@ -490,12 +518,24 @@ static int parse_argv(int argc, char *argv[]) {
!FILE_SIZE_VALID(arg_offset + arg_size_max)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset und maximum size out of range.");
- if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_pull_flags, PULL_DIRECT))
+ 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_checksum && (arg_pull_flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) != 0)
+ 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;
+
+ /* Keep the original pristine downloaded file as a copy only when dealing with machine images,
+ * because unlike sysext/confext/portable they are typically modified during runtime. */
+ if (auto_keep_download)
+ SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_class == IMAGE_MACHINE);
+
return 1;
}
@@ -507,19 +547,19 @@ static void parse_env(void) {
r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL");
if (r >= 0)
- SET_FLAG(arg_pull_flags, PULL_BTRFS_SUBVOL, r);
+ SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
else if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_SUBVOL: %m");
r = getenv_bool("SYSTEMD_IMPORT_BTRFS_QUOTA");
if (r >= 0)
- SET_FLAG(arg_pull_flags, PULL_BTRFS_QUOTA, r);
+ SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
else if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
r = getenv_bool("SYSTEMD_IMPORT_SYNC");
if (r >= 0)
- SET_FLAG(arg_pull_flags, PULL_SYNC, r);
+ SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
else if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_SYNC: %m");
}
@@ -539,8 +579,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
- log_open();
+ log_setup();
parse_env();
diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c
index c70656b..fc34f30 100644
--- a/src/import/qcow2-util.c
+++ b/src/import/qcow2-util.c
@@ -273,7 +273,7 @@ int qcow2_convert(int qcow2_fd, int raw_fd) {
if ((uint64_t) l != sz)
return -EIO;
- for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
+ for (i = 0; i < HEADER_L1_SIZE(&header); i++) {
uint64_t l2_begin, j;
r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);