dbus-service: support more options in transient service unit
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 1 Jan 2018 16:40:06 +0000 (01:40 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 1 Jan 2018 17:25:13 +0000 (02:25 +0900)
src/core/dbus-service.c

index 4f719c0..36937cc 100644 (file)
 
 #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,159 +93,210 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
-static int bus_service_set_transient_property(
-                Service *s,
+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) {
 
-        ServiceExecCommand ci;
+        const int *status, *signal;
+        size_t sz_status, sz_signal, i;
         int r;
 
-        assert(s);
-        assert(name);
-        assert(message);
-
-        flags |= UNIT_PRIVATE;
+        r = sd_bus_message_enter_container(message, 'r', "aiai");
+        if (r < 0)
+                return r;
 
-        if (streq(name, "RemainAfterExit")) {
-                int b;
+        r = sd_bus_message_read_array(message, 'i', (const void **) &status, &sz_status);
+        if (r < 0)
+                return r;
 
-                r = sd_bus_message_read(message, "b", &b);
-                if (r < 0)
-                        return r;
+        r = sd_bus_message_read_array(message, 'i', (const void **) &signal, &sz_signal);
+        if (r < 0)
+                return r;
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        s->remain_after_exit = b;
-                        unit_write_settingf(UNIT(s), flags, name, "RemainAfterExit=%s", yes_no(b));
-                }
+        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;
+        }
 
-        } else if (streq(name, "Type")) {
-                const char *t;
-                ServiceType k;
+        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]);
 
-                r = sd_bus_message_read(message, "s", &t);
-                if (r < 0)
-                        return r;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        r = set_ensure_allocated(&status_set->status, NULL);
+                        if (r < 0)
+                                return r;
 
-                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);
+                        r = set_put(status_set->status, INT_TO_PTR(status[i]));
+                        if (r < 0)
+                                return r;
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        s->type = k;
-                        unit_write_settingf(UNIT(s), flags, name, "Type=%s", service_type_to_string(s->type));
+                        unit_write_settingf(u, flags, name, "%s=%i", name, status[i]);
                 }
+        }
 
-                return 1;
-        } else if (streq(name, "RuntimeMaxUSec")) {
-                usec_t u;
+        for (i = 0; i < sz_signal; i++) {
+                const char *str;
 
-                r = sd_bus_message_read(message, "t", &u);
-                if (r < 0)
-                        return r;
+                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)) {
-                        s->runtime_max_usec = u;
-                        unit_write_settingf(UNIT(s), flags, name, "RuntimeMaxSec=" USEC_FMT "us", u);
+                        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;
+        return 1;
+}
 
-        } else if (streq(name, "Restart")) {
-                ServiceRestart sr;
-                const char *v;
+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) {
 
-                r = sd_bus_message_read(message, "s", &v);
-                if (r < 0)
-                        return r;
+        int fd, r;
 
-                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);
-                }
+        assert(p);
+        assert(b);
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        s->restart = sr;
-                        unit_write_settingf(UNIT(s), flags, name, "Restart=%s", service_restart_to_string(sr));
-                }
+        r = sd_bus_message_read(message, "h", &fd);
+        if (r < 0)
+                return r;
 
-                return 1;
+        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                int copy;
 
-        } else if (STR_IN_SET(name,
-                              "StandardInputFileDescriptor",
-                              "StandardOutputFileDescriptor",
-                              "StandardErrorFileDescriptor")) {
-                int fd;
+                copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+                if (copy < 0)
+                        return -errno;
 
-                r = sd_bus_message_read(message, "h", &fd);
-                if (r < 0)
-                        return r;
+                asynchronous_close(*p);
+                *p = copy;
+                *b = true;
+        }
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        int copy;
-
-                        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-                        if (copy < 0)
-                                return -errno;
-
-                        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;
-                        }
-
-                        s->exec_context.stdio_as_fds = 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);
 
-                return 1;
+static int bus_service_set_transient_property(
+                Service *s,
+                const char *name,
+                sd_bus_message *message,
+                UnitWriteFlags flags,
+                sd_bus_error *error) {
 
-        } else if (streq(name, "FileDescriptorStoreMax")) {
-                uint32_t u;
+        Unit *u = UNIT(s);
+        ServiceExecCommand ci;
+        int r;
 
-                r = sd_bus_message_read(message, "u", &u);
-                if (r < 0)
-                        return r;
+        assert(s);
+        assert(name);
+        assert(message);
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        s->n_fd_store_max = (unsigned) u;
-                        unit_write_settingf(UNIT(s), flags, name, "FileDescriptorStoreMax=%" PRIu32, u);
-                }
+        flags |= UNIT_PRIVATE;
 
-                return 1;
+        if (streq(name, "PermissionsStartOnly"))
+                return bus_set_transient_bool(u, name, &s->permissions_start_only, message, flags, error);
 
-        } else if (streq(name, "NotifyAccess")) {
-                const char *t;
-                NotifyAccess k;
+        if (streq(name, "RootDirectoryStartOnly"))
+                return bus_set_transient_bool(u, name, &s->root_directory_start_only, message, flags, error);
 
-                r = sd_bus_message_read(message, "s", &t);
-                if (r < 0)
-                        return r;
+        if (streq(name, "RemainAfterExit"))
+                return bus_set_transient_bool(u, name, &s->remain_after_exit, message, flags, error);
 
-                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 (streq(name, "GuessMainPID"))
+                return bus_set_transient_bool(u, name, &s->guess_main_pid, message, flags, error);
 
-                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));
-                }
+        if (streq(name, "Type"))
+                return bus_set_transient_service_type(u, name, &s->type, message, flags, error);
 
-                return 1;
+        if (streq(name, "RestartUSec"))
+                return bus_set_transient_usec(u, name, &s->restart_usec, message, flags, error);
+
+        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;
+
+                return r;
+        }
+
+        if (streq(name, "TimeoutStopUSec"))
+                return bus_set_transient_usec(u, name, &s->timeout_stop_usec, message, flags, error);
+
+        if (streq(name, "RuntimeMaxUSec"))
+                return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
+
+        if (streq(name, "WatchdogUSec"))
+                return bus_set_transient_usec(u, name, &s->watchdog_usec, message, flags, error);
+
+        if (streq(name, "FileDescriptorStoreMax"))
+                return bus_set_transient_unsigned(u, name, &s->n_fd_store_max, message, flags, error);
+
+        if (streq(name, "NotifyAccess"))
+                return bus_set_transient_notify_access(u, name, &s->notify_access, message, flags, error);
+
+        if (streq(name, "PIDFile"))
+                return bus_set_transient_path(u, name, &s->pid_file, message, flags, error);
+
+        if (streq(name, "USBFunctionDescriptors"))
+                return bus_set_transient_path(u, name, &s->usb_function_descriptors, message, flags, error);
+
+        if (streq(name, "USBFunctionStrings"))
+                return bus_set_transient_path(u, name, &s->usb_function_strings, message, flags, error);
+
+        if (streq(name, "BusName"))
+                return bus_set_transient_bus_name(u, name, &s->bus_name, message, flags, error);
+
+        if (streq(name, "Restart"))
+                return bus_set_transient_service_restart(u, name, &s->restart, message, flags, error);
+
+        if (streq(name, "RestartPreventExitStatus"))
+                return bus_set_transient_exit_status(u, name, &s->restart_prevent_status, message, flags, error);
+
+        if (streq(name, "RestartForceExitStatus"))
+                return bus_set_transient_exit_status(u, name, &s->restart_force_status, message, flags, error);
+
+        if (streq(name, "SuccessExitStatus"))
+                return bus_set_transient_exit_status(u, name, &s->success_status, message, flags, error);
+
+        if ((ci = service_exec_command_from_string(name)) >= 0)
+                return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
+
+        if (streq(name, "StandardInputFileDescriptor"))
+                return bus_set_transient_std_fd(u, name, &s->stdin_fd, &s->exec_context.stdio_as_fds, message, flags, error);
+
+        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 ((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;
 }