summaryrefslogtreecommitdiffstats
path: root/src/machine/operation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/machine/operation.c')
-rw-r--r--src/machine/operation.c91
1 files changed, 53 insertions, 38 deletions
diff --git a/src/machine/operation.c b/src/machine/operation.c
index 87c62a977b..4d3939496f 100644
--- a/src/machine/operation.c
+++ b/src/machine/operation.c
@@ -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);