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