]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-unit.c
Imported Upstream version 217
[systemd.git] / src / core / dbus-unit.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
60f067b4 22#include "sd-bus.h"
663996b3 23#include "log.h"
663996b3
MS
24#include "selinux-access.h"
25#include "cgroup-util.h"
26#include "strv.h"
27#include "path-util.h"
28#include "fileio.h"
60f067b4
JS
29#include "bus-errors.h"
30#include "dbus.h"
31#include "dbus-manager.h"
32#include "dbus-unit.h"
663996b3 33
60f067b4
JS
34static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
35static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
5eef597e 36static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
60f067b4
JS
37
38static int property_get_names(
39 sd_bus *bus,
40 const char *path,
41 const char *interface,
42 const char *property,
43 sd_bus_message *reply,
44 void *userdata,
45 sd_bus_error *error) {
46
47 Unit *u = userdata;
48 Iterator i;
49 const char *t;
50 int r;
663996b3 51
60f067b4
JS
52 assert(bus);
53 assert(reply);
54 assert(u);
663996b3 55
60f067b4
JS
56 r = sd_bus_message_open_container(reply, 'a', "s");
57 if (r < 0)
58 return r;
663996b3 59
60f067b4
JS
60 SET_FOREACH(t, u->names, i) {
61 r = sd_bus_message_append(reply, "s", t);
62 if (r < 0)
63 return r;
64 }
663996b3 65
60f067b4 66 return sd_bus_message_close_container(reply);
663996b3
MS
67}
68
60f067b4
JS
69static int property_get_following(
70 sd_bus *bus,
71 const char *path,
72 const char *interface,
73 const char *property,
74 sd_bus_message *reply,
75 void *userdata,
76 sd_bus_error *error) {
77
78 Unit *u = userdata, *f;
663996b3 79
60f067b4
JS
80 assert(bus);
81 assert(reply);
663996b3
MS
82 assert(u);
83
84 f = unit_following(u);
60f067b4 85 return sd_bus_message_append(reply, "s", f ? f->id : "");
663996b3
MS
86}
87
60f067b4
JS
88static int property_get_dependencies(
89 sd_bus *bus,
90 const char *path,
91 const char *interface,
92 const char *property,
93 sd_bus_message *reply,
94 void *userdata,
95 sd_bus_error *error) {
14228c0d 96
60f067b4 97 Set *s = *(Set**) userdata;
663996b3 98 Iterator j;
60f067b4
JS
99 Unit *u;
100 int r;
663996b3 101
60f067b4
JS
102 assert(bus);
103 assert(reply);
663996b3 104
60f067b4
JS
105 r = sd_bus_message_open_container(reply, 'a', "s");
106 if (r < 0)
107 return r;
663996b3 108
60f067b4
JS
109 SET_FOREACH(u, s, j) {
110 r = sd_bus_message_append(reply, "s", u->id);
111 if (r < 0)
112 return r;
113 }
663996b3 114
60f067b4 115 return sd_bus_message_close_container(reply);
663996b3
MS
116}
117
60f067b4
JS
118static int property_get_description(
119 sd_bus *bus,
120 const char *path,
121 const char *interface,
122 const char *property,
123 sd_bus_message *reply,
124 void *userdata,
125 sd_bus_error *error) {
663996b3 126
60f067b4 127 Unit *u = userdata;
663996b3 128
60f067b4
JS
129 assert(bus);
130 assert(reply);
131 assert(u);
663996b3 132
60f067b4 133 return sd_bus_message_append(reply, "s", unit_description(u));
663996b3
MS
134}
135
60f067b4
JS
136static int property_get_active_state(
137 sd_bus *bus,
138 const char *path,
139 const char *interface,
140 const char *property,
141 sd_bus_message *reply,
142 void *userdata,
143 sd_bus_error *error) {
663996b3 144
60f067b4 145 Unit *u = userdata;
663996b3 146
60f067b4
JS
147 assert(bus);
148 assert(reply);
663996b3
MS
149 assert(u);
150
60f067b4 151 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
663996b3
MS
152}
153
60f067b4
JS
154static int property_get_sub_state(
155 sd_bus *bus,
156 const char *path,
157 const char *interface,
158 const char *property,
159 sd_bus_message *reply,
160 void *userdata,
161 sd_bus_error *error) {
663996b3 162
60f067b4 163 Unit *u = userdata;
663996b3 164
60f067b4
JS
165 assert(bus);
166 assert(reply);
167 assert(u);
663996b3 168
60f067b4 169 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
663996b3
MS
170}
171
60f067b4
JS
172static int property_get_unit_file_state(
173 sd_bus *bus,
174 const char *path,
175 const char *interface,
176 const char *property,
177 sd_bus_message *reply,
178 void *userdata,
179 sd_bus_error *error) {
663996b3 180
60f067b4 181 Unit *u = userdata;
663996b3 182
60f067b4
JS
183 assert(bus);
184 assert(reply);
185 assert(u);
663996b3 186
60f067b4 187 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
663996b3
MS
188}
189
60f067b4
JS
190static int property_get_can_start(
191 sd_bus *bus,
192 const char *path,
193 const char *interface,
194 const char *property,
195 sd_bus_message *reply,
196 void *userdata,
197 sd_bus_error *error) {
663996b3 198
60f067b4 199 Unit *u = userdata;
663996b3 200
60f067b4
JS
201 assert(bus);
202 assert(reply);
203 assert(u);
663996b3 204
60f067b4 205 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
663996b3
MS
206}
207
60f067b4
JS
208static int property_get_can_stop(
209 sd_bus *bus,
210 const char *path,
211 const char *interface,
212 const char *property,
213 sd_bus_message *reply,
214 void *userdata,
215 sd_bus_error *error) {
216
217 Unit *u = userdata;
663996b3 218
60f067b4
JS
219 assert(bus);
220 assert(reply);
663996b3
MS
221 assert(u);
222
223 /* On the lower levels we assume that every unit we can start
224 * we can also stop */
225
60f067b4 226 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
663996b3
MS
227}
228
60f067b4
JS
229static int property_get_can_reload(
230 sd_bus *bus,
231 const char *path,
232 const char *interface,
233 const char *property,
234 sd_bus_message *reply,
235 void *userdata,
236 sd_bus_error *error) {
663996b3 237
60f067b4 238 Unit *u = userdata;
663996b3 239
60f067b4
JS
240 assert(bus);
241 assert(reply);
242 assert(u);
663996b3 243
60f067b4 244 return sd_bus_message_append(reply, "b", unit_can_reload(u));
663996b3
MS
245}
246
60f067b4
JS
247static int property_get_can_isolate(
248 sd_bus *bus,
249 const char *path,
250 const char *interface,
251 const char *property,
252 sd_bus_message *reply,
253 void *userdata,
254 sd_bus_error *error) {
663996b3 255
60f067b4 256 Unit *u = userdata;
663996b3 257
60f067b4
JS
258 assert(bus);
259 assert(reply);
260 assert(u);
663996b3 261
60f067b4 262 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
663996b3
MS
263}
264
60f067b4
JS
265static int property_get_job(
266 sd_bus *bus,
267 const char *path,
268 const char *interface,
269 const char *property,
270 sd_bus_message *reply,
271 void *userdata,
272 sd_bus_error *error) {
273
663996b3 274 _cleanup_free_ char *p = NULL;
60f067b4 275 Unit *u = userdata;
663996b3 276
60f067b4
JS
277 assert(bus);
278 assert(reply);
663996b3
MS
279 assert(u);
280
60f067b4
JS
281 if (!u->job)
282 return sd_bus_message_append(reply, "(uo)", 0, "/");
663996b3 283
60f067b4
JS
284 p = job_dbus_path(u->job);
285 if (!p)
663996b3
MS
286 return -ENOMEM;
287
60f067b4 288 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
663996b3
MS
289}
290
60f067b4
JS
291static int property_get_need_daemon_reload(
292 sd_bus *bus,
293 const char *path,
294 const char *interface,
295 const char *property,
296 sd_bus_message *reply,
297 void *userdata,
298 sd_bus_error *error) {
663996b3 299
60f067b4 300 Unit *u = userdata;
663996b3 301
60f067b4
JS
302 assert(bus);
303 assert(reply);
304 assert(u);
663996b3 305
60f067b4 306 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
663996b3
MS
307}
308
60f067b4
JS
309static int property_get_conditions(
310 sd_bus *bus,
311 const char *path,
312 const char *interface,
313 const char *property,
314 sd_bus_message *reply,
315 void *userdata,
316 sd_bus_error *error) {
663996b3 317
60f067b4
JS
318 Unit *u = userdata;
319 Condition *c;
320 int r;
663996b3 321
60f067b4
JS
322 assert(bus);
323 assert(reply);
324 assert(u);
663996b3 325
60f067b4
JS
326 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
327 if (r < 0)
328 return r;
663996b3 329
60f067b4
JS
330 LIST_FOREACH(conditions, c, u->conditions) {
331 r = sd_bus_message_append(reply, "(sbbsi)",
332 condition_type_to_string(c->type),
333 c->trigger, c->negate,
334 c->parameter, c->state);
335 if (r < 0)
336 return r;
14228c0d 337
60f067b4 338 }
663996b3 339
60f067b4 340 return sd_bus_message_close_container(reply);
663996b3
MS
341}
342
60f067b4
JS
343static int property_get_load_error(
344 sd_bus *bus,
345 const char *path,
346 const char *interface,
347 const char *property,
348 sd_bus_message *reply,
349 void *userdata,
350 sd_bus_error *error) {
663996b3 351
60f067b4
JS
352 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
353 Unit *u = userdata;
663996b3 354
60f067b4
JS
355 assert(bus);
356 assert(reply);
357 assert(u);
663996b3 358
60f067b4
JS
359 if (u->load_error != 0)
360 sd_bus_error_set_errno(&e, u->load_error);
663996b3 361
60f067b4 362 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
663996b3
MS
363}
364
60f067b4
JS
365int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
366 const char *smode;
367 JobMode mode;
663996b3
MS
368 int r;
369
60f067b4
JS
370 assert(bus);
371 assert(message);
372 assert(u);
373 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
663996b3 374
60f067b4
JS
375 r = sd_bus_message_read(message, "s", &smode);
376 if (r < 0)
377 return r;
663996b3 378
60f067b4
JS
379 mode = job_mode_from_string(smode);
380 if (mode < 0)
381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
663996b3 382
60f067b4
JS
383 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
384}
663996b3 385
60f067b4
JS
386static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
387 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
388}
663996b3 389
60f067b4
JS
390static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
391 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
392}
663996b3 393
60f067b4
JS
394static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
395 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
396}
663996b3 397
60f067b4
JS
398static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
399 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
400}
663996b3 401
60f067b4
JS
402static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
403 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
404}
663996b3 405
60f067b4
JS
406static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
407 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
408}
663996b3 409
60f067b4
JS
410static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
411 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
412}
663996b3 413
60f067b4
JS
414int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
415 Unit *u = userdata;
416 const char *swho;
417 int32_t signo;
418 KillWho who;
419 int r;
663996b3 420
60f067b4
JS
421 assert(bus);
422 assert(message);
423 assert(u);
663996b3 424
5eef597e
MP
425 r = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
426 if (r < 0)
427 return r;
428 if (r == 0)
429 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
430
60f067b4
JS
431 r = sd_bus_message_read(message, "si", &swho, &signo);
432 if (r < 0)
433 return r;
434
435 if (isempty(swho))
436 who = KILL_ALL;
437 else {
438 who = kill_who_from_string(swho);
439 if (who < 0)
440 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
663996b3
MS
441 }
442
60f067b4
JS
443 if (signo <= 0 || signo >= _NSIG)
444 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
445
5eef597e 446 r = mac_selinux_unit_access_check(u, message, "stop", error);
60f067b4
JS
447 if (r < 0)
448 return r;
663996b3 449
60f067b4
JS
450 r = unit_kill(u, who, signo, error);
451 if (r < 0)
452 return r;
663996b3 453
60f067b4 454 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
455}
456
60f067b4
JS
457int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
458 Unit *u = userdata;
663996b3 459 int r;
663996b3 460
60f067b4 461 assert(bus);
663996b3 462 assert(message);
60f067b4 463 assert(u);
663996b3 464
5eef597e
MP
465 r = bus_verify_manage_unit_async(u->manager, message, error);
466 if (r < 0)
467 return r;
468 if (r == 0)
469 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
470
471 r = mac_selinux_unit_access_check(u, message, "reload", error);
60f067b4
JS
472 if (r < 0)
473 return r;
663996b3 474
60f067b4 475 unit_reset_failed(u);
663996b3 476
60f067b4
JS
477 return sd_bus_reply_method_return(message, NULL);
478}
663996b3 479
60f067b4
JS
480int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
481 Unit *u = userdata;
482 int runtime, r;
663996b3 483
60f067b4
JS
484 assert(bus);
485 assert(message);
486 assert(u);
663996b3 487
5eef597e
MP
488 r = bus_verify_manage_unit_async(u->manager, message, error);
489 if (r < 0)
490 return r;
491 if (r == 0)
492 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
493
60f067b4
JS
494 r = sd_bus_message_read(message, "b", &runtime);
495 if (r < 0)
496 return r;
663996b3 497
5eef597e 498 r = mac_selinux_unit_access_check(u, message, "start", error);
60f067b4
JS
499 if (r < 0)
500 return r;
663996b3 501
60f067b4
JS
502 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
503 if (r < 0)
504 return r;
663996b3 505
60f067b4
JS
506 return sd_bus_reply_method_return(message, NULL);
507}
663996b3 508
60f067b4
JS
509const sd_bus_vtable bus_unit_vtable[] = {
510 SD_BUS_VTABLE_START(0),
511
512 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
513 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
514 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
515 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
516 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
517 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
518 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
519 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
520 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
521 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
522 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
523 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
524 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
525 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
526 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
527 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
528 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
529 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
530 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
531 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
532 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
533 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
534 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
535 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
536 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
537 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
538 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
539 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
540 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
541 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
542 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
543 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
544 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
545 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
546 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
547 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
550 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
551 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
552 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
553 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
554 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
555 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
557 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
558 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
559 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
560 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
563 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
5eef597e
MP
566 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4
JS
568 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
569 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
570 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
571 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
573
574 SD_BUS_METHOD("Start", "s", "o", method_start, 0),
575 SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
576 SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
577 SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
578 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
579 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
580 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
581 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
582 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
583 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
584
585 SD_BUS_VTABLE_END
586};
663996b3 587
60f067b4
JS
588static int property_get_slice(
589 sd_bus *bus,
590 const char *path,
591 const char *interface,
592 const char *property,
593 sd_bus_message *reply,
594 void *userdata,
595 sd_bus_error *error) {
663996b3 596
60f067b4 597 Unit *u = userdata;
663996b3 598
60f067b4
JS
599 assert(bus);
600 assert(reply);
601 assert(u);
663996b3 602
60f067b4
JS
603 return sd_bus_message_append(reply, "s", unit_slice_name(u));
604}
663996b3 605
60f067b4
JS
606const sd_bus_vtable bus_unit_cgroup_vtable[] = {
607 SD_BUS_VTABLE_START(0),
608 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
609 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
610 SD_BUS_VTABLE_END
611};
663996b3 612
60f067b4
JS
613static int send_new_signal(sd_bus *bus, void *userdata) {
614 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
615 _cleanup_free_ char *p = NULL;
616 Unit *u = userdata;
617 int r;
663996b3 618
60f067b4
JS
619 assert(bus);
620 assert(u);
663996b3 621
60f067b4
JS
622 p = unit_dbus_path(u);
623 if (!u)
624 return -ENOMEM;
663996b3 625
60f067b4
JS
626 r = sd_bus_message_new_signal(
627 bus,
628 &m,
629 "/org/freedesktop/systemd1",
630 "org.freedesktop.systemd1.Manager",
631 "UnitNew");
632 if (r < 0)
633 return r;
663996b3 634
60f067b4
JS
635 r = sd_bus_message_append(m, "so", u->id, p);
636 if (r < 0)
637 return r;
663996b3 638
60f067b4
JS
639 return sd_bus_send(bus, m, NULL);
640}
663996b3 641
60f067b4
JS
642static int send_changed_signal(sd_bus *bus, void *userdata) {
643 _cleanup_free_ char *p = NULL;
644 Unit *u = userdata;
645 int r;
663996b3 646
60f067b4
JS
647 assert(bus);
648 assert(u);
663996b3 649
60f067b4
JS
650 p = unit_dbus_path(u);
651 if (!p)
652 return -ENOMEM;
663996b3 653
60f067b4
JS
654 /* Send a properties changed signal. First for the specific
655 * type, then for the generic unit. The clients may rely on
656 * this order to get atomic behavior if needed. */
663996b3 657
60f067b4
JS
658 r = sd_bus_emit_properties_changed_strv(
659 bus, p,
660 UNIT_VTABLE(u)->bus_interface,
661 NULL);
662 if (r < 0)
663 return r;
663996b3 664
60f067b4
JS
665 return sd_bus_emit_properties_changed_strv(
666 bus, p,
667 "org.freedesktop.systemd1.Unit",
668 NULL);
669}
663996b3
MS
670
671void bus_unit_send_change_signal(Unit *u) {
14228c0d 672 int r;
663996b3
MS
673 assert(u);
674
675 if (u->in_dbus_queue) {
60f067b4 676 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
663996b3
MS
677 u->in_dbus_queue = false;
678 }
679
680 if (!u->id)
681 return;
682
60f067b4
JS
683 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
684 if (r < 0)
685 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
663996b3 686
60f067b4
JS
687 u->sent_dbus_new_signal = true;
688}
663996b3 689
60f067b4
JS
690static int send_removed_signal(sd_bus *bus, void *userdata) {
691 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
692 _cleanup_free_ char *p = NULL;
693 Unit *u = userdata;
694 int r;
663996b3 695
60f067b4
JS
696 assert(bus);
697 assert(u);
663996b3 698
60f067b4
JS
699 p = unit_dbus_path(u);
700 if (!u)
701 return -ENOMEM;
663996b3 702
60f067b4
JS
703 r = sd_bus_message_new_signal(
704 bus,
705 &m,
706 "/org/freedesktop/systemd1",
707 "org.freedesktop.systemd1.Manager",
708 "UnitRemoved");
709 if (r < 0)
710 return r;
663996b3 711
60f067b4
JS
712 r = sd_bus_message_append(m, "so", u->id, p);
713 if (r < 0)
714 return r;
663996b3 715
60f067b4 716 return sd_bus_send(bus, m, NULL);
663996b3
MS
717}
718
719void bus_unit_send_removed_signal(Unit *u) {
60f067b4 720 int r;
663996b3
MS
721 assert(u);
722
663996b3
MS
723 if (!u->sent_dbus_new_signal)
724 bus_unit_send_change_signal(u);
725
726 if (!u->id)
727 return;
728
60f067b4
JS
729 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
730 if (r < 0)
731 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
663996b3
MS
732}
733
60f067b4
JS
734int bus_unit_queue_job(
735 sd_bus *bus,
736 sd_bus_message *message,
663996b3
MS
737 Unit *u,
738 JobType type,
739 JobMode mode,
60f067b4
JS
740 bool reload_if_possible,
741 sd_bus_error *error) {
663996b3 742
663996b3
MS
743 _cleanup_free_ char *path = NULL;
744 Job *j;
663996b3
MS
745 int r;
746
60f067b4 747 assert(bus);
663996b3
MS
748 assert(message);
749 assert(u);
750 assert(type >= 0 && type < _JOB_TYPE_MAX);
751 assert(mode >= 0 && mode < _JOB_MODE_MAX);
752
663996b3
MS
753 if (reload_if_possible && unit_can_reload(u)) {
754 if (type == JOB_RESTART)
755 type = JOB_RELOAD_OR_START;
756 else if (type == JOB_TRY_RESTART)
757 type = JOB_RELOAD;
758 }
759
5eef597e 760 r = mac_selinux_unit_access_check(
60f067b4
JS
761 u, message,
762 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
763 type == JOB_STOP ? "stop" : "reload", error);
764 if (r < 0)
765 return r;
663996b3 766
60f067b4
JS
767 if (type == JOB_STOP &&
768 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
769 unit_active_state(u) == UNIT_INACTIVE)
770 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
663996b3
MS
771
772 if ((type == JOB_START && u->refuse_manual_start) ||
773 (type == JOB_STOP && u->refuse_manual_stop) ||
60f067b4
JS
774 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
775 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
663996b3 776
60f067b4 777 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
663996b3 778 if (r < 0)
60f067b4 779 return r;
663996b3 780
60f067b4 781 if (bus == u->manager->api_bus) {
5eef597e
MP
782 if (!j->clients) {
783 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
60f067b4
JS
784 if (r < 0)
785 return r;
786 }
663996b3 787
5eef597e 788 r = sd_bus_track_add_sender(j->clients, message);
60f067b4
JS
789 if (r < 0)
790 return r;
791 }
663996b3
MS
792
793 path = job_dbus_path(j);
794 if (!path)
60f067b4 795 return -ENOMEM;
663996b3 796
60f067b4 797 return sd_bus_reply_method_return(message, "o", path);
663996b3
MS
798}
799
14228c0d
MB
800static int bus_unit_set_transient_property(
801 Unit *u,
802 const char *name,
60f067b4 803 sd_bus_message *message,
14228c0d 804 UnitSetPropertiesMode mode,
60f067b4 805 sd_bus_error *error) {
663996b3 806
663996b3
MS
807 int r;
808
809 assert(u);
14228c0d 810 assert(name);
60f067b4 811 assert(message);
663996b3 812
14228c0d 813 if (streq(name, "Description")) {
60f067b4 814 const char *d;
663996b3 815
60f067b4
JS
816 r = sd_bus_message_read(message, "s", &d);
817 if (r < 0)
818 return r;
663996b3 819
60f067b4
JS
820 if (mode != UNIT_CHECK) {
821 r = unit_set_description(u, d);
14228c0d
MB
822 if (r < 0)
823 return r;
663996b3 824
60f067b4 825 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
14228c0d 826 }
663996b3 827
14228c0d 828 return 1;
663996b3 829
14228c0d
MB
830 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
831 const char *s;
663996b3 832
60f067b4
JS
833 r = sd_bus_message_read(message, "s", &s);
834 if (r < 0)
835 return r;
663996b3 836
60f067b4
JS
837 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
838 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
663996b3 839
14228c0d
MB
840 if (isempty(s)) {
841 if (mode != UNIT_CHECK) {
842 unit_ref_unset(&u->slice);
843 unit_remove_drop_in(u, mode, name);
844 }
845 } else {
846 Unit *slice;
663996b3 847
14228c0d
MB
848 r = manager_load_unit(u->manager, s, NULL, error, &slice);
849 if (r < 0)
850 return r;
663996b3 851
14228c0d
MB
852 if (slice->type != UNIT_SLICE)
853 return -EINVAL;
663996b3 854
14228c0d
MB
855 if (mode != UNIT_CHECK) {
856 unit_ref_set(&u->slice, slice);
857 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
858 }
859 }
663996b3 860
14228c0d
MB
861 return 1;
862
863 } else if (streq(name, "Requires") ||
864 streq(name, "RequiresOverridable") ||
865 streq(name, "Requisite") ||
866 streq(name, "RequisiteOverridable") ||
867 streq(name, "Wants") ||
868 streq(name, "BindsTo") ||
869 streq(name, "Conflicts") ||
870 streq(name, "Before") ||
871 streq(name, "After") ||
872 streq(name, "OnFailure") ||
873 streq(name, "PropagatesReloadTo") ||
874 streq(name, "ReloadPropagatedFrom") ||
875 streq(name, "PartOf")) {
876
877 UnitDependency d;
60f067b4 878 const char *other;
14228c0d
MB
879
880 d = unit_dependency_from_string(name);
881 if (d < 0)
882 return -EINVAL;
663996b3 883
60f067b4
JS
884 r = sd_bus_message_enter_container(message, 'a', "s");
885 if (r < 0)
886 return r;
663996b3 887
60f067b4
JS
888 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
889 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
890 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
663996b3 891
14228c0d
MB
892 if (mode != UNIT_CHECK) {
893 _cleanup_free_ char *label = NULL;
663996b3 894
14228c0d
MB
895 r = unit_add_dependency_by_name(u, d, other, NULL, true);
896 if (r < 0)
897 return r;
663996b3 898
14228c0d
MB
899 label = strjoin(name, "-", other, NULL);
900 if (!label)
901 return -ENOMEM;
663996b3 902
14228c0d
MB
903 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
904 }
663996b3 905
14228c0d 906 }
60f067b4
JS
907 if (r < 0)
908 return r;
909
910 r = sd_bus_message_exit_container(message);
911 if (r < 0)
912 return r;
663996b3 913
14228c0d 914 return 1;
663996b3
MS
915 }
916
917 return 0;
918}
919
14228c0d
MB
920int bus_unit_set_properties(
921 Unit *u,
60f067b4 922 sd_bus_message *message,
14228c0d
MB
923 UnitSetPropertiesMode mode,
924 bool commit,
60f067b4 925 sd_bus_error *error) {
14228c0d
MB
926
927 bool for_real = false;
14228c0d 928 unsigned n = 0;
663996b3
MS
929 int r;
930
931 assert(u);
60f067b4 932 assert(message);
663996b3 933
14228c0d
MB
934 /* We iterate through the array twice. First run we just check
935 * if all passed data is valid, second run actually applies
936 * it. This is to implement transaction-like behaviour without
937 * actually providing full transactions. */
663996b3 938
60f067b4
JS
939 r = sd_bus_message_enter_container(message, 'a', "(sv)");
940 if (r < 0)
941 return r;
663996b3 942
14228c0d 943 for (;;) {
14228c0d 944 const char *name;
663996b3 945
60f067b4
JS
946 r = sd_bus_message_enter_container(message, 'r', "sv");
947 if (r < 0)
948 return r;
949 if (r == 0) {
14228c0d
MB
950 if (for_real || mode == UNIT_CHECK)
951 break;
663996b3 952
14228c0d 953 /* Reached EOF. Let's try again, and this time for realz... */
60f067b4
JS
954 r = sd_bus_message_rewind(message, false);
955 if (r < 0)
956 return r;
957
14228c0d 958 for_real = true;
663996b3 959 continue;
663996b3 960 }
663996b3 961
60f067b4
JS
962 r = sd_bus_message_read(message, "s", &name);
963 if (r < 0)
964 return r;
663996b3 965
60f067b4
JS
966 if (!UNIT_VTABLE(u)->bus_set_property)
967 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
663996b3 968
60f067b4
JS
969 r = sd_bus_message_enter_container(message, 'v', NULL);
970 if (r < 0)
971 return r;
663996b3 972
60f067b4 973 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
14228c0d 974 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
60f067b4 975 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
663996b3
MS
976 if (r < 0)
977 return r;
60f067b4
JS
978 if (r == 0)
979 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
663996b3 980
60f067b4
JS
981 r = sd_bus_message_exit_container(message);
982 if (r < 0)
983 return r;
984
985 r = sd_bus_message_exit_container(message);
986 if (r < 0)
987 return r;
663996b3 988
14228c0d
MB
989 n += for_real;
990 }
663996b3 991
60f067b4
JS
992 r = sd_bus_message_exit_container(message);
993 if (r < 0)
994 return r;
995
14228c0d
MB
996 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
997 UNIT_VTABLE(u)->bus_commit_properties(u);
663996b3 998
14228c0d 999 return n;
663996b3 1000}