mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
machine: rework Operation logic to reuse in varlink interface
This commit is contained in:
committed by
Lennart Poettering
parent
9312b3dc28
commit
d8964f9d4d
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
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");
|
||||
}
|
||||
|
||||
} 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_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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user