]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-service.c
core: add transient units
[thirdparty/systemd.git] / src / core / dbus-service.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4139c1b2
LP
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
5430f7f2
LP
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
4139c1b2
LP
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
5430f7f2 16 Lesser General Public License for more details.
4139c1b2 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
4139c1b2
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23
c2756a68
LP
24#include "strv.h"
25#include "path-util.h"
4139c1b2
LP
26#include "dbus-unit.h"
27#include "dbus-execute.h"
4819ff03 28#include "dbus-kill.h"
4ad49000 29#include "dbus-cgroup.h"
bfebab7f 30#include "dbus-common.h"
cad45ba1 31#include "selinux-access.h"
4ad49000 32#include "dbus-service.h"
4139c1b2 33
07459bb6
FF
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=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
bb242b7b 42 " <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
a6927d7f
MO
43 " <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
44 " <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
4b939747
MO
45 " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
46 " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
69df6f00 47 " <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
07459bb6
FF
48 BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
49 BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
50 BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
51 BUS_EXEC_COMMAND_INTERFACE("ExecReload") \
52 BUS_EXEC_COMMAND_INTERFACE("ExecStop") \
53 BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
54 BUS_EXEC_CONTEXT_INTERFACE \
4819ff03 55 BUS_KILL_CONTEXT_INTERFACE \
07459bb6
FF
56 " <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
57 " <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
58 " <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
59 BUS_EXEC_STATUS_INTERFACE("ExecMain") \
60 " <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \
61 " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
62 " <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
63 " <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
f42806df 64 " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
07459bb6 65 " </interface>\n"
4288f619
LP
66
67#define INTROSPECTION \
68 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
69 "<node>\n" \
70 BUS_UNIT_INTERFACE \
71 BUS_SERVICE_INTERFACE \
72 BUS_PROPERTIES_INTERFACE \
c4e2ceae 73 BUS_PEER_INTERFACE \
4288f619
LP
74 BUS_INTROSPECTABLE_INTERFACE \
75 "</node>\n"
76
05feefe0
LP
77#define INTERFACES_LIST \
78 BUS_UNIT_INTERFACES_LIST \
79 "org.freedesktop.systemd1.Service\0"
80
9a60da28 81const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
4139c1b2 82
c4e2ceae
LP
83const char bus_service_invalidating_properties[] =
84 "ExecStartPre\0"
85 "ExecStart\0"
86 "ExecStartPost\0"
87 "ExecReload\0"
88 "ExecStop\0"
89 "ExecStopPost\0"
90 "ExecMain\0"
a6927d7f
MO
91 "WatchdogTimestamp\0"
92 "WatchdogTimestampMonotonic\0"
c4e2ceae
LP
93 "MainPID\0"
94 "ControlPID\0"
f42806df
LP
95 "StatusText\0"
96 "Result\0";
c4e2ceae 97
4139c1b2
LP
98static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
99static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
d264aa33 100static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
f42806df 101static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
4b939747 102static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
69df6f00 103static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
4139c1b2 104
d200735e
MS
105static const BusProperty bus_exec_main_status_properties[] = {
106 { "ExecMainStartTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) },
107 { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
b69bd568
MS
108 { "ExecMainExitTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.realtime) },
109 { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.monotonic) },
d200735e
MS
110 { "ExecMainPID", bus_property_append_pid, "u", offsetof(ExecStatus, pid) },
111 { "ExecMainCode", bus_property_append_int, "i", offsetof(ExecStatus, code) },
112 { "ExecMainStatus", bus_property_append_int, "i", offsetof(ExecStatus, status) },
113 { NULL, }
114};
115
116static const BusProperty bus_service_properties[] = {
a6927d7f
MO
117 { "Type", bus_service_append_type, "s", offsetof(Service, type) },
118 { "Restart", bus_service_append_restart, "s", offsetof(Service, restart) },
119 { "PIDFile", bus_property_append_string, "s", offsetof(Service, pid_file), true },
120 { "NotifyAccess", bus_service_append_notify_access, "s", offsetof(Service, notify_access) },
121 { "RestartUSec", bus_property_append_usec, "t", offsetof(Service, restart_usec) },
d568a335
MS
122 { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) },
123 { "TimeoutStartUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) },
124 { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Service, timeout_stop_usec) },
bb242b7b 125 { "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) },
a6927d7f
MO
126 { "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) },
127 { "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) },
4b939747
MO
128 { "StartLimitInterval", bus_property_append_usec, "t", offsetof(Service, start_limit.interval) },
129 { "StartLimitBurst", bus_property_append_uint32, "u", offsetof(Service, start_limit.burst) },
69df6f00 130 { "StartLimitAction", bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action},
d200735e
MS
131 BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), true ),
132 BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), true ),
133 BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
134 BUS_EXEC_COMMAND_PROPERTY("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), true ),
135 BUS_EXEC_COMMAND_PROPERTY("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), true ),
136 BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), true ),
a6927d7f
MO
137 { "PermissionsStartOnly", bus_property_append_bool, "b", offsetof(Service, permissions_start_only) },
138 { "RootDirectoryStartOnly", bus_property_append_bool, "b", offsetof(Service, root_directory_start_only) },
139 { "RemainAfterExit", bus_property_append_bool, "b", offsetof(Service, remain_after_exit) },
140 { "GuessMainPID", bus_property_append_bool, "b", offsetof(Service, guess_main_pid) },
141 { "MainPID", bus_property_append_pid, "u", offsetof(Service, main_pid) },
142 { "ControlPID", bus_property_append_pid, "u", offsetof(Service, control_pid) },
143 { "BusName", bus_property_append_string, "s", offsetof(Service, bus_name), true },
144 { "StatusText", bus_property_append_string, "s", offsetof(Service, status_text), true },
f42806df 145 { "Result", bus_service_append_service_result,"s", offsetof(Service, result) },
d200735e
MS
146 { NULL, }
147};
148
149DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
150 Service *s = SERVICE(u);
4819ff03 151
d200735e
MS
152 const BusBoundProperties bps[] = {
153 { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
154 { "org.freedesktop.systemd1.Service", bus_service_properties, s },
155 { "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context },
4819ff03 156 { "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context },
4ad49000 157 { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties, &s->cgroup_context },
d200735e
MS
158 { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
159 { NULL, }
4139c1b2
LP
160 };
161
cad45ba1
LP
162 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
163
d200735e 164 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
4139c1b2 165}
74c964d3 166
c2756a68
LP
167static int bus_service_set_transient_properties(
168 Service *s,
169 const char *name,
170 DBusMessageIter *i,
171 UnitSetPropertiesMode mode,
172 DBusError *error) {
173
174 int r;
175
176 assert(name);
177 assert(s);
178 assert(i);
179
180 if (streq(name, "ExecStart")) {
181 DBusMessageIter sub;
182 unsigned n = 0;
183
184 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
185 dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
186 return -EINVAL;
187
188 dbus_message_iter_recurse(i, &sub);
189 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
190 _cleanup_strv_free_ char **argv = NULL;
191 DBusMessageIter sub2;
192 dbus_bool_t ignore;
193 const char *path;
194
195 dbus_message_iter_recurse(&sub, &sub2);
196
197 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
198 return -EINVAL;
199
200 if (!path_is_absolute(path)) {
201 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
202 return -EINVAL;
203 }
204
205 r = bus_parse_strv_iter(&sub2, &argv);
206 if (r < 0)
207 return r;
208
209 dbus_message_iter_next(&sub2);
210
211 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0)
212 return -EINVAL;
213
214 if (mode != UNIT_CHECK) {
215 ExecCommand *c;
216
217 c = new0(ExecCommand, 1);
218 if (!c)
219 return -ENOMEM;
220
221 c->path = strdup(path);
222 if (!c->path) {
223 free(c);
224 return -ENOMEM;
225 }
226
227 c->argv = argv;
228 argv = NULL;
229
230 c->ignore = ignore;
231
232 path_kill_slashes(c->path);
233 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
234 }
235
236 n++;
237 dbus_message_iter_next(&sub);
238 }
239
240 if (mode != UNIT_CHECK) {
241 _cleanup_free_ char *buf = NULL;
242 _cleanup_fclose_ FILE *f = NULL;
243 ExecCommand *c;
244 size_t size = 0;
245
246 if (n == 0) {
247 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
248 s->exec_command[SERVICE_EXEC_START] = NULL;
249 }
250
251 f = open_memstream(&buf, &size);
252 if (!f)
253 return -ENOMEM;
254
255 fputs("ExecStart=\n", f);
256
257 LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
258 char **a;
259 fputs("ExecStart=", f);
260
261 if (c->ignore)
262 fputc('-', f);
263
264 fputc('@', f);
265 fputs(c->path, f);
266
267 STRV_FOREACH(a, c->argv) {
268 fputc(' ', f);
269 fputs(*a, f);
270 }
271
272 fputc('\n', f);
273 }
274
275 fflush(f);
276 unit_write_drop_in_private_section(UNIT(s), mode, "exec-start", buf);
277 }
278
279 return 1;
280 }
281
282 return 0;
283}
284
74c964d3
LP
285int bus_service_set_property(
286 Unit *u,
287 const char *name,
288 DBusMessageIter *i,
289 UnitSetPropertiesMode mode,
290 DBusError *error) {
291
292 Service *s = SERVICE(u);
293 int r;
294
295 assert(name);
296 assert(u);
297 assert(i);
298
299 r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
300 if (r != 0)
301 return r;
302
c2756a68
LP
303 if (u->transient && u->load_state == UNIT_STUB) {
304 /* This is a transient unit, let's load a little more */
305
306 r = bus_service_set_transient_properties(s, name, i, mode, error);
307 if (r != 0)
308 return r;
309 }
310
74c964d3
LP
311 return 0;
312}
313
314int bus_service_commit_properties(Unit *u) {
315 assert(u);
316
317 unit_realize_cgroup(u);
318 return 0;
319}