1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "path-util.h"
26 #include "dbus-unit.h"
27 #include "dbus-execute.h"
28 #include "dbus-kill.h"
29 #include "dbus-cgroup.h"
30 #include "dbus-common.h"
31 #include "selinux-access.h"
32 #include "dbus-service.h"
34 #define BUS_SERVICE_INTERFACE \
35 " <interface name=\"org.freedesktop.systemd1.Service\">\n" \
36 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
37 " <property name=\"Restart\" type=\"s\" access=\"read\"/>\n" \
38 " <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n" \
39 " <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
40 " <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
41 " <property name=\"TimeoutStartUSec\" type=\"t\" access=\"read\"/>\n" \
42 " <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
43 " <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
44 " <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
45 " <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
46 " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
47 " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
48 " <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
49 BUS_UNIT_CGROUP_INTERFACE \
50 BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
51 BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
52 BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
53 BUS_EXEC_COMMAND_INTERFACE("ExecReload") \
54 BUS_EXEC_COMMAND_INTERFACE("ExecStop") \
55 BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
56 BUS_EXEC_CONTEXT_INTERFACE \
57 BUS_KILL_CONTEXT_INTERFACE \
58 BUS_CGROUP_CONTEXT_INTERFACE \
59 " <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
60 " <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
61 " <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
62 BUS_EXEC_STATUS_INTERFACE("ExecMain") \
63 " <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \
64 " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
65 " <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
66 " <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
67 " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
70 #define INTROSPECTION \
71 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
74 BUS_SERVICE_INTERFACE \
75 BUS_PROPERTIES_INTERFACE \
77 BUS_INTROSPECTABLE_INTERFACE \
80 #define INTERFACES_LIST \
81 BUS_UNIT_INTERFACES_LIST \
82 "org.freedesktop.systemd1.Service\0"
84 const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
86 const char bus_service_invalidating_properties[] =
95 "WatchdogTimestampMonotonic\0"
101 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
102 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
103 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
104 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
105 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
106 static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
108 static const BusProperty bus_exec_main_status_properties[] = {
109 { "ExecMainStartTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) },
110 { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
111 { "ExecMainExitTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.realtime) },
112 { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.monotonic) },
113 { "ExecMainPID", bus_property_append_pid, "u", offsetof(ExecStatus, pid) },
114 { "ExecMainCode", bus_property_append_int, "i", offsetof(ExecStatus, code) },
115 { "ExecMainStatus", bus_property_append_int, "i", offsetof(ExecStatus, status) },
119 static const BusProperty bus_service_properties[] = {
120 { "Type", bus_service_append_type, "s", offsetof(Service, type) },
121 { "Restart", bus_service_append_restart, "s", offsetof(Service, restart) },
122 { "PIDFile", bus_property_append_string, "s", offsetof(Service, pid_file), true },
123 { "NotifyAccess", bus_service_append_notify_access, "s", offsetof(Service, notify_access) },
124 { "RestartUSec", bus_property_append_usec, "t", offsetof(Service, restart_usec) },
125 { "TimeoutStartUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) },
126 { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Service, timeout_stop_usec) },
127 { "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) },
128 { "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) },
129 { "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) },
130 { "StartLimitInterval", bus_property_append_usec, "t", offsetof(Service, start_limit.interval) },
131 { "StartLimitBurst", bus_property_append_uint32, "u", offsetof(Service, start_limit.burst) },
132 { "StartLimitAction", bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action},
133 BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), true ),
134 BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), true ),
135 BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
136 BUS_EXEC_COMMAND_PROPERTY("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), true ),
137 BUS_EXEC_COMMAND_PROPERTY("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), true ),
138 BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), true ),
139 { "PermissionsStartOnly", bus_property_append_bool, "b", offsetof(Service, permissions_start_only) },
140 { "RootDirectoryStartOnly", bus_property_append_bool, "b", offsetof(Service, root_directory_start_only) },
141 { "RemainAfterExit", bus_property_append_bool, "b", offsetof(Service, remain_after_exit) },
142 { "GuessMainPID", bus_property_append_bool, "b", offsetof(Service, guess_main_pid) },
143 { "MainPID", bus_property_append_pid, "u", offsetof(Service, main_pid) },
144 { "ControlPID", bus_property_append_pid, "u", offsetof(Service, control_pid) },
145 { "BusName", bus_property_append_string, "s", offsetof(Service, bus_name), true },
146 { "StatusText", bus_property_append_string, "s", offsetof(Service, status_text), true },
147 { "Result", bus_service_append_service_result,"s", offsetof(Service, result) },
151 DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
152 Service *s = SERVICE(u);
154 const BusBoundProperties bps[] = {
155 { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
156 { "org.freedesktop.systemd1.Service", bus_unit_cgroup_properties, u },
157 { "org.freedesktop.systemd1.Service", bus_service_properties, s },
158 { "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context },
159 { "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context },
160 { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties, &s->cgroup_context },
161 { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
165 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
167 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
170 static int bus_service_set_transient_property(
174 UnitSetPropertiesMode mode,
183 if (streq(name, "RemainAfterExit")) {
184 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
187 if (mode != UNIT_CHECK) {
190 dbus_message_iter_get_basic(i, &b);
192 s->remain_after_exit = b;
193 unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
198 } else if (streq(name, "ExecStart")) {
202 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
203 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
206 dbus_message_iter_recurse(i, &sub);
207 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
208 _cleanup_strv_free_ char **argv = NULL;
209 DBusMessageIter sub2;
213 dbus_message_iter_recurse(&sub, &sub2);
215 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
218 if (!path_is_absolute(path)) {
219 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
223 r = bus_parse_strv_iter(&sub2, &argv);
227 dbus_message_iter_next(&sub2);
229 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0)
232 if (mode != UNIT_CHECK) {
235 c = new0(ExecCommand, 1);
239 c->path = strdup(path);
250 path_kill_slashes(c->path);
251 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
255 dbus_message_iter_next(&sub);
258 if (mode != UNIT_CHECK) {
259 _cleanup_free_ char *buf = NULL;
260 _cleanup_fclose_ FILE *f = NULL;
265 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
266 s->exec_command[SERVICE_EXEC_START] = NULL;
269 f = open_memstream(&buf, &size);
273 fputs("ExecStart=\n", f);
275 LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
277 fputs("ExecStart=", f);
285 STRV_FOREACH(a, c->argv) {
294 unit_write_drop_in_private(UNIT(s), mode, name, buf);
303 int bus_service_set_property(
307 UnitSetPropertiesMode mode,
310 Service *s = SERVICE(u);
317 r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
321 if (u->transient && u->load_state == UNIT_STUB) {
322 /* This is a transient unit, let's load a little more */
324 r = bus_service_set_transient_property(s, name, i, mode, error);
328 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, i, mode, error);
336 int bus_service_commit_properties(Unit *u) {
339 unit_realize_cgroup(u);