]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-service.c
core: move ControlGroup and Slice properties out of the dbus "Unit" interface
[thirdparty/systemd.git] / src / core / dbus-service.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "strv.h"
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"
33
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" \
68 " </interface>\n"
69
70 #define INTROSPECTION \
71 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
72 "<node>\n" \
73 BUS_UNIT_INTERFACE \
74 BUS_SERVICE_INTERFACE \
75 BUS_PROPERTIES_INTERFACE \
76 BUS_PEER_INTERFACE \
77 BUS_INTROSPECTABLE_INTERFACE \
78 "</node>\n"
79
80 #define INTERFACES_LIST \
81 BUS_UNIT_INTERFACES_LIST \
82 "org.freedesktop.systemd1.Service\0"
83
84 const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
85
86 const char bus_service_invalidating_properties[] =
87 "ExecStartPre\0"
88 "ExecStart\0"
89 "ExecStartPost\0"
90 "ExecReload\0"
91 "ExecStop\0"
92 "ExecStopPost\0"
93 "ExecMain\0"
94 "WatchdogTimestamp\0"
95 "WatchdogTimestampMonotonic\0"
96 "MainPID\0"
97 "ControlPID\0"
98 "StatusText\0"
99 "Result\0";
100
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);
107
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) },
116 {}
117 };
118
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) },
148 {}
149 };
150
151 DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
152 Service *s = SERVICE(u);
153
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 },
162 {}
163 };
164
165 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
166
167 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
168 }
169
170 static int bus_service_set_transient_property(
171 Service *s,
172 const char *name,
173 DBusMessageIter *i,
174 UnitSetPropertiesMode mode,
175 DBusError *error) {
176
177 int r;
178
179 assert(name);
180 assert(s);
181 assert(i);
182
183 if (streq(name, "ExecStart")) {
184 DBusMessageIter sub;
185 unsigned n = 0;
186
187 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
188 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
189 return -EINVAL;
190
191 dbus_message_iter_recurse(i, &sub);
192 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
193 _cleanup_strv_free_ char **argv = NULL;
194 DBusMessageIter sub2;
195 dbus_bool_t ignore;
196 const char *path;
197
198 dbus_message_iter_recurse(&sub, &sub2);
199
200 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
201 return -EINVAL;
202
203 if (!path_is_absolute(path)) {
204 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
205 return -EINVAL;
206 }
207
208 r = bus_parse_strv_iter(&sub2, &argv);
209 if (r < 0)
210 return r;
211
212 dbus_message_iter_next(&sub2);
213
214 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0)
215 return -EINVAL;
216
217 if (mode != UNIT_CHECK) {
218 ExecCommand *c;
219
220 c = new0(ExecCommand, 1);
221 if (!c)
222 return -ENOMEM;
223
224 c->path = strdup(path);
225 if (!c->path) {
226 free(c);
227 return -ENOMEM;
228 }
229
230 c->argv = argv;
231 argv = NULL;
232
233 c->ignore = ignore;
234
235 path_kill_slashes(c->path);
236 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
237 }
238
239 n++;
240 dbus_message_iter_next(&sub);
241 }
242
243 if (mode != UNIT_CHECK) {
244 _cleanup_free_ char *buf = NULL;
245 _cleanup_fclose_ FILE *f = NULL;
246 ExecCommand *c;
247 size_t size = 0;
248
249 if (n == 0) {
250 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
251 s->exec_command[SERVICE_EXEC_START] = NULL;
252 }
253
254 f = open_memstream(&buf, &size);
255 if (!f)
256 return -ENOMEM;
257
258 fputs("ExecStart=\n", f);
259
260 LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
261 char **a;
262 fputs("ExecStart=", f);
263
264 if (c->ignore)
265 fputc('-', f);
266
267 fputc('@', f);
268 fputs(c->path, f);
269
270 STRV_FOREACH(a, c->argv) {
271 fputc(' ', f);
272 fputs(*a, f);
273 }
274
275 fputc('\n', f);
276 }
277
278 fflush(f);
279 unit_write_drop_in_private_section(UNIT(s), mode, "exec-start", buf);
280 }
281
282 return 1;
283 }
284
285 return 0;
286 }
287
288 int bus_service_set_property(
289 Unit *u,
290 const char *name,
291 DBusMessageIter *i,
292 UnitSetPropertiesMode mode,
293 DBusError *error) {
294
295 Service *s = SERVICE(u);
296 int r;
297
298 assert(name);
299 assert(u);
300 assert(i);
301
302 r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
303 if (r != 0)
304 return r;
305
306 if (u->transient && u->load_state == UNIT_STUB) {
307 /* This is a transient unit, let's load a little more */
308
309 r = bus_service_set_transient_property(s, name, i, mode, error);
310 if (r != 0)
311 return r;
312 }
313
314 return 0;
315 }
316
317 int bus_service_commit_properties(Unit *u) {
318 assert(u);
319
320 unit_realize_cgroup(u);
321 return 0;
322 }