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