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