dbus-service: support more options in transient service unit

This commit is contained in:
Yu Watanabe
2018-01-02 02:25:13 +09:00
parent 8c3fd5ebdd
commit d2f056176c
+169 -113
View File
@@ -22,15 +22,20 @@
#include "alloc-util.h"
#include "async.h"
#include "bus-internal.h"
#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
#include "dbus-service.h"
#include "dbus-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
#include "parse-util.h"
#include "path-util.h"
#include "service.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "unit.h"
@@ -88,6 +93,117 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_VTABLE_END
};
static int bus_set_transient_exit_status(
Unit *u,
const char *name,
ExitStatusSet *status_set,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
const int *status, *signal;
size_t sz_status, sz_signal, i;
int r;
r = sd_bus_message_enter_container(message, 'r', "aiai");
if (r < 0)
return r;
r = sd_bus_message_read_array(message, 'i', (const void **) &status, &sz_status);
if (r < 0)
return r;
r = sd_bus_message_read_array(message, 'i', (const void **) &signal, &sz_signal);
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (sz_status == 0 && sz_signal == 0 && !UNIT_WRITE_FLAGS_NOOP(flags)) {
exit_status_set_free(status_set);
unit_write_settingf(u, flags, name, "%s=", name);
return 1;
}
for (i = 0; i < sz_status; i++) {
if (status[i] < 0 || status[i] > 255)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid status code in %s: %i", name, status[i]);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = set_ensure_allocated(&status_set->status, NULL);
if (r < 0)
return r;
r = set_put(status_set->status, INT_TO_PTR(status[i]));
if (r < 0)
return r;
unit_write_settingf(u, flags, name, "%s=%i", name, status[i]);
}
}
for (i = 0; i < sz_signal; i++) {
const char *str;
str = signal_to_string(signal[i]);
if (!str)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal in %s: %i", name, signal[i]);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = set_ensure_allocated(&status_set->signal, NULL);
if (r < 0)
return r;
r = set_put(status_set->signal, INT_TO_PTR(signal[i]));
if (r < 0)
return r;
unit_write_settingf(u, flags, name, "%s=%s", name, str);
}
}
return 1;
}
static int bus_set_transient_std_fd(
Unit *u,
const char *name,
int *p,
bool *b,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
int fd, r;
assert(p);
assert(b);
r = sd_bus_message_read(message, "h", &fd);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
int copy;
copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (copy < 0)
return -errno;
asynchronous_close(*p);
*p = copy;
*b = true;
}
return 1;
}
static BUS_DEFINE_SET_TRANSIENT_PARSE(notify_access, NotifyAccess, notify_access_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, service_name_is_valid);
static int bus_service_set_transient_property(
Service *s,
const char *name,
@@ -95,6 +211,7 @@ static int bus_service_set_transient_property(
UnitWriteFlags flags,
sd_bus_error *error) {
Unit *u = UNIT(s);
ServiceExecCommand ci;
int r;
@@ -104,143 +221,82 @@ static int bus_service_set_transient_property(
flags |= UNIT_PRIVATE;
if (streq(name, "RemainAfterExit")) {
int b;
if (streq(name, "PermissionsStartOnly"))
return bus_set_transient_bool(u, name, &s->permissions_start_only, message, flags, error);
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
if (streq(name, "RootDirectoryStartOnly"))
return bus_set_transient_bool(u, name, &s->root_directory_start_only, message, flags, error);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->remain_after_exit = b;
unit_write_settingf(UNIT(s), flags, name, "RemainAfterExit=%s", yes_no(b));
}
if (streq(name, "RemainAfterExit"))
return bus_set_transient_bool(u, name, &s->remain_after_exit, message, flags, error);
return 1;
if (streq(name, "GuessMainPID"))
return bus_set_transient_bool(u, name, &s->guess_main_pid, message, flags, error);
} else if (streq(name, "Type")) {
const char *t;
ServiceType k;
if (streq(name, "Type"))
return bus_set_transient_service_type(u, name, &s->type, message, flags, error);
r = sd_bus_message_read(message, "s", &t);
if (r < 0)
return r;
if (streq(name, "RestartUSec"))
return bus_set_transient_usec(u, name, &s->restart_usec, message, flags, error);
k = service_type_from_string(t);
if (k < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
if (streq(name, "TimeoutStartUSec")) {
r = bus_set_transient_usec(u, name, &s->timeout_start_usec, message, flags, error);
if (r >= 0 && !UNIT_WRITE_FLAGS_NOOP(flags))
s->start_timeout_defined = true;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->type = k;
unit_write_settingf(UNIT(s), flags, name, "Type=%s", service_type_to_string(s->type));
}
return r;
}
return 1;
} else if (streq(name, "RuntimeMaxUSec")) {
usec_t u;
if (streq(name, "TimeoutStopUSec"))
return bus_set_transient_usec(u, name, &s->timeout_stop_usec, message, flags, error);
r = sd_bus_message_read(message, "t", &u);
if (r < 0)
return r;
if (streq(name, "RuntimeMaxUSec"))
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->runtime_max_usec = u;
unit_write_settingf(UNIT(s), flags, name, "RuntimeMaxSec=" USEC_FMT "us", u);
}
if (streq(name, "WatchdogUSec"))
return bus_set_transient_usec(u, name, &s->watchdog_usec, message, flags, error);
return 1;
if (streq(name, "FileDescriptorStoreMax"))
return bus_set_transient_unsigned(u, name, &s->n_fd_store_max, message, flags, error);
} else if (streq(name, "Restart")) {
ServiceRestart sr;
const char *v;
if (streq(name, "NotifyAccess"))
return bus_set_transient_notify_access(u, name, &s->notify_access, message, flags, error);
r = sd_bus_message_read(message, "s", &v);
if (r < 0)
return r;
if (streq(name, "PIDFile"))
return bus_set_transient_path(u, name, &s->pid_file, message, flags, error);
if (isempty(v))
sr = SERVICE_RESTART_NO;
else {
sr = service_restart_from_string(v);
if (sr < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid restart setting: %s", v);
}
if (streq(name, "USBFunctionDescriptors"))
return bus_set_transient_path(u, name, &s->usb_function_descriptors, message, flags, error);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->restart = sr;
unit_write_settingf(UNIT(s), flags, name, "Restart=%s", service_restart_to_string(sr));
}
if (streq(name, "USBFunctionStrings"))
return bus_set_transient_path(u, name, &s->usb_function_strings, message, flags, error);
return 1;
if (streq(name, "BusName"))
return bus_set_transient_bus_name(u, name, &s->bus_name, message, flags, error);
} else if (STR_IN_SET(name,
"StandardInputFileDescriptor",
"StandardOutputFileDescriptor",
"StandardErrorFileDescriptor")) {
int fd;
if (streq(name, "Restart"))
return bus_set_transient_service_restart(u, name, &s->restart, message, flags, error);
r = sd_bus_message_read(message, "h", &fd);
if (r < 0)
return r;
if (streq(name, "RestartPreventExitStatus"))
return bus_set_transient_exit_status(u, name, &s->restart_prevent_status, message, flags, error);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
int copy;
if (streq(name, "RestartForceExitStatus"))
return bus_set_transient_exit_status(u, name, &s->restart_force_status, message, flags, error);
copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (copy < 0)
return -errno;
if (streq(name, "SuccessExitStatus"))
return bus_set_transient_exit_status(u, name, &s->success_status, message, flags, error);
if (streq(name, "StandardInputFileDescriptor")) {
asynchronous_close(s->stdin_fd);
s->stdin_fd = copy;
} else if (streq(name, "StandardOutputFileDescriptor")) {
asynchronous_close(s->stdout_fd);
s->stdout_fd = copy;
} else {
asynchronous_close(s->stderr_fd);
s->stderr_fd = copy;
}
if ((ci = service_exec_command_from_string(name)) >= 0)
return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
s->exec_context.stdio_as_fds = true;
}
if (streq(name, "StandardInputFileDescriptor"))
return bus_set_transient_std_fd(u, name, &s->stdin_fd, &s->exec_context.stdio_as_fds, message, flags, error);
return 1;
if (streq(name, "StandardOutputFileDescriptor"))
return bus_set_transient_std_fd(u, name, &s->stdout_fd, &s->exec_context.stdio_as_fds, message, flags, error);
} else if (streq(name, "FileDescriptorStoreMax")) {
uint32_t u;
r = sd_bus_message_read(message, "u", &u);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->n_fd_store_max = (unsigned) u;
unit_write_settingf(UNIT(s), flags, name, "FileDescriptorStoreMax=%" PRIu32, u);
}
return 1;
} else if (streq(name, "NotifyAccess")) {
const char *t;
NotifyAccess k;
r = sd_bus_message_read(message, "s", &t);
if (r < 0)
return r;
k = notify_access_from_string(t);
if (k < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid notify access setting %s", t);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->notify_access = k;
unit_write_settingf(UNIT(s), flags, name, "NotifyAccess=%s", notify_access_to_string(s->notify_access));
}
return 1;
} else if ((ci = service_exec_command_from_string(name)) >= 0)
return bus_set_transient_exec_command(UNIT(s), name, &s->exec_command[ci], message, flags, error);
if (streq(name, "StandardErrorFileDescriptor"))
return bus_set_transient_std_fd(u, name, &s->stderr_fd, &s->exec_context.stdio_as_fds, message, flags, error);
return 0;
}