]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/import/importd.c
tree-wide: introduce PIPE_EBADF macro
[thirdparty/systemd.git] / src / import / importd.c
index 15914cc8853b5afd9e1f4eab3f9b3c94a445c541..65647a66a6342e0ea1ab599fcf09cc78b403058e 100644 (file)
@@ -10,7 +10,8 @@
 #include "bus-get-properties.h"
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
-#include "def.h"
+#include "constants.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "float.h"
 #include "hostname-util.h"
 #include "machine-pool.h"
 #include "main-func.h"
 #include "missing_capability.h"
-#include "mkdir.h"
+#include "mkdir-label.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "percent-util.h"
 #include "process-util.h"
 #include "service-util.h"
 #include "signal-util.h"
@@ -30,7 +32,6 @@
 #include "strv.h"
 #include "syslog-util.h"
 #include "user-util.h"
-#include "util.h"
 #include "web-util.h"
 
 typedef struct Transfer Transfer;
@@ -45,7 +46,7 @@ typedef enum TransferType {
         TRANSFER_PULL_TAR,
         TRANSFER_PULL_RAW,
         _TRANSFER_TYPE_MAX,
-        _TRANSFER_TYPE_INVALID = -1,
+        _TRANSFER_TYPE_INVALID = -EINVAL,
 } TransferType;
 
 struct Transfer {
@@ -93,6 +94,9 @@ struct Manager {
         int notify_fd;
 
         sd_event_source *notify_event_source;
+
+        bool use_btrfs_subvol;
+        bool use_btrfs_quota;
 };
 
 #define TRANSFERS_MAX 64
@@ -124,10 +128,8 @@ static Transfer *transfer_unref(Transfer *t) {
         free(t->format);
         free(t->object_path);
 
-        if (t->pid > 0) {
-                (void) kill_and_sigcont(t->pid, SIGKILL);
-                (void) wait_for_terminate(t->pid, NULL);
-        }
+        if (t->pid > 1)
+                sigkill_wait(t->pid);
 
         safe_close(t->log_fd);
         safe_close(t->stdin_fd);
@@ -155,11 +157,11 @@ static int transfer_new(Manager *m, Transfer **ret) {
 
         *t = (Transfer) {
                 .type = _TRANSFER_TYPE_INVALID,
-                .log_fd = -1,
-                .stdin_fd = -1,
-                .stdout_fd = -1,
+                .log_fd = -EBADF,
+                .stdin_fd = -EBADF,
+                .stdout_fd = -EBADF,
                 .verify = _IMPORT_VERIFY_INVALID,
-                .progress_percent= (unsigned) -1,
+                .progress_percent= UINT_MAX,
         };
 
         id = m->current_transfer_id + 1;
@@ -184,7 +186,7 @@ static int transfer_new(Manager *m, Transfer **ret) {
 static double transfer_percent_as_double(Transfer *t) {
         assert(t);
 
-        if (t->progress_percent == (unsigned) -1)
+        if (t->progress_percent == UINT_MAX)
                 return -DBL_MAX;
 
         return (double) t->progress_percent / 100.0;
@@ -306,11 +308,10 @@ static int transfer_cancel(Transfer *t) {
 }
 
 static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
-        Transfer *t = userdata;
+        Transfer *t = ASSERT_PTR(userdata);
         bool success = false;
 
         assert(s);
-        assert(t);
 
         if (si->si_code == CLD_EXITED) {
                 if (si->si_status != 0)
@@ -331,11 +332,10 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda
 }
 
 static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        Transfer *t = userdata;
+        Transfer *t = ASSERT_PTR(userdata);
         ssize_t l;
 
         assert(s);
-        assert(t);
 
         l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
         if (l < 0)
@@ -356,7 +356,7 @@ static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *u
 }
 
 static int transfer_start(Transfer *t) {
-        _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+        _cleanup_close_pair_ int pipefd[2] = PIPE_EBADF;
         int r;
 
         assert(t);
@@ -389,9 +389,10 @@ static int transfer_start(Transfer *t) {
 
                 pipefd[0] = safe_close(pipefd[0]);
 
-                r = rearrange_stdio(t->stdin_fd,
-                                    t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd,
+                r = rearrange_stdio(TAKE_FD(t->stdin_fd),
+                                    t->stdout_fd < 0 ? pipefd[1] : TAKE_FD(t->stdout_fd),
                                     pipefd[1]);
+                TAKE_FD(pipefd[1]);
                 if (r < 0) {
                         log_error_errno(r, "Failed to set stdin/stdout/stderr: %m");
                         _exit(EXIT_FAILURE);
@@ -403,6 +404,10 @@ static int transfer_start(Transfer *t) {
                         _exit(EXIT_FAILURE);
                 }
 
+                r = setenv_systemd_exec_pid(true);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
+
                 switch (t->type) {
 
                 case TRANSFER_IMPORT_TAR:
@@ -425,7 +430,7 @@ static int transfer_start(Transfer *t) {
                         break;
 
                 default:
-                        assert_not_reached("Unexpected transfer type");
+                        assert_not_reached();
                 }
 
                 switch (t->type) {
@@ -562,10 +567,11 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
         int r;
 
         n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-        if (IN_SET(n, -EAGAIN, -EINTR))
-                return 0;
-        if (n < 0)
+        if (n < 0) {
+                if (ERRNO_IS_TRANSIENT(n))
+                        return 0;
                 return (int) n;
+        }
 
         cmsg_close_all(&msghdr);
 
@@ -625,10 +631,15 @@ static int manager_new(Manager **ret) {
 
         assert(ret);
 
-        m = new0(Manager, 1);
+        m = new(Manager, 1);
         if (!m)
                 return -ENOMEM;
 
+        *m = (Manager) {
+                .use_btrfs_subvol = true,
+                .use_btrfs_quota = true,
+        };
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -681,13 +692,12 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         int fd, force, read_only, r;
         const char *local, *object;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         TransferType type;
         struct stat st;
         uint32_t id;
 
         assert(msg);
-        assert(m);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -717,7 +727,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                          "Local name %s is invalid", local);
 
-        r = setup_machine_directory(error);
+        r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
         if (r < 0)
                 return r;
 
@@ -755,11 +765,10 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         int fd, force, read_only, r;
         const char *local, *object;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         uint32_t id;
 
         assert(msg);
-        assert(m);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -787,7 +796,7 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                          "Local name %s is invalid", local);
 
-        r = setup_machine_directory(error);
+        r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
         if (r < 0)
                 return r;
 
@@ -822,13 +831,12 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         int fd, r;
         const char *local, *object, *format;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         TransferType type;
         struct stat st;
         uint32_t id;
 
         assert(msg);
-        assert(m);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -895,14 +903,13 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
 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;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         ImportVerify v;
         TransferType type;
         int force, r;
         uint32_t id;
 
         assert(msg);
-        assert(m);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -922,7 +929,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
         if (r < 0)
                 return r;
 
-        if (!http_url_is_valid(remote))
+        if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                          "URL %s is invalid", remote);
 
@@ -940,7 +947,7 @@ 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);
+        r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
         if (r < 0)
                 return r;
 
@@ -982,12 +989,11 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
 
 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 = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         Transfer *t;
         int r;
 
         assert(msg);
-        assert(m);
 
         r = sd_bus_message_new_method_return(msg, &reply);
         if (r < 0)
@@ -1020,11 +1026,10 @@ static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_err
 }
 
 static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
-        Transfer *t = userdata;
+        Transfer *t = ASSERT_PTR(userdata);
         int r;
 
         assert(msg);
-        assert(t);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -1048,13 +1053,12 @@ static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *erro
 }
 
 static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         Transfer *t;
         uint32_t id;
         int r;
 
         assert(msg);
-        assert(m);
 
         r = bus_verify_polkit_async(
                         msg,
@@ -1074,7 +1078,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
         if (r < 0)
                 return r;
         if (id <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
 
         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
         if (!t)
@@ -1096,11 +1100,10 @@ static int property_get_progress(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Transfer *t = userdata;
+        Transfer *t = ASSERT_PTR(userdata);
 
         assert(bus);
         assert(reply);
-        assert(t);
 
         return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
 }
@@ -1116,7 +1119,7 @@ static int transfer_object_find(
                 void **found,
                 sd_bus_error *error) {
 
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         Transfer *t;
         const char *p;
         uint32_t id;
@@ -1126,7 +1129,6 @@ static int transfer_object_find(
         assert(path);
         assert(interface);
         assert(found);
-        assert(m);
 
         p = startswith(path, "/org/freedesktop/import1/transfer/_");
         if (!p)
@@ -1357,11 +1359,33 @@ static int manager_run(Manager *m) {
                         m);
 }
 
+static void manager_parse_env(Manager *m) {
+        int r;
+
+        assert(m);
+
+        /* Same as src/import/{import,pull}.c:
+         * Let's make these relatively low-level settings also controllable via env vars. User can then set
+         * them for systemd-importd.service if they like to tweak behaviour */
+
+        r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL");
+        if (r >= 0)
+                m->use_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)
+                m->use_btrfs_quota = r;
+        else if (r != -ENXIO)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_(manager_unrefp) Manager *m = NULL;
         int r;
 
-        log_setup_service();
+        log_setup();
 
         r = service_parse_argv("systemd-importd.service",
                                "VM and container image import and export service.",
@@ -1379,6 +1403,8 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate manager object: %m");
 
+        manager_parse_env(m);
+
         r = manager_add_bus_objects(m);
         if (r < 0)
                 return r;