chiark / gitweb /
core: allow setting of the description string for transient units
[elogind.git] / src / core / dbus-service.c
index d99058dd46a7945be94a556e64ca307370d6b3d8..3bedda6c014fb394bd9d7935ce27bf2c1433c3d9 100644 (file)
 
 #include <errno.h>
 
+#include "strv.h"
+#include "path-util.h"
 #include "dbus-unit.h"
 #include "dbus-execute.h"
 #include "dbus-kill.h"
-#include "dbus-service.h"
+#include "dbus-cgroup.h"
 #include "dbus-common.h"
 #include "selinux-access.h"
+#include "dbus-service.h"
 
 #define BUS_SERVICE_INTERFACE                                           \
         " <interface name=\"org.freedesktop.systemd1.Service\">\n"      \
@@ -35,7 +38,8 @@
         "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimeoutStartUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
@@ -50,6 +54,7 @@
         BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
         BUS_EXEC_CONTEXT_INTERFACE                                      \
         BUS_KILL_CONTEXT_INTERFACE                                      \
+        BUS_CGROUP_CONTEXT_INTERFACE                                    \
         "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
@@ -102,12 +107,12 @@ static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_li
 static const BusProperty bus_exec_main_status_properties[] = {
         { "ExecMainStartTimestamp",         bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
         { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
-        { "ExecMainExitTimestamp",          bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
-        { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
+        { "ExecMainExitTimestamp",          bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.realtime)   },
+        { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.monotonic)  },
         { "ExecMainPID",                    bus_property_append_pid,  "u", offsetof(ExecStatus, pid)                       },
         { "ExecMainCode",                   bus_property_append_int,  "i", offsetof(ExecStatus, code)                      },
         { "ExecMainStatus",                 bus_property_append_int,  "i", offsetof(ExecStatus, status)                    },
-        { NULL, }
+        {}
 };
 
 static const BusProperty bus_service_properties[] = {
@@ -116,7 +121,6 @@ static const BusProperty bus_service_properties[] = {
         { "PIDFile",                bus_property_append_string,       "s", offsetof(Service, pid_file),               true },
         { "NotifyAccess",           bus_service_append_notify_access, "s", offsetof(Service, notify_access)                },
         { "RestartUSec",            bus_property_append_usec,         "t", offsetof(Service, restart_usec)                 },
-        { "TimeoutUSec",            bus_property_append_usec,         "t", offsetof(Service, timeout_start_usec)           },
         { "TimeoutStartUSec",       bus_property_append_usec,         "t", offsetof(Service, timeout_start_usec)           },
         { "TimeoutStopUSec",        bus_property_append_usec,         "t", offsetof(Service, timeout_stop_usec)            },
         { "WatchdogUSec",           bus_property_append_usec,         "t", offsetof(Service, watchdog_usec)                },
@@ -140,7 +144,7 @@ static const BusProperty bus_service_properties[] = {
         { "BusName",                bus_property_append_string,       "s", offsetof(Service, bus_name),               true },
         { "StatusText",             bus_property_append_string,       "s", offsetof(Service, status_text),            true },
         { "Result",                 bus_service_append_service_result,"s", offsetof(Service, result)                       },
-        { NULL, }
+        {}
 };
 
 DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
@@ -151,11 +155,166 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
                 { "org.freedesktop.systemd1.Service", bus_service_properties,          s },
                 { "org.freedesktop.systemd1.Service", bus_exec_context_properties,     &s->exec_context },
                 { "org.freedesktop.systemd1.Service", bus_kill_context_properties,     &s->kill_context },
+                { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties,   &s->cgroup_context },
                 { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
-                { NULL, }
+                {}
         };
 
         SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
 
         return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
 }
+
+static int bus_service_set_transient_property(
+                Service *s,
+                const char *name,
+                DBusMessageIter *i,
+                UnitSetPropertiesMode mode,
+                DBusError *error) {
+
+        int r;
+
+        assert(name);
+        assert(s);
+        assert(i);
+
+        if (streq(name, "ExecStart")) {
+                DBusMessageIter sub;
+                unsigned n = 0;
+
+                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
+                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
+                        return -EINVAL;
+
+                dbus_message_iter_recurse(i, &sub);
+                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                        _cleanup_strv_free_ char **argv = NULL;
+                        DBusMessageIter sub2;
+                        dbus_bool_t ignore;
+                        const char *path;
+
+                        dbus_message_iter_recurse(&sub, &sub2);
+
+                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
+                                return -EINVAL;
+
+                        if (!path_is_absolute(path)) {
+                                dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
+                                return -EINVAL;
+                        }
+
+                        r = bus_parse_strv_iter(&sub2, &argv);
+                        if (r < 0)
+                                return r;
+
+                        dbus_message_iter_next(&sub2);
+
+                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0)
+                                return -EINVAL;
+
+                        if (mode != UNIT_CHECK) {
+                                ExecCommand *c;
+
+                                c = new0(ExecCommand, 1);
+                                if (!c)
+                                        return -ENOMEM;
+
+                                c->path = strdup(path);
+                                if (!c->path) {
+                                        free(c);
+                                        return -ENOMEM;
+                                }
+
+                                c->argv = argv;
+                                argv = NULL;
+
+                                c->ignore = ignore;
+
+                                path_kill_slashes(c->path);
+                                exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
+                        }
+
+                        n++;
+                        dbus_message_iter_next(&sub);
+                }
+
+                if (mode != UNIT_CHECK) {
+                        _cleanup_free_ char *buf = NULL;
+                        _cleanup_fclose_ FILE *f = NULL;
+                        ExecCommand *c;
+                        size_t size = 0;
+
+                        if (n == 0) {
+                                exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
+                                s->exec_command[SERVICE_EXEC_START] = NULL;
+                        }
+
+                        f = open_memstream(&buf, &size);
+                        if (!f)
+                                return -ENOMEM;
+
+                        fputs("ExecStart=\n", f);
+
+                        LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
+                                char **a;
+                                fputs("ExecStart=", f);
+
+                                if (c->ignore)
+                                        fputc('-', f);
+
+                                fputc('@', f);
+                                fputs(c->path, f);
+
+                                STRV_FOREACH(a, c->argv) {
+                                        fputc(' ', f);
+                                        fputs(*a, f);
+                                }
+
+                                fputc('\n', f);
+                        }
+
+                        fflush(f);
+                        unit_write_drop_in_private_section(UNIT(s), mode, "exec-start", buf);
+                }
+
+                return 1;
+        }
+
+        return 0;
+}
+
+int bus_service_set_property(
+                Unit *u,
+                const char *name,
+                DBusMessageIter *i,
+                UnitSetPropertiesMode mode,
+                DBusError *error) {
+
+        Service *s = SERVICE(u);
+        int r;
+
+        assert(name);
+        assert(u);
+        assert(i);
+
+        r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
+        if (r != 0)
+                return r;
+
+        if (u->transient && u->load_state == UNIT_STUB) {
+                /* This is a transient unit, let's load a little more */
+
+                r = bus_service_set_transient_property(s, name, i, mode, error);
+                if (r != 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int bus_service_commit_properties(Unit *u) {
+        assert(u);
+
+        unit_realize_cgroup(u);
+        return 0;
+}