diff options
Diffstat (limited to 'src/import/importd.c')
-rw-r--r-- | src/import/importd.c | 228 |
1 files changed, 171 insertions, 57 deletions
diff --git a/src/import/importd.c b/src/import/importd.c index 04563fb098..2426933558 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -10,9 +10,11 @@ #include "bus-util.h" #include "def.h" #include "fd-util.h" +#include "float.h" #include "hostname-util.h" #include "import-util.h" #include "machine-pool.h" +#include "main-func.h" #include "missing.h" #include "mkdir.h" #include "parse-util.h" @@ -20,6 +22,7 @@ #include "process-util.h" #include "signal-util.h" #include "socket-util.h" +#include "stat-util.h" #include "string-table.h" #include "strv.h" #include "syslog-util.h" @@ -33,6 +36,7 @@ typedef struct Manager Manager; typedef enum TransferType { TRANSFER_IMPORT_TAR, TRANSFER_IMPORT_RAW, + TRANSFER_IMPORT_FS, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW, TRANSFER_PULL_TAR, @@ -93,6 +97,7 @@ 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_EXPORT_TAR] = "export-tar", [TRANSFER_EXPORT_RAW] = "export-raw", [TRANSFER_PULL_TAR] = "pull-tar", @@ -145,15 +150,18 @@ static int transfer_new(Manager *m, Transfer **ret) { if (r < 0) return r; - t = new0(Transfer, 1); + t = new(Transfer, 1); if (!t) return -ENOMEM; - t->type = _TRANSFER_TYPE_INVALID; - t->log_fd = -1; - t->stdin_fd = -1; - t->stdout_fd = -1; - t->verify = _IMPORT_VERIFY_INVALID; + *t = (Transfer) { + .type = _TRANSFER_TYPE_INVALID, + .log_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .verify = _IMPORT_VERIFY_INVALID, + .progress_percent= (unsigned) -1, + }; id = m->current_transfer_id + 1; @@ -174,6 +182,15 @@ static int transfer_new(Manager *m, Transfer **ret) { return 0; } +static double transfer_percent_as_double(Transfer *t) { + assert(t); + + if (t->progress_percent == (unsigned) -1) + return -DBL_MAX; + + return (double) t->progress_percent / 100.0; +} + static void transfer_send_log_line(Transfer *t, const char *line) { int r, priority = LOG_INFO; @@ -193,7 +210,7 @@ static void transfer_send_log_line(Transfer *t, const char *line) { priority, line); if (r < 0) - log_error_errno(r, "Cannot emit message: %m"); + log_warning_errno(r, "Cannot emit log message signal, ignoring: %m"); } static void transfer_send_logs(Transfer *t, bool flush) { @@ -298,17 +315,16 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda if (si->si_code == CLD_EXITED) { if (si->si_status != 0) - log_error("Import process failed with exit code %i.", si->si_status); + log_error("Transfer process failed with exit code %i.", si->si_status); else { - log_debug("Import process succeeded."); + log_debug("Transfer process succeeded."); success = true; } } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED)) - - log_error("Import process terminated by signal %s.", signal_to_string(si->si_status)); + log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status)); else - log_error("Import process failed due to unknown reason."); + log_error("Transfer process failed due to unknown reason."); t->pid = 0; @@ -323,14 +339,12 @@ static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *u assert(t); l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size); + if (l < 0) + log_error_errno(errno, "Failed to read log message: %m"); if (l <= 0) { /* EOF/read error. We just close the pipe here, and * close the watch, waiting for the SIGCHLD to arrive, * before we do anything else. */ - - if (l < 0) - log_error_errno(errno, "Failed to read log message: %m"); - t->log_event_source = sd_event_source_unref(t->log_event_source); return 0; } @@ -357,7 +371,7 @@ static int transfer_start(Transfer *t) { return r; if (r == 0) { const char *cmd[] = { - NULL, /* systemd-import, systemd-export or systemd-pull */ + NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */ NULL, /* tar, raw */ NULL, /* --verify= */ NULL, /* verify argument */ @@ -390,17 +404,52 @@ static int transfer_start(Transfer *t) { _exit(EXIT_FAILURE); } - if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_IMPORT_RAW)) + switch (t->type) { + + case TRANSFER_IMPORT_TAR: + case TRANSFER_IMPORT_RAW: cmd[k++] = SYSTEMD_IMPORT_PATH; - else if (IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) + break; + + case TRANSFER_IMPORT_FS: + cmd[k++] = SYSTEMD_IMPORT_FS_PATH; + break; + + case TRANSFER_EXPORT_TAR: + case TRANSFER_EXPORT_RAW: cmd[k++] = SYSTEMD_EXPORT_PATH; - else + break; + + case TRANSFER_PULL_TAR: + case TRANSFER_PULL_RAW: cmd[k++] = SYSTEMD_PULL_PATH; + break; - if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_EXPORT_TAR, TRANSFER_PULL_TAR)) + default: + assert_not_reached("Unexpected transfer type"); + } + + switch (t->type) { + + case TRANSFER_IMPORT_TAR: + case TRANSFER_EXPORT_TAR: + case TRANSFER_PULL_TAR: cmd[k++] = "tar"; - else + break; + + case TRANSFER_IMPORT_RAW: + case TRANSFER_EXPORT_RAW: + case TRANSFER_PULL_RAW: cmd[k++] = "raw"; + break; + + case TRANSFER_IMPORT_FS: + cmd[k++] = "run"; + break; + + default: + break; + } if (t->verify != _IMPORT_VERIFY_INVALID) { cmd[k++] = "--verify"; @@ -510,7 +559,6 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void struct ucred *ucred = NULL; Manager *m = userdata; struct cmsghdr *cmsg; - unsigned percent; char *p, *e; Transfer *t; Iterator i; @@ -566,15 +614,15 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void e = strchrnul(p, '\n'); *e = 0; - r = safe_atou(p, &percent); - if (r < 0 || percent > 100) { + r = parse_percent(p); + if (r < 0) { log_warning("Got invalid percent value, ignoring."); return 0; } - t->progress_percent = percent; + t->progress_percent = (unsigned) r; - log_debug("Got percentage from client: %u%%", percent); + log_debug("Got percentage from client: %u%%", t->progress_percent); return 0; } @@ -584,7 +632,6 @@ static int manager_new(Manager **ret) { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/import/notify", }; - static const int one = 1; int r; assert(ret); @@ -608,13 +655,14 @@ static int manager_new(Manager **ret) { return -errno; (void) mkdir_parents_label(sa.un.sun_path, 0755); - (void) unlink(sa.un.sun_path); + (void) sockaddr_un_unlink(&sa.un); if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return -errno; - if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) - return -errno; + r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true); + if (r < 0) + return r; r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m); if (r < 0) @@ -633,12 +681,9 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *remote) assert(type >= 0); assert(type < _TRANSFER_TYPE_MAX); - HASHMAP_FOREACH(t, m->transfers, i) { - - if (t->type == type && - streq_ptr(t->remote, remote)) + HASHMAP_FOREACH(t, m->transfers, i) + if (t->type == type && streq_ptr(t->remote, remote)) return t; - } return NULL; } @@ -672,10 +717,14 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r < 0) return r; + r = fd_verify_regular(fd); + if (r < 0) + return r; + if (!machine_name_is_valid(local)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - r = setup_machine_directory((uint64_t) -1, error); + r = setup_machine_directory(error); if (r < 0) return r; @@ -708,6 +757,72 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ return sd_bus_reply_method_return(msg, "uo", id, object); } +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; + Manager *m = userdata; + uint32_t id; + + assert(msg); + assert(m); + + r = bus_verify_polkit_async( + msg, + CAP_SYS_ADMIN, + "org.freedesktop.import1.import", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); + if (r < 0) + return r; + + r = fd_verify_directory(fd); + if (r < 0) + return r; + + if (!machine_name_is_valid(local)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); + + r = setup_machine_directory(error); + 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->local = strdup(local); + if (!t->local) + return -ENOMEM; + + t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (t->stdin_fd < 0) + return -errno; + + r = transfer_start(t); + if (r < 0) + return r; + + object = t->object_path; + id = t->id; + t = NULL; + + return sd_bus_reply_method_return(msg, "uo", id, object); +} + 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; @@ -740,6 +855,10 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (!machine_name_is_valid(local)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); + r = fd_verify_regular(fd); + if (r < 0) + return r; + type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW; r = transfer_new(m, &t); @@ -818,7 +937,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (v < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); - r = setup_machine_directory((uint64_t) -1, error); + r = setup_machine_directory(error); if (r < 0) return r; @@ -883,7 +1002,7 @@ static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_err transfer_type_to_string(t->type), t->remote, t->local, - (double) t->progress_percent / 100.0, + transfer_percent_as_double(t), t->object_path); if (r < 0) return r; @@ -979,7 +1098,7 @@ static int property_get_progress( assert(reply); assert(t); - return sd_bus_message_append(reply, "d", (double) t->progress_percent / 100.0); + return sd_bus_message_append(reply, "d", transfer_percent_as_double(t)); } static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType); @@ -1002,6 +1121,7 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ImportFileSystem", "hsbb", "uo", method_import_fs, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), @@ -1113,40 +1233,34 @@ static int manager_run(Manager *m) { m); } -int main(int argc, char *argv[]) { +static int run(int argc, char *argv[]) { _cleanup_(manager_unrefp) Manager *m = NULL; int r; - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); + log_setup_service(); umask(0022); if (argc != 1) { log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; + return -EINVAL; } assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); r = manager_new(&m); - if (r < 0) { - log_error_errno(r, "Failed to allocate manager object: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to allocate manager object: %m"); r = manager_add_bus_objects(m); if (r < 0) - goto finish; + return r; r = manager_run(m); - if (r < 0) { - log_error_errno(r, "Failed to run event loop: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to run event loop: %m"); -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return 0; } + +DEFINE_MAIN_FUNCTION(run); |