static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_force = false;
-static const char* arg_verify = NULL;
+static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
static const char* arg_dkr_index_url = NULL;
static void pager_open_if_enabled(void) {
return -EINVAL;
}
- p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/");
+ p = strjoina("/run/systemd/nspawn/propagate/", argv[1], "/");
if (access(p, F_OK) < 0) {
log_error("Container does not allow propagation of mount points.");
return -ENOTSUP;
/* Second, we mount the source directory to a directory inside
of our MS_SLAVE playground. */
- mount_tmp = strappenda(mount_slave, "/mount");
+ mount_tmp = strjoina(mount_slave, "/mount");
if (mkdir(mount_tmp, 0700) < 0) {
r = log_error_errno(errno, "Failed to create temporary mount: %m");
goto finish;
* directory. This way it will appear there read-only
* right-away. */
- mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
+ mount_outside = strjoina("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
if (!mkdtemp(mount_outside)) {
r = log_error_errno(errno, "Cannot create propagation directory: %m");
goto finish;
mkdir_p(dest, 0755);
/* Fifth, move the mount to the right place inside */
- mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside));
+ mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
log_error_errno(errno, "Failed to mount: %m");
_exit(EXIT_FAILURE);
int master = -1, r, ret = 0;
sd_bus *bus = userdata;
const char *pty, *match;
- sigset_t mask;
char last_char = 0;
bool machine_died;
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- match = strappenda("type='signal',"
+ match = strjoina("type='signal',"
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
if (r < 0)
return bus_log_parse_error(r);
- assert_se(sigemptyset(&mask) == 0);
- sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
- assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
+ sigprocmask_many(SIG_BLOCK, SIGWINCH, SIGTERM, SIGINT, -1);
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
return 0;
}
-typedef struct PullContext {
- const char *path;
- int result;
-} PullContext;
-
static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- PullContext *c = userdata;
- const char *line;
+ const char **our_path = userdata, *line;
unsigned priority;
int r;
assert(bus);
assert(m);
+ assert(our_path);
r = sd_bus_message_read(m, "us", &priority, &line);
if (r < 0) {
return 0;
}
- if (!streq_ptr(c->path, sd_bus_message_get_path(m)))
+ if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
return 0;
if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
}
static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- PullContext *c = userdata;
- const char *path, *result;
+ const char **our_path = userdata, *path, *result;
uint32_t id;
int r;
assert(bus);
assert(m);
- assert(c);
+ assert(our_path);
r = sd_bus_message_read(m, "uos", &id, &path, &result);
if (r < 0) {
return 0;
}
- if (!streq_ptr(c->path, path))
+ if (!streq_ptr(*our_path, path))
return 0;
- c->result = streq_ptr(result, "done");
+ sd_event_exit(sd_bus_get_event(bus), !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)
+ log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
+
+ sd_event_exit(sd_event_source_get_event(s), EINTR);
return 0;
}
_cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- PullContext c = {
- .result = -1,
- };
+ _cleanup_event_unref_ sd_event* event = NULL;
+ const char *path = NULL;
uint32_t id;
int r;
polkit_agent_open_if_enabled();
+ 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 = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
if (r < 0)
return bus_log_create_error(r);
"interface='org.freedesktop.import1.Manager',"
"member='TransferRemoved',"
"path='/org/freedesktop/import1'",
- match_transfer_removed, &c);
+ match_transfer_removed, &path);
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
"sender='org.freedesktop.import1',"
"interface='org.freedesktop.import1.Transfer',"
"member='LogMessage'",
- match_log_message, &c);
+ match_log_message, &path);
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
return r;
}
- r = sd_bus_message_read(reply, "uo", &id, &c.path);
+ r = sd_bus_message_read(reply, "uo", &id, &path);
if (r < 0)
return bus_log_parse_error(r);
- for (;;) {
- r = sd_bus_process(bus, NULL);
- if (r < 0)
- return r;
+ sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
- /* The match sets this to NULL when we are done */
- if (c.result >= 0)
- break;
+ if (!arg_quiet)
+ log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0)
- return r;
- }
+ sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
+ sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
- return c.result ? 0 : -EINVAL;
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ return -r;
}
static int pull_tar(int argc, char *argv[], void *userdata) {
"sssb",
remote,
local,
- arg_verify,
+ import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
"sssb",
remote,
local,
- arg_verify,
+ import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
static int pull_dkr(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *l = NULL, *ll = NULL;
const char *local, *remote, *tag;
sd_bus *bus = userdata;
int r;
- if (!streq_ptr(arg_dkr_index_url, "no")) {
+ if (arg_verify != IMPORT_VERIFY_NO) {
log_error("Imports from DKR do not support image verification, please pass --verify=no.");
return -EINVAL;
}
remote,
tag,
local,
- arg_verify,
+ import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
const char *type;
const char *remote;
const char *local;
+ double progress;
} TransferInfo;
static int compare_transfer_info(const void *a, const void *b) {
const char *type, *remote, *local, *object;
sd_bus *bus = userdata;
uint32_t id, max_id = 0;
+ double progress;
int r;
pager_open_if_enabled();
return r;
}
- r = sd_bus_message_enter_container(reply, 'a', "(ussso)");
+ r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(reply, "(ussso)", &id, &type, &remote, &local, &object)) > 0) {
+ while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
size_t l;
if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
transfers[n_transfers].type = type;
transfers[n_transfers].remote = remote;
transfers[n_transfers].local = local;
+ transfers[n_transfers].progress = progress;
l = strlen(type);
if (l > max_type)
qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
if (arg_legend)
- printf("%-*s %-*s %-*s %-*s\n",
+ printf("%-*s %-*s %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
+ (int) 7, "PERCENT",
(int) max_type, "TYPE",
(int) max_local, "LOCAL",
(int) max_remote, "REMOTE");
for (j = 0; j < n_transfers; j++)
- printf("%*" PRIu32 " %-*s %-*s %-*s\n",
+ printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
+ (int) 6, (unsigned) (transfers[j].progress * 100),
(int) max_type, transfers[j].type,
(int) max_local, transfers[j].local,
(int) max_remote, transfers[j].remote);
" -o --output=STRING Change journal output mode (short,\n"
" short-monotonic, verbose, export, json,\n"
" json-pretty, json-sse, cat)\n"
- " --verify=MODE Verification mode for downloaded images (no, sum,\n"
- " signature)\n"
+ " --verify=MODE Verification mode for downloaded images (no,\n"
+ " checksum, signature)\n"
" --force Download image even if already exists\n"
" --dkr-index-url=URL Specify the index URL to use for DKR image\n"
" downloads\n\n"
" copy-from NAME PATH [PATH] Copy files from a container to the host\n"
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
"Image Commands:\n"
- " list-images Show available images\n"
+ " list-images Show available container and VM images\n"
" image-status NAME... Show image details\n"
" show-image NAME... Show properties of image\n"
" clone NAME NAME Clone an image\n"
" rename NAME NAME Rename an image\n"
" read-only NAME [BOOL] Mark or unmark image read-only\n"
" remove NAME... Remove an image\n\n"
- "Transfer Commands:\n"
- " pull-tar URL [NAME] Download a TAR image\n"
- " pull-raw URL [NAME] Download a RAW image\n"
- " pull-dkr REMOTE [NAME] Download a DKR image\n"
- " list-transfers Show list of current downloads\n"
+ "Image Transfer Commands:\n"
+ " pull-tar URL [NAME] Download a TAR container image\n"
+ " pull-raw URL [NAME] Download a RAW container or VM image\n"
+ " pull-dkr REMOTE [NAME] Download a DKR container image\n"
+ " list-transfers Show list of downloads in progress\n"
" cancel-transfer Cancel a download\n"
, program_invocation_short_name);
break;
case ARG_VERIFY:
- arg_verify = optarg;
+ arg_verify = import_verify_from_string(optarg);
+ if (arg_verify < 0) {
+ log_error("Failed to parse --verify= setting: %s", optarg);
+ return -EINVAL;
+ }
break;
case ARG_FORCE: