]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-service.c
Imported Upstream version 208
[systemd.git] / src / core / dbus-service.c
CommitLineData
663996b3
MS
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
14228c0d
MB
24#include "strv.h"
25#include "path-util.h"
663996b3
MS
26#include "dbus-unit.h"
27#include "dbus-execute.h"
28#include "dbus-kill.h"
14228c0d 29#include "dbus-cgroup.h"
663996b3
MS
30#include "dbus-common.h"
31#include "selinux-access.h"
14228c0d 32#include "dbus-service.h"
663996b3
MS
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" \
14228c0d
MB
41 " <property name=\"TimeoutStartUSec\" type=\"t\" access=\"read\"/>\n" \
42 " <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
663996b3
MS
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" \
14228c0d 49 BUS_UNIT_CGROUP_INTERFACE \
663996b3
MS
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 \
14228c0d 58 BUS_CGROUP_CONTEXT_INTERFACE \
663996b3
MS
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
84const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
85
86const 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
101static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
102static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
103static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
104static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
105static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
106static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
107
108static 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) },
14228c0d
MB
111 { "ExecMainExitTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.realtime) },
112 { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.monotonic) },
663996b3
MS
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) },
14228c0d 116 {}
663996b3
MS
117};
118
119static 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) },
663996b3
MS
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) },
14228c0d 148 {}
663996b3
MS
149};
150
151DBusHandlerResult 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 },
14228c0d 156 { "org.freedesktop.systemd1.Service", bus_unit_cgroup_properties, u },
663996b3
MS
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 },
14228c0d 160 { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties, &s->cgroup_context },
663996b3 161 { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
14228c0d 162 {}
663996b3
MS
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}
14228c0d
MB
169
170static 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, "RemainAfterExit")) {
184 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
185 return -EINVAL;
186
187 if (mode != UNIT_CHECK) {
188 dbus_bool_t b;
189
190 dbus_message_iter_get_basic(i, &b);
191
192 s->remain_after_exit = b;
193 unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
194 }
195
196 return 1;
197
198 } else if (streq(name, "ExecStart")) {
199 DBusMessageIter sub;
200 unsigned n = 0;
201
202 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
203 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
204 return -EINVAL;
205
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;
210 dbus_bool_t ignore;
211 const char *path;
212
213 dbus_message_iter_recurse(&sub, &sub2);
214
215 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
216 return -EINVAL;
217
218 if (!path_is_absolute(path)) {
219 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
220 return -EINVAL;
221 }
222
223 r = bus_parse_strv_iter(&sub2, &argv);
224 if (r < 0)
225 return r;
226
227 dbus_message_iter_next(&sub2);
228
229 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0)
230 return -EINVAL;
231
232 if (mode != UNIT_CHECK) {
233 ExecCommand *c;
234
235 c = new0(ExecCommand, 1);
236 if (!c)
237 return -ENOMEM;
238
239 c->path = strdup(path);
240 if (!c->path) {
241 free(c);
242 return -ENOMEM;
243 }
244
245 c->argv = argv;
246 argv = NULL;
247
248 c->ignore = ignore;
249
250 path_kill_slashes(c->path);
251 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
252 }
253
254 n++;
255 dbus_message_iter_next(&sub);
256 }
257
258 if (mode != UNIT_CHECK) {
259 _cleanup_free_ char *buf = NULL;
260 _cleanup_fclose_ FILE *f = NULL;
261 ExecCommand *c;
262 size_t size = 0;
263
264 if (n == 0) {
265 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
266 s->exec_command[SERVICE_EXEC_START] = NULL;
267 }
268
269 f = open_memstream(&buf, &size);
270 if (!f)
271 return -ENOMEM;
272
273 fputs("ExecStart=\n", f);
274
275 LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
276 _cleanup_free_ char *a;
277
278 a = strv_join_quoted(c->argv);
279 if (!a)
280 return -ENOMEM;
281
282 fprintf(f, "ExecStart=%s@%s %s\n",
283 c->ignore ? "-" : "",
284 c->path,
285 a);
286 }
287
288 fflush(f);
289 unit_write_drop_in_private(UNIT(s), mode, name, buf);
290 }
291
292 return 1;
293 }
294
295 return 0;
296}
297
298int bus_service_set_property(
299 Unit *u,
300 const char *name,
301 DBusMessageIter *i,
302 UnitSetPropertiesMode mode,
303 DBusError *error) {
304
305 Service *s = SERVICE(u);
306 int r;
307
308 assert(name);
309 assert(u);
310 assert(i);
311
312 r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
313 if (r != 0)
314 return r;
315
316 if (u->transient && u->load_state == UNIT_STUB) {
317 /* This is a transient unit, let's load a little more */
318
319 r = bus_service_set_transient_property(s, name, i, mode, error);
320 if (r != 0)
321 return r;
322
323 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, i, mode, error);
324 if (r != 0)
325 return r;
326 }
327
328 return 0;
329}
330
331int bus_service_commit_properties(Unit *u) {
332 assert(u);
333
334 unit_realize_cgroup(u);
335 return 0;
336}