]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine: rework Operation logic to reuse in varlink interface
authorIvan Kruglov <mail@ikruglov.com>
Fri, 11 Oct 2024 14:26:38 +0000 (16:26 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 21 Oct 2024 15:08:14 +0000 (17:08 +0200)
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machined-dbus.c
src/machine/operation.c
src/machine/operation.h

index da71b9115f434882a2f5c5117470c095e48a13f4..2ae61f99b75673d9880c8633bf84c4af35a9f36d 100644 (file)
@@ -79,7 +79,7 @@ int bus_image_method_remove(
 
         errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
 
-        r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
+        r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
         if (r < 0) {
                 (void) sigkill_wait(child);
                 return r;
@@ -196,7 +196,7 @@ int bus_image_method_clone(
 
         errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
 
-        r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
+        r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
         if (r < 0) {
                 (void) sigkill_wait(child);
                 return r;
index fc7c9a83031c0810f90d0ac8656934f8e8cd752c..30abc659f8ff9abaec3508108c91c4133a70c371 100644 (file)
@@ -856,7 +856,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
 
         /* Copying might take a while, hence install a watch on the child, and return */
 
-        r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
+        r = operation_new_with_bus_reply(m->manager, m, child, message, errno_pipe_fd[0], /* ret= */ NULL);
         if (r < 0) {
                 (void) sigkill_wait(child);
                 return r;
index 730b436545d02d8dbd7697652ea0f9f52990125b..f4915f67da4e3aa5118ff005635e13054d4877ce 100644 (file)
@@ -813,7 +813,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
 
         /* The clean-up might take a while, hence install a watch on the child and return */
 
-        r = operation_new(m, NULL, child, message, errno_pipe_fd[0], &operation);
+        r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], &operation);
         if (r < 0) {
                 (void) sigkill_wait(child);
                 return r;
index 87c62a977b96778220869081d9f2e8d8c9aa10f1..4d3939496fbdd27b64a95b89cc155050f78d80e1 100644 (file)
@@ -8,8 +8,38 @@
 #include "operation.h"
 #include "process-util.h"
 
+static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_error *error) {
+        int r;
+
+        assert(si);
+        assert(o);
+
+        if (si->si_code != CLD_EXITED)
+                return log_debug_errno(SYNTHETIC_ERRNO(ESHUTDOWN), "Child died abnormally");
+
+        if (si->si_status == EXIT_SUCCESS)
+                r = 0;
+        else {
+                ssize_t n = read(o->errno_fd, &r, sizeof(r));
+                if (n < 0)
+                        return log_debug_errno(errno, "Failed to read operation's errno: %m");
+                if (n != sizeof(r))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message when reading operation's errno");
+        }
+
+        if (o->done)
+                /* A completion routine is set for this operation, call it. */
+                return o->done(o, r, error);
+
+        /* The default operation when done is to simply return an error on failure or an empty success
+         * message on success. */
+        if (r < 0)
+                log_debug_errno(r, "Operation failed: %m");
+
+        return r;
+}
+
 static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         Operation *o = ASSERT_PTR(userdata);
         int r;
 
@@ -21,61 +51,44 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
 
         o->pid = 0;
 
-        if (si->si_code != CLD_EXITED) {
-                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
-                goto fail;
-        }
+        if (o->message) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-        if (si->si_status == EXIT_SUCCESS)
-                r = 0;
-        else if (read(o->errno_fd, &r, sizeof(r)) != sizeof(r)) { /* Try to acquire error code for failed operation */
-                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-                goto fail;
-        }
-
-        if (o->done) {
-                /* A completion routine is set for this operation, call it. */
-                r = o->done(o, r, &error);
+                r = operation_done_internal(si, o, &error);
                 if (r < 0) {
                         if (!sd_bus_error_is_set(&error))
                                 sd_bus_error_set_errno(&error, r);
 
-                        goto fail;
-                }
-
-        } else {
-                /* The default operation when done is to simply return an error on failure or an empty success
-                 * message on success. */
-                if (r < 0) {
-                        sd_bus_error_set_errno(&error, r);
-                        goto fail;
+                        r = sd_bus_reply_method_error(o->message, &error);
+                        if (r < 0)
+                                log_error_errno(r, "Failed to reply to dbus message: %m");
+                } else {
+                        r = sd_bus_reply_method_return(o->message, NULL);
+                        if (r < 0)
+                                log_error_errno(r, "Failed to reply to dbus message: %m");
                 }
-
-                r = sd_bus_reply_method_return(o->message, NULL);
+        } else if (o->link) {
+                r = operation_done_internal(si, o, /* error = */ NULL);
                 if (r < 0)
-                        log_error_errno(r, "Failed to reply to message: %m");
-        }
-
-        operation_free(o);
-        return 0;
-
-fail:
-        r = sd_bus_reply_method_error(o->message, &error);
-        if (r < 0)
-                log_error_errno(r, "Failed to reply to message: %m");
+                        (void) sd_varlink_error_errno(o->link, r);
+                else
+                        (void) sd_varlink_reply(o->link, NULL);
+        } else
+                assert_not_reached();
 
         operation_free(o);
         return 0;
 }
 
-int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) {
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, sd_varlink *link, int errno_fd, Operation **ret) {
         Operation *o;
         int r;
 
         assert(manager);
         assert(child > 1);
-        assert(message);
         assert(errno_fd >= 0);
+        assert(message || link);
+        assert(!(message && link));
 
         o = new0(Operation, 1);
         if (!o)
@@ -91,6 +104,7 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_messag
 
         o->pid = child;
         o->message = sd_bus_message_ref(message);
+        o->link = sd_varlink_ref(link);
         o->errno_fd = errno_fd;
 
         LIST_PREPEND(operations, manager->operations, o);
@@ -125,6 +139,7 @@ Operation *operation_free(Operation *o) {
                 (void) sigkill_wait(o->pid);
 
         sd_bus_message_unref(o->message);
+        sd_varlink_unref(o->link);
 
         if (o->manager) {
                 LIST_REMOVE(operations, o->manager->operations, o);
index fd4828878d74a81e0b2615cb300b2dc1c6bda5f8..75bf918c2b1cf52830f02f87c80b9d4bd54599c0 100644 (file)
@@ -18,7 +18,11 @@ struct Operation {
         Manager *manager;
         Machine *machine;
         pid_t pid;
+
+        /* only one of these two fields should be set */
+        sd_varlink *link;
         sd_bus_message *message;
+
         int errno_fd;
         int extra_fd;
         sd_event_source *event_source;
@@ -27,5 +31,11 @@ struct Operation {
         LIST_FIELDS(Operation, operations_by_machine);
 };
 
-int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret);
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, sd_varlink *link, int errno_fd, Operation **ret);
 Operation *operation_free(Operation *o);
+static inline int operation_new_with_bus_reply(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) {
+        return operation_new(manager, machine, child, message, /* link = */ NULL, errno_fd, ret);
+}
+static inline int operation_new_with_varlink_reply(Manager *manager, Machine *machine, pid_t child, sd_varlink *link, int errno_fd, Operation **ret) {
+        return operation_new(manager, machine, child, /* message = */ NULL, link, errno_fd, ret);
+}