]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-unit.c
Imported Upstream version 227
[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"
f47781d8 27#include "bus-common-errors.h"
d9dfd233 28#include "special.h"
60f067b4 29#include "dbus.h"
60f067b4 30#include "dbus-unit.h"
663996b3 31
60f067b4
JS
32static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
33static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
5eef597e 34static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
60f067b4
JS
35
36static int property_get_names(
37 sd_bus *bus,
38 const char *path,
39 const char *interface,
40 const char *property,
41 sd_bus_message *reply,
42 void *userdata,
43 sd_bus_error *error) {
44
45 Unit *u = userdata;
46 Iterator i;
47 const char *t;
48 int r;
663996b3 49
60f067b4
JS
50 assert(bus);
51 assert(reply);
52 assert(u);
663996b3 53
60f067b4
JS
54 r = sd_bus_message_open_container(reply, 'a', "s");
55 if (r < 0)
56 return r;
663996b3 57
60f067b4
JS
58 SET_FOREACH(t, u->names, i) {
59 r = sd_bus_message_append(reply, "s", t);
60 if (r < 0)
61 return r;
62 }
663996b3 63
60f067b4 64 return sd_bus_message_close_container(reply);
663996b3
MS
65}
66
60f067b4
JS
67static int property_get_following(
68 sd_bus *bus,
69 const char *path,
70 const char *interface,
71 const char *property,
72 sd_bus_message *reply,
73 void *userdata,
74 sd_bus_error *error) {
75
76 Unit *u = userdata, *f;
663996b3 77
60f067b4
JS
78 assert(bus);
79 assert(reply);
663996b3
MS
80 assert(u);
81
82 f = unit_following(u);
60f067b4 83 return sd_bus_message_append(reply, "s", f ? f->id : "");
663996b3
MS
84}
85
60f067b4
JS
86static int property_get_dependencies(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
92 void *userdata,
93 sd_bus_error *error) {
14228c0d 94
60f067b4 95 Set *s = *(Set**) userdata;
663996b3 96 Iterator j;
60f067b4
JS
97 Unit *u;
98 int r;
663996b3 99
60f067b4
JS
100 assert(bus);
101 assert(reply);
663996b3 102
60f067b4
JS
103 r = sd_bus_message_open_container(reply, 'a', "s");
104 if (r < 0)
105 return r;
663996b3 106
60f067b4
JS
107 SET_FOREACH(u, s, j) {
108 r = sd_bus_message_append(reply, "s", u->id);
109 if (r < 0)
110 return r;
111 }
663996b3 112
60f067b4 113 return sd_bus_message_close_container(reply);
663996b3
MS
114}
115
60f067b4
JS
116static int property_get_description(
117 sd_bus *bus,
118 const char *path,
119 const char *interface,
120 const char *property,
121 sd_bus_message *reply,
122 void *userdata,
123 sd_bus_error *error) {
663996b3 124
60f067b4 125 Unit *u = userdata;
663996b3 126
60f067b4
JS
127 assert(bus);
128 assert(reply);
129 assert(u);
663996b3 130
60f067b4 131 return sd_bus_message_append(reply, "s", unit_description(u));
663996b3
MS
132}
133
60f067b4
JS
134static int property_get_active_state(
135 sd_bus *bus,
136 const char *path,
137 const char *interface,
138 const char *property,
139 sd_bus_message *reply,
140 void *userdata,
141 sd_bus_error *error) {
663996b3 142
60f067b4 143 Unit *u = userdata;
663996b3 144
60f067b4
JS
145 assert(bus);
146 assert(reply);
663996b3
MS
147 assert(u);
148
60f067b4 149 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
663996b3
MS
150}
151
60f067b4
JS
152static int property_get_sub_state(
153 sd_bus *bus,
154 const char *path,
155 const char *interface,
156 const char *property,
157 sd_bus_message *reply,
158 void *userdata,
159 sd_bus_error *error) {
663996b3 160
60f067b4 161 Unit *u = userdata;
663996b3 162
60f067b4
JS
163 assert(bus);
164 assert(reply);
165 assert(u);
663996b3 166
60f067b4 167 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
663996b3
MS
168}
169
f47781d8
MP
170static int property_get_unit_file_preset(
171 sd_bus *bus,
172 const char *path,
173 const char *interface,
174 const char *property,
175 sd_bus_message *reply,
176 void *userdata,
177 sd_bus_error *error) {
178
179 Unit *u = userdata;
180 int r;
181
182 assert(bus);
183 assert(reply);
184 assert(u);
185
186 r = unit_get_unit_file_preset(u);
187
188 return sd_bus_message_append(reply, "s",
189 r < 0 ? "":
190 r > 0 ? "enabled" : "disabled");
191}
192
60f067b4
JS
193static int property_get_unit_file_state(
194 sd_bus *bus,
195 const char *path,
196 const char *interface,
197 const char *property,
198 sd_bus_message *reply,
199 void *userdata,
200 sd_bus_error *error) {
663996b3 201
60f067b4 202 Unit *u = userdata;
663996b3 203
60f067b4
JS
204 assert(bus);
205 assert(reply);
206 assert(u);
663996b3 207
60f067b4 208 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
663996b3
MS
209}
210
60f067b4
JS
211static int property_get_can_start(
212 sd_bus *bus,
213 const char *path,
214 const char *interface,
215 const char *property,
216 sd_bus_message *reply,
217 void *userdata,
218 sd_bus_error *error) {
663996b3 219
60f067b4 220 Unit *u = userdata;
663996b3 221
60f067b4
JS
222 assert(bus);
223 assert(reply);
224 assert(u);
663996b3 225
60f067b4 226 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
663996b3
MS
227}
228
60f067b4
JS
229static int property_get_can_stop(
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) {
237
238 Unit *u = userdata;
663996b3 239
60f067b4
JS
240 assert(bus);
241 assert(reply);
663996b3
MS
242 assert(u);
243
244 /* On the lower levels we assume that every unit we can start
245 * we can also stop */
246
60f067b4 247 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
663996b3
MS
248}
249
60f067b4
JS
250static int property_get_can_reload(
251 sd_bus *bus,
252 const char *path,
253 const char *interface,
254 const char *property,
255 sd_bus_message *reply,
256 void *userdata,
257 sd_bus_error *error) {
663996b3 258
60f067b4 259 Unit *u = userdata;
663996b3 260
60f067b4
JS
261 assert(bus);
262 assert(reply);
263 assert(u);
663996b3 264
60f067b4 265 return sd_bus_message_append(reply, "b", unit_can_reload(u));
663996b3
MS
266}
267
60f067b4
JS
268static int property_get_can_isolate(
269 sd_bus *bus,
270 const char *path,
271 const char *interface,
272 const char *property,
273 sd_bus_message *reply,
274 void *userdata,
275 sd_bus_error *error) {
663996b3 276
60f067b4 277 Unit *u = userdata;
663996b3 278
60f067b4
JS
279 assert(bus);
280 assert(reply);
281 assert(u);
663996b3 282
60f067b4 283 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
663996b3
MS
284}
285
60f067b4
JS
286static int property_get_job(
287 sd_bus *bus,
288 const char *path,
289 const char *interface,
290 const char *property,
291 sd_bus_message *reply,
292 void *userdata,
293 sd_bus_error *error) {
294
663996b3 295 _cleanup_free_ char *p = NULL;
60f067b4 296 Unit *u = userdata;
663996b3 297
60f067b4
JS
298 assert(bus);
299 assert(reply);
663996b3
MS
300 assert(u);
301
60f067b4
JS
302 if (!u->job)
303 return sd_bus_message_append(reply, "(uo)", 0, "/");
663996b3 304
60f067b4
JS
305 p = job_dbus_path(u->job);
306 if (!p)
663996b3
MS
307 return -ENOMEM;
308
60f067b4 309 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
663996b3
MS
310}
311
60f067b4
JS
312static int property_get_need_daemon_reload(
313 sd_bus *bus,
314 const char *path,
315 const char *interface,
316 const char *property,
317 sd_bus_message *reply,
318 void *userdata,
319 sd_bus_error *error) {
663996b3 320
60f067b4 321 Unit *u = userdata;
663996b3 322
60f067b4
JS
323 assert(bus);
324 assert(reply);
325 assert(u);
663996b3 326
60f067b4 327 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
663996b3
MS
328}
329
60f067b4
JS
330static int property_get_conditions(
331 sd_bus *bus,
332 const char *path,
333 const char *interface,
334 const char *property,
335 sd_bus_message *reply,
336 void *userdata,
337 sd_bus_error *error) {
663996b3 338
f47781d8
MP
339 const char *(*to_string)(ConditionType type) = NULL;
340 Condition **list = userdata, *c;
60f067b4 341 int r;
663996b3 342
60f067b4
JS
343 assert(bus);
344 assert(reply);
f47781d8
MP
345 assert(list);
346
347 to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
663996b3 348
60f067b4
JS
349 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
350 if (r < 0)
351 return r;
663996b3 352
f47781d8
MP
353 LIST_FOREACH(conditions, c, *list) {
354 int tristate;
355
356 tristate =
357 c->result == CONDITION_UNTESTED ? 0 :
358 c->result == CONDITION_SUCCEEDED ? 1 : -1;
359
60f067b4 360 r = sd_bus_message_append(reply, "(sbbsi)",
f47781d8 361 to_string(c->type),
60f067b4 362 c->trigger, c->negate,
f47781d8 363 c->parameter, tristate);
60f067b4
JS
364 if (r < 0)
365 return r;
14228c0d 366
60f067b4 367 }
663996b3 368
60f067b4 369 return sd_bus_message_close_container(reply);
663996b3
MS
370}
371
60f067b4
JS
372static int property_get_load_error(
373 sd_bus *bus,
374 const char *path,
375 const char *interface,
376 const char *property,
377 sd_bus_message *reply,
378 void *userdata,
379 sd_bus_error *error) {
663996b3 380
60f067b4
JS
381 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
382 Unit *u = userdata;
663996b3 383
60f067b4
JS
384 assert(bus);
385 assert(reply);
386 assert(u);
663996b3 387
60f067b4
JS
388 if (u->load_error != 0)
389 sd_bus_error_set_errno(&e, u->load_error);
663996b3 390
60f067b4 391 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
663996b3
MS
392}
393
d9dfd233
MP
394static int bus_verify_manage_units_async_full(
395 Unit *u,
396 const char *verb,
397 int capability,
398 const char *polkit_message,
399 sd_bus_message *call,
400 sd_bus_error *error) {
401
402 const char *details[9] = {
403 "unit", u->id,
404 "verb", verb,
405 };
406
407 if (polkit_message) {
408 details[4] = "polkit.message";
409 details[5] = polkit_message;
410 details[6] = "polkit.gettext_domain";
411 details[7] = GETTEXT_PACKAGE;
412 }
413
414 return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
415}
416
e3bff60a
MP
417int bus_unit_method_start_generic(
418 sd_bus_message *message,
419 Unit *u,
420 JobType job_type,
421 bool reload_if_possible,
422 sd_bus_error *error) {
423
60f067b4
JS
424 const char *smode;
425 JobMode mode;
d9dfd233
MP
426 _cleanup_free_ char *verb = NULL;
427 static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
428 [JOB_START] = N_("Authentication is required to start '$(unit)'."),
429 [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
430 [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
431 [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
432 [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
433 };
663996b3
MS
434 int r;
435
60f067b4
JS
436 assert(message);
437 assert(u);
438 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
663996b3 439
e3bff60a
MP
440 r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
441 if (r < 0)
442 return r;
443
60f067b4
JS
444 r = sd_bus_message_read(message, "s", &smode);
445 if (r < 0)
446 return r;
663996b3 447
60f067b4
JS
448 mode = job_mode_from_string(smode);
449 if (mode < 0)
450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
663996b3 451
d9dfd233
MP
452 if (reload_if_possible)
453 verb = strjoin("reload-or-", job_type_to_string(job_type), NULL);
454 else
455 verb = strdup(job_type_to_string(job_type));
456 if (!verb)
457 return -ENOMEM;
458
459 r = bus_verify_manage_units_async_full(
460 u,
461 verb,
462 CAP_SYS_ADMIN,
463 job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
464 message,
465 error);
e3bff60a
MP
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 return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
60f067b4 472}
663996b3 473
e3bff60a
MP
474static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
475 return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
60f067b4 476}
663996b3 477
e3bff60a
MP
478static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
479 return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
60f067b4 480}
663996b3 481
e3bff60a
MP
482static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
483 return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
60f067b4 484}
663996b3 485
e3bff60a
MP
486static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
487 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
60f067b4 488}
663996b3 489
e3bff60a
MP
490static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
491 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
60f067b4 492}
663996b3 493
e3bff60a
MP
494static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
495 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
60f067b4 496}
663996b3 497
e3bff60a
MP
498static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
499 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
60f067b4 500}
663996b3 501
e3bff60a 502int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
503 Unit *u = userdata;
504 const char *swho;
505 int32_t signo;
506 KillWho who;
507 int r;
663996b3 508
60f067b4
JS
509 assert(message);
510 assert(u);
663996b3 511
e3bff60a 512 r = mac_selinux_unit_access_check(u, message, "stop", error);
5eef597e
MP
513 if (r < 0)
514 return r;
5eef597e 515
60f067b4
JS
516 r = sd_bus_message_read(message, "si", &swho, &signo);
517 if (r < 0)
518 return r;
519
520 if (isempty(swho))
521 who = KILL_ALL;
522 else {
523 who = kill_who_from_string(swho);
524 if (who < 0)
525 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
663996b3
MS
526 }
527
60f067b4
JS
528 if (signo <= 0 || signo >= _NSIG)
529 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
530
d9dfd233
MP
531 r = bus_verify_manage_units_async_full(
532 u,
533 "kill",
534 CAP_KILL,
535 N_("Authentication is required to kill '$(unit)'."),
536 message,
537 error);
60f067b4
JS
538 if (r < 0)
539 return r;
e3bff60a
MP
540 if (r == 0)
541 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 542
60f067b4
JS
543 r = unit_kill(u, who, signo, error);
544 if (r < 0)
545 return r;
663996b3 546
60f067b4 547 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
548}
549
e3bff60a 550int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4 551 Unit *u = userdata;
663996b3 552 int r;
663996b3 553
663996b3 554 assert(message);
60f067b4 555 assert(u);
663996b3 556
e3bff60a 557 r = mac_selinux_unit_access_check(u, message, "reload", error);
5eef597e
MP
558 if (r < 0)
559 return r;
5eef597e 560
d9dfd233
MP
561 r = bus_verify_manage_units_async_full(
562 u,
563 "reset-failed",
564 CAP_SYS_ADMIN,
565 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
566 message,
567 error);
60f067b4
JS
568 if (r < 0)
569 return r;
e3bff60a
MP
570 if (r == 0)
571 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 572
60f067b4 573 unit_reset_failed(u);
663996b3 574
60f067b4
JS
575 return sd_bus_reply_method_return(message, NULL);
576}
663996b3 577
e3bff60a 578int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
579 Unit *u = userdata;
580 int runtime, r;
663996b3 581
60f067b4
JS
582 assert(message);
583 assert(u);
663996b3 584
e3bff60a 585 r = mac_selinux_unit_access_check(u, message, "start", error);
5eef597e
MP
586 if (r < 0)
587 return r;
5eef597e 588
60f067b4
JS
589 r = sd_bus_message_read(message, "b", &runtime);
590 if (r < 0)
591 return r;
663996b3 592
d9dfd233
MP
593 r = bus_verify_manage_units_async_full(
594 u,
595 "set-property",
596 CAP_SYS_ADMIN,
597 N_("Authentication is required to set properties on '$(unit)'."),
598 message,
599 error);
60f067b4
JS
600 if (r < 0)
601 return r;
e3bff60a
MP
602 if (r == 0)
603 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 604
60f067b4
JS
605 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
606 if (r < 0)
607 return r;
663996b3 608
60f067b4
JS
609 return sd_bus_reply_method_return(message, NULL);
610}
663996b3 611
60f067b4
JS
612const sd_bus_vtable bus_unit_vtable[] = {
613 SD_BUS_VTABLE_START(0),
614
615 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
616 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
617 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
618 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
619 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
620 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
621 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
622 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
623 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
624 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
625 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
626 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
e3bff60a
MP
627 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
628 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4
JS
629 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
630 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
631 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
632 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
633 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
634 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
635 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
636 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
637 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
638 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
639 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
640 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
641 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
642 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
643 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
644 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
645 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
646 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
647 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
648 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
649 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
650 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
651 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
f47781d8 652 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
60f067b4
JS
653 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
654 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
655 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
656 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
657 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
658 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
659 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
660 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
661 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
662 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
663 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
664 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
665 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
666 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
667 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
668 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
669 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
670 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
671 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
5eef597e
MP
672 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
673 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4 674 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f47781d8 675 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4 676 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f47781d8
MP
677 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
678 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
679 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
60f067b4
JS
680 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
681 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
6300502b 682 SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0),
60f067b4 683
e3bff60a
MP
684 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
685 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
686 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
687 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
688 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
689 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
690 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
691 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
692 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
693 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
60f067b4
JS
694
695 SD_BUS_VTABLE_END
696};
663996b3 697
60f067b4
JS
698static int property_get_slice(
699 sd_bus *bus,
700 const char *path,
701 const char *interface,
702 const char *property,
703 sd_bus_message *reply,
704 void *userdata,
705 sd_bus_error *error) {
663996b3 706
60f067b4 707 Unit *u = userdata;
663996b3 708
60f067b4
JS
709 assert(bus);
710 assert(reply);
711 assert(u);
663996b3 712
60f067b4
JS
713 return sd_bus_message_append(reply, "s", unit_slice_name(u));
714}
663996b3 715
e735f4d4
MP
716static int property_get_current_memory(
717 sd_bus *bus,
718 const char *path,
719 const char *interface,
720 const char *property,
721 sd_bus_message *reply,
722 void *userdata,
723 sd_bus_error *error) {
724
e735f4d4 725 uint64_t sz = (uint64_t) -1;
e3bff60a 726 Unit *u = userdata;
e735f4d4
MP
727 int r;
728
729 assert(bus);
730 assert(reply);
731 assert(u);
732
e3bff60a
MP
733 r = unit_get_memory_current(u, &sz);
734 if (r < 0 && r != -ENODATA)
735 log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m");
e735f4d4 736
e3bff60a
MP
737 return sd_bus_message_append(reply, "t", sz);
738}
e735f4d4 739
6300502b
MP
740static int property_get_current_tasks(
741 sd_bus *bus,
742 const char *path,
743 const char *interface,
744 const char *property,
745 sd_bus_message *reply,
746 void *userdata,
747 sd_bus_error *error) {
748
749 uint64_t cn = (uint64_t) -1;
750 Unit *u = userdata;
751 int r;
752
753 assert(bus);
754 assert(reply);
755 assert(u);
756
757 r = unit_get_tasks_current(u, &cn);
758 if (r < 0 && r != -ENODATA)
759 log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
760
761 return sd_bus_message_append(reply, "t", cn);
762}
763
e3bff60a
MP
764static int property_get_cpu_usage(
765 sd_bus *bus,
766 const char *path,
767 const char *interface,
768 const char *property,
769 sd_bus_message *reply,
770 void *userdata,
771 sd_bus_error *error) {
e735f4d4 772
e3bff60a
MP
773 nsec_t ns = (nsec_t) -1;
774 Unit *u = userdata;
775 int r;
776
777 assert(bus);
778 assert(reply);
779 assert(u);
780
781 r = unit_get_cpu_usage(u, &ns);
782 if (r < 0 && r != -ENODATA)
783 log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m");
784
785 return sd_bus_message_append(reply, "t", ns);
e735f4d4
MP
786}
787
13d276d0
MP
788static int property_get_cgroup(
789 sd_bus *bus,
790 const char *path,
791 const char *interface,
792 const char *property,
793 sd_bus_message *reply,
794 void *userdata,
795 sd_bus_error *error) {
796
797 Unit *u = userdata;
798 const char *t;
799
800 assert(bus);
801 assert(reply);
802 assert(u);
803
804 /* Three cases: a) u->cgroup_path is NULL, in which case the
805 * unit has no control group, which we report as the empty
806 * string. b) u->cgroup_path is the empty string, which
807 * indicates the root cgroup, which we report as "/". c) all
808 * other cases we report as-is. */
809
810 if (u->cgroup_path)
811 t = isempty(u->cgroup_path) ? "/" : u->cgroup_path;
812 else
813 t = "";
814
815 return sd_bus_message_append(reply, "s", t);
816}
817
60f067b4
JS
818const sd_bus_vtable bus_unit_cgroup_vtable[] = {
819 SD_BUS_VTABLE_START(0),
820 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
13d276d0 821 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
e735f4d4 822 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
e3bff60a 823 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
6300502b 824 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
60f067b4
JS
825 SD_BUS_VTABLE_END
826};
663996b3 827
60f067b4
JS
828static int send_new_signal(sd_bus *bus, void *userdata) {
829 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
830 _cleanup_free_ char *p = NULL;
831 Unit *u = userdata;
832 int r;
663996b3 833
60f067b4
JS
834 assert(bus);
835 assert(u);
663996b3 836
60f067b4 837 p = unit_dbus_path(u);
e3bff60a 838 if (!p)
60f067b4 839 return -ENOMEM;
663996b3 840
60f067b4
JS
841 r = sd_bus_message_new_signal(
842 bus,
843 &m,
844 "/org/freedesktop/systemd1",
845 "org.freedesktop.systemd1.Manager",
846 "UnitNew");
847 if (r < 0)
848 return r;
663996b3 849
60f067b4
JS
850 r = sd_bus_message_append(m, "so", u->id, p);
851 if (r < 0)
852 return r;
663996b3 853
60f067b4
JS
854 return sd_bus_send(bus, m, NULL);
855}
663996b3 856
60f067b4
JS
857static int send_changed_signal(sd_bus *bus, void *userdata) {
858 _cleanup_free_ char *p = NULL;
859 Unit *u = userdata;
860 int r;
663996b3 861
60f067b4
JS
862 assert(bus);
863 assert(u);
663996b3 864
60f067b4
JS
865 p = unit_dbus_path(u);
866 if (!p)
867 return -ENOMEM;
663996b3 868
60f067b4
JS
869 /* Send a properties changed signal. First for the specific
870 * type, then for the generic unit. The clients may rely on
871 * this order to get atomic behavior if needed. */
663996b3 872
60f067b4
JS
873 r = sd_bus_emit_properties_changed_strv(
874 bus, p,
d9dfd233 875 unit_dbus_interface_from_type(u->type),
60f067b4
JS
876 NULL);
877 if (r < 0)
878 return r;
663996b3 879
60f067b4
JS
880 return sd_bus_emit_properties_changed_strv(
881 bus, p,
882 "org.freedesktop.systemd1.Unit",
883 NULL);
884}
663996b3
MS
885
886void bus_unit_send_change_signal(Unit *u) {
14228c0d 887 int r;
663996b3
MS
888 assert(u);
889
890 if (u->in_dbus_queue) {
60f067b4 891 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
663996b3
MS
892 u->in_dbus_queue = false;
893 }
894
895 if (!u->id)
896 return;
897
60f067b4
JS
898 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
899 if (r < 0)
e3bff60a 900 log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id);
663996b3 901
60f067b4
JS
902 u->sent_dbus_new_signal = true;
903}
663996b3 904
60f067b4
JS
905static int send_removed_signal(sd_bus *bus, void *userdata) {
906 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
907 _cleanup_free_ char *p = NULL;
908 Unit *u = userdata;
909 int r;
663996b3 910
60f067b4
JS
911 assert(bus);
912 assert(u);
663996b3 913
60f067b4 914 p = unit_dbus_path(u);
e3bff60a 915 if (!p)
60f067b4 916 return -ENOMEM;
663996b3 917
60f067b4
JS
918 r = sd_bus_message_new_signal(
919 bus,
920 &m,
921 "/org/freedesktop/systemd1",
922 "org.freedesktop.systemd1.Manager",
923 "UnitRemoved");
924 if (r < 0)
925 return r;
663996b3 926
60f067b4
JS
927 r = sd_bus_message_append(m, "so", u->id, p);
928 if (r < 0)
929 return r;
663996b3 930
60f067b4 931 return sd_bus_send(bus, m, NULL);
663996b3
MS
932}
933
934void bus_unit_send_removed_signal(Unit *u) {
60f067b4 935 int r;
663996b3
MS
936 assert(u);
937
663996b3
MS
938 if (!u->sent_dbus_new_signal)
939 bus_unit_send_change_signal(u);
940
941 if (!u->id)
942 return;
943
60f067b4
JS
944 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
945 if (r < 0)
e3bff60a 946 log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
663996b3
MS
947}
948
60f067b4 949int bus_unit_queue_job(
60f067b4 950 sd_bus_message *message,
663996b3
MS
951 Unit *u,
952 JobType type,
953 JobMode mode,
60f067b4
JS
954 bool reload_if_possible,
955 sd_bus_error *error) {
663996b3 956
663996b3
MS
957 _cleanup_free_ char *path = NULL;
958 Job *j;
663996b3
MS
959 int r;
960
663996b3
MS
961 assert(message);
962 assert(u);
963 assert(type >= 0 && type < _JOB_TYPE_MAX);
964 assert(mode >= 0 && mode < _JOB_MODE_MAX);
965
663996b3
MS
966 if (reload_if_possible && unit_can_reload(u)) {
967 if (type == JOB_RESTART)
968 type = JOB_RELOAD_OR_START;
969 else if (type == JOB_TRY_RESTART)
970 type = JOB_RELOAD;
971 }
972
5eef597e 973 r = mac_selinux_unit_access_check(
60f067b4
JS
974 u, message,
975 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
976 type == JOB_STOP ? "stop" : "reload", error);
977 if (r < 0)
978 return r;
663996b3 979
60f067b4
JS
980 if (type == JOB_STOP &&
981 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
982 unit_active_state(u) == UNIT_INACTIVE)
983 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
663996b3
MS
984
985 if ((type == JOB_START && u->refuse_manual_start) ||
986 (type == JOB_STOP && u->refuse_manual_stop) ||
60f067b4
JS
987 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
988 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
663996b3 989
60f067b4 990 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
663996b3 991 if (r < 0)
60f067b4 992 return r;
663996b3 993
e3bff60a 994 if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
5eef597e 995 if (!j->clients) {
e3bff60a 996 r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL);
60f067b4
JS
997 if (r < 0)
998 return r;
999 }
663996b3 1000
5eef597e 1001 r = sd_bus_track_add_sender(j->clients, message);
60f067b4
JS
1002 if (r < 0)
1003 return r;
1004 }
663996b3
MS
1005
1006 path = job_dbus_path(j);
1007 if (!path)
60f067b4 1008 return -ENOMEM;
663996b3 1009
60f067b4 1010 return sd_bus_reply_method_return(message, "o", path);
663996b3
MS
1011}
1012
14228c0d
MB
1013static int bus_unit_set_transient_property(
1014 Unit *u,
1015 const char *name,
60f067b4 1016 sd_bus_message *message,
14228c0d 1017 UnitSetPropertiesMode mode,
60f067b4 1018 sd_bus_error *error) {
663996b3 1019
663996b3
MS
1020 int r;
1021
1022 assert(u);
14228c0d 1023 assert(name);
60f067b4 1024 assert(message);
663996b3 1025
14228c0d 1026 if (streq(name, "Description")) {
60f067b4 1027 const char *d;
663996b3 1028
60f067b4
JS
1029 r = sd_bus_message_read(message, "s", &d);
1030 if (r < 0)
1031 return r;
663996b3 1032
60f067b4
JS
1033 if (mode != UNIT_CHECK) {
1034 r = unit_set_description(u, d);
14228c0d
MB
1035 if (r < 0)
1036 return r;
663996b3 1037
60f067b4 1038 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
14228c0d 1039 }
663996b3 1040
14228c0d 1041 return 1;
e735f4d4
MP
1042
1043 } else if (streq(name, "DefaultDependencies")) {
1044 int b;
1045
1046 r = sd_bus_message_read(message, "b", &b);
1047 if (r < 0)
1048 return r;
1049
1050 if (mode != UNIT_CHECK) {
1051 u->default_dependencies = b;
1052 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
1053 }
1054
1055 return 1;
663996b3 1056
d9dfd233
MP
1057 } else if (streq(name, "Slice")) {
1058 Unit *slice;
14228c0d 1059 const char *s;
663996b3 1060
d9dfd233
MP
1061 if (!UNIT_HAS_CGROUP_CONTEXT(u))
1062 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
1063 if (u->type == UNIT_SLICE)
1064 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
1065 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
1066 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
1067
60f067b4
JS
1068 r = sd_bus_message_read(message, "s", &s);
1069 if (r < 0)
1070 return r;
663996b3 1071
d9dfd233
MP
1072 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
1073 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
663996b3 1074
d9dfd233
MP
1075 r = manager_load_unit(u->manager, s, NULL, error, &slice);
1076 if (r < 0)
1077 return r;
663996b3 1078
d9dfd233
MP
1079 if (slice->type != UNIT_SLICE)
1080 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
1081
1082 if (mode != UNIT_CHECK) {
1083 r = unit_set_slice(u, slice);
14228c0d
MB
1084 if (r < 0)
1085 return r;
663996b3 1086
d9dfd233 1087 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
14228c0d 1088 }
663996b3 1089
14228c0d 1090 return 1;
d9dfd233 1091
f47781d8
MP
1092 } else if (STR_IN_SET(name,
1093 "Requires", "RequiresOverridable",
1094 "Requisite", "RequisiteOverridable",
1095 "Wants",
1096 "BindsTo",
1097 "Conflicts",
1098 "Before", "After",
1099 "OnFailure",
1100 "PropagatesReloadTo", "ReloadPropagatedFrom",
1101 "PartOf")) {
14228c0d
MB
1102
1103 UnitDependency d;
60f067b4 1104 const char *other;
14228c0d
MB
1105
1106 d = unit_dependency_from_string(name);
1107 if (d < 0)
1108 return -EINVAL;
663996b3 1109
60f067b4
JS
1110 r = sd_bus_message_enter_container(message, 'a', "s");
1111 if (r < 0)
1112 return r;
663996b3 1113
60f067b4 1114 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
e3bff60a 1115 if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
60f067b4 1116 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
663996b3 1117
14228c0d
MB
1118 if (mode != UNIT_CHECK) {
1119 _cleanup_free_ char *label = NULL;
663996b3 1120
14228c0d
MB
1121 r = unit_add_dependency_by_name(u, d, other, NULL, true);
1122 if (r < 0)
1123 return r;
663996b3 1124
14228c0d
MB
1125 label = strjoin(name, "-", other, NULL);
1126 if (!label)
1127 return -ENOMEM;
663996b3 1128
14228c0d
MB
1129 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1130 }
663996b3 1131
14228c0d 1132 }
60f067b4
JS
1133 if (r < 0)
1134 return r;
1135
1136 r = sd_bus_message_exit_container(message);
1137 if (r < 0)
1138 return r;
663996b3 1139
14228c0d 1140 return 1;
663996b3
MS
1141 }
1142
1143 return 0;
1144}
1145
14228c0d
MB
1146int bus_unit_set_properties(
1147 Unit *u,
60f067b4 1148 sd_bus_message *message,
14228c0d
MB
1149 UnitSetPropertiesMode mode,
1150 bool commit,
60f067b4 1151 sd_bus_error *error) {
14228c0d
MB
1152
1153 bool for_real = false;
14228c0d 1154 unsigned n = 0;
663996b3
MS
1155 int r;
1156
1157 assert(u);
60f067b4 1158 assert(message);
663996b3 1159
14228c0d
MB
1160 /* We iterate through the array twice. First run we just check
1161 * if all passed data is valid, second run actually applies
1162 * it. This is to implement transaction-like behaviour without
1163 * actually providing full transactions. */
663996b3 1164
60f067b4
JS
1165 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1166 if (r < 0)
1167 return r;
663996b3 1168
14228c0d 1169 for (;;) {
14228c0d 1170 const char *name;
663996b3 1171
60f067b4
JS
1172 r = sd_bus_message_enter_container(message, 'r', "sv");
1173 if (r < 0)
1174 return r;
1175 if (r == 0) {
14228c0d
MB
1176 if (for_real || mode == UNIT_CHECK)
1177 break;
663996b3 1178
14228c0d 1179 /* Reached EOF. Let's try again, and this time for realz... */
60f067b4
JS
1180 r = sd_bus_message_rewind(message, false);
1181 if (r < 0)
1182 return r;
1183
14228c0d 1184 for_real = true;
663996b3 1185 continue;
663996b3 1186 }
663996b3 1187
60f067b4
JS
1188 r = sd_bus_message_read(message, "s", &name);
1189 if (r < 0)
1190 return r;
663996b3 1191
60f067b4
JS
1192 if (!UNIT_VTABLE(u)->bus_set_property)
1193 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
663996b3 1194
60f067b4
JS
1195 r = sd_bus_message_enter_container(message, 'v', NULL);
1196 if (r < 0)
1197 return r;
663996b3 1198
60f067b4 1199 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
14228c0d 1200 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
60f067b4 1201 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
663996b3
MS
1202 if (r < 0)
1203 return r;
60f067b4
JS
1204 if (r == 0)
1205 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
663996b3 1206
60f067b4
JS
1207 r = sd_bus_message_exit_container(message);
1208 if (r < 0)
1209 return r;
1210
1211 r = sd_bus_message_exit_container(message);
1212 if (r < 0)
1213 return r;
663996b3 1214
14228c0d
MB
1215 n += for_real;
1216 }
663996b3 1217
60f067b4
JS
1218 r = sd_bus_message_exit_container(message);
1219 if (r < 0)
1220 return r;
1221
14228c0d
MB
1222 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1223 UNIT_VTABLE(u)->bus_commit_properties(u);
663996b3 1224
14228c0d 1225 return n;
663996b3 1226}