]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-unit.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / dbus-unit.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
a7334b09 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
718db961 21#include "sd-bus.h"
07630cea 22
b5efdb8a 23#include "alloc-util.h"
906c06f6 24#include "bpf-firewall.h"
07630cea
LP
25#include "bus-common-errors.h"
26#include "cgroup-util.h"
c5a97ed1 27#include "dbus-job.h"
8752c575 28#include "dbus-unit.h"
07630cea 29#include "dbus.h"
291d565a 30#include "fd-util.h"
8752c575 31#include "locale-util.h"
ea430986 32#include "log.h"
291d565a 33#include "process-util.h"
e2417e41 34#include "selinux-access.h"
6eb7c172 35#include "signal-util.h"
efdb0237 36#include "special.h"
07630cea
LP
37#include "string-util.h"
38#include "strv.h"
ee104e11 39#include "user-util.h"
718db961 40
5afe510c 41static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode);
718db961 42static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
d420282b 43static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
87a47f99 44static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
718db961
LP
45
46static int property_get_names(
47 sd_bus *bus,
48 const char *path,
49 const char *interface,
50 const char *property,
51 sd_bus_message *reply,
ebcf1f97
LP
52 void *userdata,
53 sd_bus_error *error) {
718db961
LP
54
55 Unit *u = userdata;
56 Iterator i;
57 const char *t;
58 int r;
ea430986 59
718db961
LP
60 assert(bus);
61 assert(reply);
62 assert(u);
4139c1b2 63
718db961
LP
64 r = sd_bus_message_open_container(reply, 'a', "s");
65 if (r < 0)
66 return r;
4139c1b2 67
718db961
LP
68 SET_FOREACH(t, u->names, i) {
69 r = sd_bus_message_append(reply, "s", t);
70 if (r < 0)
71 return r;
72 }
4139c1b2 73
718db961 74 return sd_bus_message_close_container(reply);
4139c1b2
LP
75}
76
718db961
LP
77static int property_get_following(
78 sd_bus *bus,
79 const char *path,
80 const char *interface,
81 const char *property,
82 sd_bus_message *reply,
ebcf1f97
LP
83 void *userdata,
84 sd_bus_error *error) {
718db961
LP
85
86 Unit *u = userdata, *f;
8fe914ec 87
718db961
LP
88 assert(bus);
89 assert(reply);
8fe914ec
LP
90 assert(u);
91
a7f241db 92 f = unit_following(u);
718db961 93 return sd_bus_message_append(reply, "s", f ? f->id : "");
8fe914ec
LP
94}
95
718db961
LP
96static int property_get_dependencies(
97 sd_bus *bus,
98 const char *path,
99 const char *interface,
100 const char *property,
101 sd_bus_message *reply,
ebcf1f97
LP
102 void *userdata,
103 sd_bus_error *error) {
4ec9a8a4 104
eef85c4a 105 Hashmap *h = *(Hashmap**) userdata;
5301be81 106 Iterator j;
718db961 107 Unit *u;
eef85c4a 108 void *v;
718db961 109 int r;
5301be81 110
718db961
LP
111 assert(bus);
112 assert(reply);
5301be81 113
718db961
LP
114 r = sd_bus_message_open_container(reply, 'a', "s");
115 if (r < 0)
116 return r;
5301be81 117
eef85c4a 118 HASHMAP_FOREACH_KEY(v, u, h, j) {
718db961
LP
119 r = sd_bus_message_append(reply, "s", u->id);
120 if (r < 0)
121 return r;
122 }
5301be81 123
718db961 124 return sd_bus_message_close_container(reply);
5301be81
LP
125}
126
f32b43bd
LP
127static int property_get_obsolete_dependencies(
128 sd_bus *bus,
129 const char *path,
130 const char *interface,
131 const char *property,
132 sd_bus_message *reply,
133 void *userdata,
134 sd_bus_error *error) {
135
136 assert(bus);
137 assert(reply);
138
139 /* For dependency types we don't support anymore always return an empty array */
140 return sd_bus_message_append(reply, "as", 0);
141}
142
99c14018
YW
143static int property_get_requires_mounts_for(
144 sd_bus *bus,
145 const char *path,
146 const char *interface,
147 const char *property,
148 sd_bus_message *reply,
149 void *userdata,
150 sd_bus_error *error) {
151
f6e11b39 152 Hashmap *h = *(Hashmap**) userdata;
99c14018 153 const char *p;
f6e11b39 154 Iterator j;
99c14018
YW
155 void *v;
156 int r;
157
158 assert(bus);
159 assert(reply);
160
161 r = sd_bus_message_open_container(reply, 'a', "s");
162 if (r < 0)
163 return r;
164
165 HASHMAP_FOREACH_KEY(v, p, h, j) {
166 r = sd_bus_message_append(reply, "s", p);
167 if (r < 0)
168 return r;
169 }
170
171 return sd_bus_message_close_container(reply);
172}
173
718db961
LP
174static int property_get_description(
175 sd_bus *bus,
176 const char *path,
177 const char *interface,
178 const char *property,
179 sd_bus_message *reply,
ebcf1f97
LP
180 void *userdata,
181 sd_bus_error *error) {
ea430986 182
718db961 183 Unit *u = userdata;
ea430986 184
718db961
LP
185 assert(bus);
186 assert(reply);
187 assert(u);
ea430986 188
718db961 189 return sd_bus_message_append(reply, "s", unit_description(u));
ea430986
LP
190}
191
718db961
LP
192static int property_get_active_state(
193 sd_bus *bus,
194 const char *path,
195 const char *interface,
196 const char *property,
197 sd_bus_message *reply,
ebcf1f97
LP
198 void *userdata,
199 sd_bus_error *error) {
ea430986 200
718db961 201 Unit *u = userdata;
ea430986 202
718db961
LP
203 assert(bus);
204 assert(reply);
ea430986
LP
205 assert(u);
206
718db961 207 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
ea430986
LP
208}
209
718db961
LP
210static int property_get_sub_state(
211 sd_bus *bus,
212 const char *path,
213 const char *interface,
214 const char *property,
215 sd_bus_message *reply,
ebcf1f97
LP
216 void *userdata,
217 sd_bus_error *error) {
10a94420 218
718db961 219 Unit *u = userdata;
10a94420 220
718db961
LP
221 assert(bus);
222 assert(reply);
223 assert(u);
10a94420 224
718db961 225 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
10a94420
LP
226}
227
d2dc52db
LP
228static int property_get_unit_file_preset(
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 Unit *u = userdata;
238 int r;
239
240 assert(bus);
241 assert(reply);
242 assert(u);
243
244 r = unit_get_unit_file_preset(u);
245
246 return sd_bus_message_append(reply, "s",
247 r < 0 ? "":
248 r > 0 ? "enabled" : "disabled");
249}
250
718db961
LP
251static int property_get_unit_file_state(
252 sd_bus *bus,
253 const char *path,
254 const char *interface,
255 const char *property,
256 sd_bus_message *reply,
ebcf1f97
LP
257 void *userdata,
258 sd_bus_error *error) {
a4375746 259
718db961 260 Unit *u = userdata;
a4375746 261
718db961
LP
262 assert(bus);
263 assert(reply);
264 assert(u);
a4375746 265
76445832 266 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
a4375746
LP
267}
268
718db961
LP
269static int property_get_can_start(
270 sd_bus *bus,
271 const char *path,
272 const char *interface,
273 const char *property,
274 sd_bus_message *reply,
ebcf1f97
LP
275 void *userdata,
276 sd_bus_error *error) {
38131695 277
718db961 278 Unit *u = userdata;
b5e9dba8 279
718db961
LP
280 assert(bus);
281 assert(reply);
282 assert(u);
b5e9dba8 283
718db961 284 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
b5e9dba8
LP
285}
286
718db961
LP
287static int property_get_can_stop(
288 sd_bus *bus,
289 const char *path,
290 const char *interface,
291 const char *property,
292 sd_bus_message *reply,
ebcf1f97
LP
293 void *userdata,
294 sd_bus_error *error) {
718db961
LP
295
296 Unit *u = userdata;
b5e9dba8 297
718db961
LP
298 assert(bus);
299 assert(reply);
b5e9dba8
LP
300 assert(u);
301
f5869324 302 return sd_bus_message_append(reply, "b", unit_can_stop(u) && !u->refuse_manual_stop);
38131695
LP
303}
304
718db961
LP
305static int property_get_can_reload(
306 sd_bus *bus,
307 const char *path,
308 const char *interface,
309 const char *property,
310 sd_bus_message *reply,
ebcf1f97
LP
311 void *userdata,
312 sd_bus_error *error) {
38131695 313
718db961 314 Unit *u = userdata;
38131695 315
718db961
LP
316 assert(bus);
317 assert(reply);
318 assert(u);
38131695 319
718db961 320 return sd_bus_message_append(reply, "b", unit_can_reload(u));
38131695
LP
321}
322
718db961
LP
323static int property_get_can_isolate(
324 sd_bus *bus,
325 const char *path,
326 const char *interface,
327 const char *property,
328 sd_bus_message *reply,
ebcf1f97
LP
329 void *userdata,
330 sd_bus_error *error) {
2528a7a6 331
718db961 332 Unit *u = userdata;
2528a7a6 333
718db961
LP
334 assert(bus);
335 assert(reply);
336 assert(u);
2528a7a6 337
718db961 338 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
2528a7a6
LP
339}
340
718db961
LP
341static int property_get_job(
342 sd_bus *bus,
343 const char *path,
344 const char *interface,
345 const char *property,
346 sd_bus_message *reply,
ebcf1f97
LP
347 void *userdata,
348 sd_bus_error *error) {
718db961 349
f93891f3 350 _cleanup_free_ char *p = NULL;
718db961 351 Unit *u = userdata;
38131695 352
718db961
LP
353 assert(bus);
354 assert(reply);
38131695
LP
355 assert(u);
356
718db961
LP
357 if (!u->job)
358 return sd_bus_message_append(reply, "(uo)", 0, "/");
38131695 359
718db961
LP
360 p = job_dbus_path(u->job);
361 if (!p)
362 return -ENOMEM;
38131695 363
718db961
LP
364 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
365}
38131695 366
718db961
LP
367static int property_get_need_daemon_reload(
368 sd_bus *bus,
369 const char *path,
370 const char *interface,
371 const char *property,
372 sd_bus_message *reply,
ebcf1f97
LP
373 void *userdata,
374 sd_bus_error *error) {
38131695 375
718db961 376 Unit *u = userdata;
38131695 377
718db961
LP
378 assert(bus);
379 assert(reply);
380 assert(u);
38131695 381
718db961 382 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
38131695
LP
383}
384
718db961
LP
385static int property_get_conditions(
386 sd_bus *bus,
387 const char *path,
388 const char *interface,
389 const char *property,
390 sd_bus_message *reply,
ebcf1f97
LP
391 void *userdata,
392 sd_bus_error *error) {
45fb0699 393
59fccdc5
LP
394 const char *(*to_string)(ConditionType type) = NULL;
395 Condition **list = userdata, *c;
718db961 396 int r;
45fb0699 397
718db961
LP
398 assert(bus);
399 assert(reply);
59fccdc5
LP
400 assert(list);
401
402 to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
45fb0699 403
718db961
LP
404 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
405 if (r < 0)
406 return r;
45fb0699 407
59fccdc5 408 LIST_FOREACH(conditions, c, *list) {
cc50ef13
LP
409 int tristate;
410
411 tristate =
412 c->result == CONDITION_UNTESTED ? 0 :
413 c->result == CONDITION_SUCCEEDED ? 1 : -1;
414
2c7e050f 415 r = sd_bus_message_append(reply, "(sbbsi)",
59fccdc5 416 to_string(c->type),
2c7e050f 417 c->trigger, c->negate,
cc50ef13 418 c->parameter, tristate);
718db961
LP
419 if (r < 0)
420 return r;
45fb0699 421
718db961 422 }
52990c2e 423
718db961 424 return sd_bus_message_close_container(reply);
52990c2e
ZJS
425}
426
718db961
LP
427static int property_get_load_error(
428 sd_bus *bus,
429 const char *path,
430 const char *interface,
431 const char *property,
432 sd_bus_message *reply,
ebcf1f97
LP
433 void *userdata,
434 sd_bus_error *error) {
52990c2e 435
4afd3348 436 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
718db961 437 Unit *u = userdata;
52990c2e 438
718db961
LP
439 assert(bus);
440 assert(reply);
441 assert(u);
52990c2e 442
718db961
LP
443 if (u->load_error != 0)
444 sd_bus_error_set_errno(&e, u->load_error);
52990c2e 445
718db961 446 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
52990c2e
ZJS
447}
448
88ced61b
MC
449static int bus_verify_manage_units_async_full(
450 Unit *u,
451 const char *verb,
452 int capability,
453 const char *polkit_message,
05a98afd 454 bool interactive,
88ced61b
MC
455 sd_bus_message *call,
456 sd_bus_error *error) {
457
458 const char *details[9] = {
459 "unit", u->id,
460 "verb", verb,
461 };
462
463 if (polkit_message) {
464 details[4] = "polkit.message";
465 details[5] = polkit_message;
466 details[6] = "polkit.gettext_domain";
467 details[7] = GETTEXT_PACKAGE;
468 }
469
05a98afd
LP
470 return bus_verify_polkit_async(
471 call,
472 capability,
473 "org.freedesktop.systemd1.manage-units",
474 details,
475 interactive,
476 UID_INVALID,
477 &u->manager->polkit_registry,
478 error);
88ced61b
MC
479}
480
1d22e906 481int bus_unit_method_start_generic(
1d22e906
LP
482 sd_bus_message *message,
483 Unit *u,
484 JobType job_type,
485 bool reload_if_possible,
486 sd_bus_error *error) {
487
718db961
LP
488 const char *smode;
489 JobMode mode;
88ced61b
MC
490 _cleanup_free_ char *verb = NULL;
491 static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
492 [JOB_START] = N_("Authentication is required to start '$(unit)'."),
493 [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
494 [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
495 [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
496 [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
497 };
718db961 498 int r;
9f39404c 499
718db961 500 assert(message);
9f39404c 501 assert(u);
718db961 502 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
9f39404c 503
61ea63f1
EV
504 r = mac_selinux_unit_access_check(
505 u, message,
94bd7323
EV
506 job_type_to_access_method(job_type),
507 error);
1d22e906
LP
508 if (r < 0)
509 return r;
510
718db961
LP
511 r = sd_bus_message_read(message, "s", &smode);
512 if (r < 0)
ebcf1f97 513 return r;
9f39404c 514
718db961
LP
515 mode = job_mode_from_string(smode);
516 if (mode < 0)
ebcf1f97 517 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
9f39404c 518
88ced61b 519 if (reload_if_possible)
605405c6 520 verb = strjoin("reload-or-", job_type_to_string(job_type));
88ced61b
MC
521 else
522 verb = strdup(job_type_to_string(job_type));
523 if (!verb)
524 return -ENOMEM;
525
526 r = bus_verify_manage_units_async_full(
527 u,
528 verb,
529 CAP_SYS_ADMIN,
530 job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
05a98afd 531 true,
88ced61b
MC
532 message,
533 error);
1d22e906
LP
534 if (r < 0)
535 return r;
536 if (r == 0)
537 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
538
19070062 539 return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
9f39404c
LP
540}
541
19070062
LP
542static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
543 return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
718db961 544}
b548631a 545
19070062
LP
546static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
547 return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
718db961
LP
548}
549
19070062
LP
550static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
551 return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
718db961 552}
0a524ba7 553
19070062
LP
554static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
555 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
718db961 556}
8a0867d6 557
19070062
LP
558static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
559 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
718db961 560}
cad45ba1 561
19070062
LP
562static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
563 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
718db961 564}
8a0867d6 565
19070062
LP
566static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
567 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
718db961 568}
8a0867d6 569
19070062 570int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
571 Unit *u = userdata;
572 const char *swho;
573 int32_t signo;
574 KillWho who;
575 int r;
5632e374 576
718db961
LP
577 assert(message);
578 assert(u);
cad45ba1 579
1d22e906 580 r = mac_selinux_unit_access_check(u, message, "stop", error);
283868e1
SW
581 if (r < 0)
582 return r;
283868e1 583
718db961
LP
584 r = sd_bus_message_read(message, "si", &swho, &signo);
585 if (r < 0)
ebcf1f97 586 return r;
718db961
LP
587
588 if (isempty(swho))
589 who = KILL_ALL;
590 else {
591 who = kill_who_from_string(swho);
592 if (who < 0)
ebcf1f97 593 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
718db961 594 }
5632e374 595
6eb7c172 596 if (!SIGNAL_VALID(signo))
ebcf1f97 597 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
8e2af478 598
88ced61b
MC
599 r = bus_verify_manage_units_async_full(
600 u,
601 "kill",
602 CAP_KILL,
603 N_("Authentication is required to kill '$(unit)'."),
05a98afd 604 true,
88ced61b
MC
605 message,
606 error);
ebcf1f97
LP
607 if (r < 0)
608 return r;
1d22e906
LP
609 if (r == 0)
610 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
8e2af478 611
ebcf1f97 612 r = unit_kill(u, who, signo, error);
718db961 613 if (r < 0)
ebcf1f97 614 return r;
8e2af478 615
df2d202e 616 return sd_bus_reply_method_return(message, NULL);
718db961 617}
8e2af478 618
19070062 619int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 620 Unit *u = userdata;
ebcf1f97 621 int r;
b548631a 622
718db961
LP
623 assert(message);
624 assert(u);
b548631a 625
1d22e906 626 r = mac_selinux_unit_access_check(u, message, "reload", error);
283868e1
SW
627 if (r < 0)
628 return r;
283868e1 629
88ced61b
MC
630 r = bus_verify_manage_units_async_full(
631 u,
632 "reset-failed",
633 CAP_SYS_ADMIN,
634 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
05a98afd 635 true,
88ced61b
MC
636 message,
637 error);
ebcf1f97
LP
638 if (r < 0)
639 return r;
1d22e906
LP
640 if (r == 0)
641 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
b548631a 642
718db961 643 unit_reset_failed(u);
b548631a 644
df2d202e 645 return sd_bus_reply_method_return(message, NULL);
ea430986
LP
646}
647
19070062 648int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
649 Unit *u = userdata;
650 int runtime, r;
ea430986 651
ea430986 652 assert(message);
718db961 653 assert(u);
80fbf05e 654
1d22e906 655 r = mac_selinux_unit_access_check(u, message, "start", error);
283868e1
SW
656 if (r < 0)
657 return r;
283868e1 658
718db961
LP
659 r = sd_bus_message_read(message, "b", &runtime);
660 if (r < 0)
ebcf1f97 661 return r;
2cccbca4 662
88ced61b
MC
663 r = bus_verify_manage_units_async_full(
664 u,
665 "set-property",
666 CAP_SYS_ADMIN,
667 N_("Authentication is required to set properties on '$(unit)'."),
05a98afd 668 true,
88ced61b
MC
669 message,
670 error);
ebcf1f97
LP
671 if (r < 0)
672 return r;
1d22e906
LP
673 if (r == 0)
674 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
cad45ba1 675
ebcf1f97 676 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
718db961 677 if (r < 0)
ebcf1f97 678 return r;
2cccbca4 679
df2d202e 680 return sd_bus_reply_method_return(message, NULL);
718db961 681}
2cccbca4 682
05a98afd
LP
683int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
684 Unit *u = userdata;
685 int r;
686
687 assert(message);
688 assert(u);
689
690 r = mac_selinux_unit_access_check(u, message, "start", error);
691 if (r < 0)
692 return r;
693
694 r = bus_verify_manage_units_async_full(
695 u,
696 "ref",
697 CAP_SYS_ADMIN,
698 NULL,
699 false,
700 message,
701 error);
702 if (r < 0)
703 return r;
704 if (r == 0)
705 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
706
707 r = bus_unit_track_add_sender(u, message);
708 if (r < 0)
709 return r;
710
711 return sd_bus_reply_method_return(message, NULL);
712}
713
714int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
715 Unit *u = userdata;
716 int r;
717
718 assert(message);
719 assert(u);
720
721 r = bus_unit_track_remove_sender(u, message);
722 if (r == -EUNATCH)
723 return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
724 if (r < 0)
725 return r;
726
727 return sd_bus_reply_method_return(message, NULL);
728}
729
718db961
LP
730const sd_bus_vtable bus_unit_vtable[] = {
731 SD_BUS_VTABLE_START(0),
732
556089dc
LP
733 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
734 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 735 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
556089dc 736 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc 737 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
738 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
739 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
740 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
741 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
be7d9ff7 742 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
743 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
744 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
745 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
746 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
747 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
748 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
749 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
750 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
751 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
752 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
753 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
754 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
755 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
99c14018 756 SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
757 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
758 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
759 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
760 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
761 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
762 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
763 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
764 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 765 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
d2dc52db 766 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
a483fb59 767 BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
718db961
LP
768 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
769 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
770 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
771 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
772 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
773 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
774 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
775 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 776 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
777 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
778 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
779 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
780 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
781 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
782 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
783 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
784 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
785 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
a2df3ea4 786 SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
87a47f99 787 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
f189ab18 788 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 789 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
59fccdc5 790 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
718db961 791 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
59fccdc5
LP
792 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
793 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
794 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
556089dc
LP
795 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
796 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
f5869324 797 SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST),
f0367da7 798 SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
6bf0f408 799 SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
87a47f99 800 SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
6bf0f408 801 SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
4b58153d 802 SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0),
5afe510c 803 SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), 0),
718db961 804
1d22e906
LP
805 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
806 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
807 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
808 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
809 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
810 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
811 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
812 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
813 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
814 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
05a98afd
LP
815 SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED),
816 SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED),
718db961 817
51d73fd9
LP
818 /* Obsolete properties or obsolete alias names */
819 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
820 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
821 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
822 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
823 SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
718db961
LP
824 SD_BUS_VTABLE_END
825};
2cccbca4 826
718db961
LP
827static int property_get_slice(
828 sd_bus *bus,
829 const char *path,
830 const char *interface,
831 const char *property,
832 sd_bus_message *reply,
ebcf1f97
LP
833 void *userdata,
834 sd_bus_error *error) {
2cccbca4 835
718db961 836 Unit *u = userdata;
2cccbca4 837
718db961
LP
838 assert(bus);
839 assert(reply);
840 assert(u);
2cccbca4 841
718db961
LP
842 return sd_bus_message_append(reply, "s", unit_slice_name(u));
843}
2cccbca4 844
934277fe
LP
845static int property_get_current_memory(
846 sd_bus *bus,
847 const char *path,
848 const char *interface,
849 const char *property,
850 sd_bus_message *reply,
851 void *userdata,
852 sd_bus_error *error) {
853
934277fe 854 uint64_t sz = (uint64_t) -1;
5ad096b3 855 Unit *u = userdata;
934277fe
LP
856 int r;
857
858 assert(bus);
859 assert(reply);
860 assert(u);
861
5ad096b3
LP
862 r = unit_get_memory_current(u, &sz);
863 if (r < 0 && r != -ENODATA)
f2341e0a 864 log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m");
934277fe 865
5ad096b3
LP
866 return sd_bus_message_append(reply, "t", sz);
867}
934277fe 868
03a7b521
LP
869static int property_get_current_tasks(
870 sd_bus *bus,
871 const char *path,
872 const char *interface,
873 const char *property,
874 sd_bus_message *reply,
875 void *userdata,
876 sd_bus_error *error) {
877
878 uint64_t cn = (uint64_t) -1;
879 Unit *u = userdata;
880 int r;
881
882 assert(bus);
883 assert(reply);
884 assert(u);
885
886 r = unit_get_tasks_current(u, &cn);
887 if (r < 0 && r != -ENODATA)
888 log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
889
890 return sd_bus_message_append(reply, "t", cn);
891}
892
5ad096b3
LP
893static int property_get_cpu_usage(
894 sd_bus *bus,
895 const char *path,
896 const char *interface,
897 const char *property,
898 sd_bus_message *reply,
899 void *userdata,
900 sd_bus_error *error) {
934277fe 901
5ad096b3
LP
902 nsec_t ns = (nsec_t) -1;
903 Unit *u = userdata;
904 int r;
905
906 assert(bus);
907 assert(reply);
908 assert(u);
909
910 r = unit_get_cpu_usage(u, &ns);
911 if (r < 0 && r != -ENODATA)
f2341e0a 912 log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m");
5ad096b3
LP
913
914 return sd_bus_message_append(reply, "t", ns);
934277fe
LP
915}
916
98bac605
LP
917static int property_get_cgroup(
918 sd_bus *bus,
919 const char *path,
920 const char *interface,
921 const char *property,
922 sd_bus_message *reply,
923 void *userdata,
924 sd_bus_error *error) {
925
926 Unit *u = userdata;
927 const char *t;
928
929 assert(bus);
930 assert(reply);
931 assert(u);
932
933 /* Three cases: a) u->cgroup_path is NULL, in which case the
934 * unit has no control group, which we report as the empty
935 * string. b) u->cgroup_path is the empty string, which
936 * indicates the root cgroup, which we report as "/". c) all
937 * other cases we report as-is. */
938
939 if (u->cgroup_path)
940 t = isempty(u->cgroup_path) ? "/" : u->cgroup_path;
941 else
942 t = "";
943
944 return sd_bus_message_append(reply, "s", t);
945}
946
291d565a
LP
947static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) {
948 _cleanup_free_ char *buf = NULL, *cmdline = NULL;
949 int r;
950
951 assert(reply);
952 assert(pid > 0);
953
954 r = set_put(pids, PID_TO_PTR(pid));
4c701096 955 if (IN_SET(r, 0, -EEXIST))
291d565a
LP
956 return 0;
957 if (r < 0)
958 return r;
959
960 if (!p) {
961 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf);
962 if (r == -ESRCH)
963 return 0;
964 if (r < 0)
965 return r;
966
967 p = buf;
968 }
969
970 (void) get_process_cmdline(pid, 0, true, &cmdline);
971
972 return sd_bus_message_append(reply,
973 "(sus)",
974 p,
975 (uint32_t) pid,
976 cmdline);
977}
978
979static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
980 _cleanup_closedir_ DIR *d = NULL;
981 _cleanup_fclose_ FILE *f = NULL;
982 int r;
983
984 assert(reply);
985 assert(p);
986
987 r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
988 if (r == ENOENT)
989 return 0;
990 if (r < 0)
991 return r;
992
993 for (;;) {
994 pid_t pid;
995
996 r = cg_read_pid(f, &pid);
997 if (r < 0)
998 return r;
999 if (r == 0)
1000 break;
1001
1002 if (is_kernel_thread(pid) > 0)
1003 continue;
1004
1005 r = append_process(reply, p, pid, pids);
1006 if (r < 0)
1007 return r;
1008 }
1009
1010 r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d);
1011 if (r == -ENOENT)
1012 return 0;
1013 if (r < 0)
1014 return r;
1015
1016 for (;;) {
1017 _cleanup_free_ char *g = NULL, *j = NULL;
1018
1019 r = cg_read_subgroup(d, &g);
1020 if (r < 0)
1021 return r;
1022 if (r == 0)
1023 break;
1024
605405c6 1025 j = strjoin(p, "/", g);
291d565a
LP
1026 if (!j)
1027 return -ENOMEM;
1028
1029 r = append_cgroup(reply, j, pids);
1030 if (r < 0)
1031 return r;
1032 }
1033
1034 return 0;
1035}
1036
1037int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1038 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1039 _cleanup_(set_freep) Set *pids = NULL;
291d565a
LP
1040 Unit *u = userdata;
1041 pid_t pid;
1042 int r;
1043
1044 assert(message);
1045
807fa5d9
LP
1046 r = mac_selinux_unit_access_check(u, message, "status", error);
1047 if (r < 0)
1048 return r;
1049
291d565a
LP
1050 pids = set_new(NULL);
1051 if (!pids)
1052 return -ENOMEM;
1053
1054 r = sd_bus_message_new_method_return(message, &reply);
1055 if (r < 0)
1056 return r;
1057
1058 r = sd_bus_message_open_container(reply, 'a', "(sus)");
1059 if (r < 0)
1060 return r;
1061
1062 if (u->cgroup_path) {
1063 r = append_cgroup(reply, u->cgroup_path, pids);
1064 if (r < 0)
1065 return r;
1066 }
1067
1068 /* The main and control pids might live outside of the cgroup, hence fetch them separately */
1069 pid = unit_main_pid(u);
1070 if (pid > 0) {
1071 r = append_process(reply, NULL, pid, pids);
1072 if (r < 0)
1073 return r;
1074 }
1075
1076 pid = unit_control_pid(u);
1077 if (pid > 0) {
1078 r = append_process(reply, NULL, pid, pids);
1079 if (r < 0)
1080 return r;
1081 }
1082
1083 r = sd_bus_message_close_container(reply);
1084 if (r < 0)
1085 return r;
1086
1087 return sd_bus_send(NULL, reply, NULL);
1088}
1089
906c06f6
DM
1090static int property_get_ip_counter(
1091 sd_bus *bus,
1092 const char *path,
1093 const char *interface,
1094 const char *property,
1095 sd_bus_message *reply,
1096 void *userdata,
1097 sd_bus_error *error) {
1098
1099 CGroupIPAccountingMetric metric;
1100 uint64_t value = (uint64_t) -1;
1101 Unit *u = userdata;
1102
1103 assert(bus);
1104 assert(reply);
1105 assert(property);
1106 assert(u);
1107
1108 if (streq(property, "IPIngressBytes"))
1109 metric = CGROUP_IP_INGRESS_BYTES;
1110 else if (streq(property, "IPIngressPackets"))
1111 metric = CGROUP_IP_INGRESS_PACKETS;
1112 else if (streq(property, "IPEgressBytes"))
1113 metric = CGROUP_IP_EGRESS_BYTES;
1114 else {
1115 assert(streq(property, "IPEgressPackets"));
1116 metric = CGROUP_IP_EGRESS_PACKETS;
1117 }
1118
1119 (void) unit_get_ip_accounting(u, metric, &value);
1120 return sd_bus_message_append(reply, "t", value);
1121}
1122
718db961
LP
1123const sd_bus_vtable bus_unit_cgroup_vtable[] = {
1124 SD_BUS_VTABLE_START(0),
1125 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
98bac605 1126 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
934277fe 1127 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
5ad096b3 1128 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
03a7b521 1129 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
906c06f6
DM
1130 SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0),
1131 SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0),
1132 SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0),
1133 SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0),
291d565a 1134 SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
718db961
LP
1135 SD_BUS_VTABLE_END
1136};
2cccbca4 1137
8f8f05a9 1138static int send_new_signal(sd_bus *bus, void *userdata) {
4afd3348 1139 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
718db961
LP
1140 _cleanup_free_ char *p = NULL;
1141 Unit *u = userdata;
1142 int r;
2cccbca4 1143
718db961
LP
1144 assert(bus);
1145 assert(u);
2cccbca4 1146
718db961 1147 p = unit_dbus_path(u);
e861098b 1148 if (!p)
718db961 1149 return -ENOMEM;
2cccbca4 1150
718db961
LP
1151 r = sd_bus_message_new_signal(
1152 bus,
151b9b96 1153 &m,
718db961
LP
1154 "/org/freedesktop/systemd1",
1155 "org.freedesktop.systemd1.Manager",
151b9b96 1156 "UnitNew");
718db961
LP
1157 if (r < 0)
1158 return r;
2cccbca4 1159
718db961
LP
1160 r = sd_bus_message_append(m, "so", u->id, p);
1161 if (r < 0)
1162 return r;
2cccbca4 1163
8f8f05a9 1164 return sd_bus_send(bus, m, NULL);
718db961 1165}
2cccbca4 1166
8f8f05a9 1167static int send_changed_signal(sd_bus *bus, void *userdata) {
718db961
LP
1168 _cleanup_free_ char *p = NULL;
1169 Unit *u = userdata;
1170 int r;
2cccbca4 1171
718db961
LP
1172 assert(bus);
1173 assert(u);
2cccbca4 1174
718db961 1175 p = unit_dbus_path(u);
9ceefc81 1176 if (!p)
718db961 1177 return -ENOMEM;
2cccbca4 1178
718db961
LP
1179 /* Send a properties changed signal. First for the specific
1180 * type, then for the generic unit. The clients may rely on
1181 * this order to get atomic behavior if needed. */
ea430986 1182
aec8de63
LP
1183 r = sd_bus_emit_properties_changed_strv(
1184 bus, p,
21b735e7 1185 unit_dbus_interface_from_type(u->type),
aec8de63 1186 NULL);
fe7f06f1 1187 if (r < 0)
aec8de63 1188 return r;
80fbf05e 1189
fe7f06f1 1190 return sd_bus_emit_properties_changed_strv(
718db961
LP
1191 bus, p,
1192 "org.freedesktop.systemd1.Unit",
718db961 1193 NULL);
ea430986
LP
1194}
1195
c1e1601e 1196void bus_unit_send_change_signal(Unit *u) {
b170dd80 1197 int r;
c1e1601e 1198 assert(u);
c1e1601e 1199
ac155bb8 1200 if (u->in_dbus_queue) {
71fda00f 1201 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
ac155bb8 1202 u->in_dbus_queue = false;
c0bd0cf7 1203 }
c1e1601e 1204
ac155bb8 1205 if (!u->id)
04ade7d2
LP
1206 return;
1207
ae572acd 1208 r = bus_foreach_bus(u->manager, u->bus_track, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
718db961 1209 if (r < 0)
f2341e0a 1210 log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id);
c1e1601e 1211
718db961
LP
1212 u->sent_dbus_new_signal = true;
1213}
c4e2ceae 1214
8f8f05a9 1215static int send_removed_signal(sd_bus *bus, void *userdata) {
4afd3348 1216 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
718db961
LP
1217 _cleanup_free_ char *p = NULL;
1218 Unit *u = userdata;
1219 int r;
c4e2ceae 1220
718db961
LP
1221 assert(bus);
1222 assert(u);
c1e1601e 1223
718db961 1224 p = unit_dbus_path(u);
e861098b 1225 if (!p)
718db961 1226 return -ENOMEM;
c1e1601e 1227
718db961
LP
1228 r = sd_bus_message_new_signal(
1229 bus,
151b9b96 1230 &m,
718db961
LP
1231 "/org/freedesktop/systemd1",
1232 "org.freedesktop.systemd1.Manager",
151b9b96 1233 "UnitRemoved");
718db961
LP
1234 if (r < 0)
1235 return r;
c1e1601e 1236
718db961
LP
1237 r = sd_bus_message_append(m, "so", u->id, p);
1238 if (r < 0)
1239 return r;
c1e1601e 1240
8f8f05a9 1241 return sd_bus_send(bus, m, NULL);
c1e1601e
LP
1242}
1243
1244void bus_unit_send_removed_signal(Unit *u) {
718db961 1245 int r;
c1e1601e
LP
1246 assert(u);
1247
0dd99f86 1248 if (!u->sent_dbus_new_signal || u->in_dbus_queue)
7535cc78
LP
1249 bus_unit_send_change_signal(u);
1250
ac155bb8 1251 if (!u->id)
04ade7d2
LP
1252 return;
1253
ae572acd 1254 r = bus_foreach_bus(u->manager, u->bus_track, send_removed_signal, u);
718db961 1255 if (r < 0)
f2341e0a 1256 log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
c1e1601e 1257}
e2110e5d 1258
718db961 1259int bus_unit_queue_job(
718db961 1260 sd_bus_message *message,
cad45ba1
LP
1261 Unit *u,
1262 JobType type,
1263 JobMode mode,
ebcf1f97
LP
1264 bool reload_if_possible,
1265 sd_bus_error *error) {
cad45ba1 1266
cad45ba1
LP
1267 _cleanup_free_ char *path = NULL;
1268 Job *j;
cad45ba1
LP
1269 int r;
1270
cad45ba1
LP
1271 assert(message);
1272 assert(u);
1273 assert(type >= 0 && type < _JOB_TYPE_MAX);
1274 assert(mode >= 0 && mode < _JOB_MODE_MAX);
1275
f596e00f
EV
1276 r = mac_selinux_unit_access_check(
1277 u, message,
1278 job_type_to_access_method(type),
1279 error);
1280 if (r < 0)
1281 return r;
1282
cad45ba1
LP
1283 if (reload_if_possible && unit_can_reload(u)) {
1284 if (type == JOB_RESTART)
1285 type = JOB_RELOAD_OR_START;
1286 else if (type == JOB_TRY_RESTART)
3282591d 1287 type = JOB_TRY_RELOAD;
cad45ba1
LP
1288 }
1289
718db961 1290 if (type == JOB_STOP &&
3742095b 1291 (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR)) &&
718db961 1292 unit_active_state(u) == UNIT_INACTIVE)
ebcf1f97 1293 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
cad45ba1
LP
1294
1295 if ((type == JOB_START && u->refuse_manual_start) ||
1296 (type == JOB_STOP && u->refuse_manual_stop) ||
3742095b 1297 (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
efb30ba1 1298 (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
7e974e85 1299 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
cad45ba1 1300
4bd29fe5 1301 r = manager_add_job(u->manager, type, u, mode, error, &j);
cad45ba1 1302 if (r < 0)
ebcf1f97 1303 return r;
cad45ba1 1304
c5a97ed1
LP
1305 r = bus_job_track_sender(j, message);
1306 if (r < 0)
1307 return r;
cad45ba1
LP
1308
1309 path = job_dbus_path(j);
1310 if (!path)
6ce270b1 1311 return -ENOMEM;
cad45ba1 1312
df2d202e 1313 return sd_bus_reply_method_return(message, "o", path);
cad45ba1
LP
1314}
1315
9f2e86af
LP
1316static int bus_unit_set_transient_property(
1317 Unit *u,
1318 const char *name,
718db961 1319 sd_bus_message *message,
9f2e86af 1320 UnitSetPropertiesMode mode,
718db961 1321 sd_bus_error *error) {
9f2e86af
LP
1322
1323 int r;
1324
1325 assert(u);
1326 assert(name);
718db961 1327 assert(message);
9f2e86af
LP
1328
1329 if (streq(name, "Description")) {
718db961 1330 const char *d;
9f2e86af 1331
718db961
LP
1332 r = sd_bus_message_read(message, "s", &d);
1333 if (r < 0)
1334 return r;
8aec412f 1335
718db961
LP
1336 if (mode != UNIT_CHECK) {
1337 r = unit_set_description(u, d);
8aec412f
LP
1338 if (r < 0)
1339 return r;
b9316fb0 1340
b27b4b51 1341 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d);
8aec412f 1342 }
9f2e86af
LP
1343
1344 return 1;
261420ba
LP
1345
1346 } else if (streq(name, "DefaultDependencies")) {
1347 int b;
1348
1349 r = sd_bus_message_read(message, "b", &b);
1350 if (r < 0)
1351 return r;
1352
1353 if (mode != UNIT_CHECK) {
1354 u->default_dependencies = b;
b27b4b51 1355 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b));
261420ba
LP
1356 }
1357
1358 return 1;
c221420b 1359
5afe510c
LP
1360 } else if (streq(name, "CollectMode")) {
1361 const char *s;
1362 CollectMode m;
1363
1364 r = sd_bus_message_read(message, "s", &s);
1365 if (r < 0)
1366 return r;
1367
1368 m = collect_mode_from_string(s);
1369 if (m < 0)
1370 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown garbage collection mode: %s", s);
1371
1372 if (mode != UNIT_CHECK) {
1373 u->collect_mode = m;
1374 unit_write_drop_in_format(u, mode, name, "[Unit]\nCollectMode=%s", collect_mode_to_string(m));
1375 }
1376
1377 return 1;
1378
d79200e2
LP
1379 } else if (streq(name, "Slice")) {
1380 Unit *slice;
c221420b 1381 const char *s;
c221420b 1382
d79200e2
LP
1383 if (!UNIT_HAS_CGROUP_CONTEXT(u))
1384 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
1385 if (u->type == UNIT_SLICE)
1386 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
efdb0237
LP
1387 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
1388 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
d79200e2 1389
718db961
LP
1390 r = sd_bus_message_read(message, "s", &s);
1391 if (r < 0)
1392 return r;
c221420b 1393
d79200e2
LP
1394 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
1395 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
1396
aea529e5
LP
1397 /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
1398 * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare()
1399 * instead of manager_load_unit() on purpose, here. */
1400 r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice);
d79200e2
LP
1401 if (r < 0)
1402 return r;
c221420b 1403
d79200e2
LP
1404 if (slice->type != UNIT_SLICE)
1405 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
b9316fb0 1406
d79200e2
LP
1407 if (mode != UNIT_CHECK) {
1408 r = unit_set_slice(u, slice);
8aec412f
LP
1409 if (r < 0)
1410 return r;
c221420b 1411
b27b4b51 1412 unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s);
8aec412f 1413 }
b9ec9359 1414
c221420b 1415 return 1;
d79200e2 1416
311f6cf3
WC
1417 } else if (STR_IN_SET(name,
1418 "Requires", "RequiresOverridable",
1419 "Requisite", "RequisiteOverridable",
1420 "Wants",
1421 "BindsTo",
1422 "Conflicts",
1423 "Before", "After",
1424 "OnFailure",
1425 "PropagatesReloadTo", "ReloadPropagatedFrom",
1426 "PartOf")) {
7fb3ee51
LP
1427
1428 UnitDependency d;
718db961 1429 const char *other;
7fb3ee51 1430
f32b43bd
LP
1431 if (streq(name, "RequiresOverridable"))
1432 d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */
1433 else if (streq(name, "RequisiteOverridable"))
1434 d = UNIT_REQUISITE; /* same here */
1435 else {
1436 d = unit_dependency_from_string(name);
1437 if (d < 0)
1438 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name);
1439 }
7fb3ee51 1440
718db961
LP
1441 r = sd_bus_message_enter_container(message, 'a', "s");
1442 if (r < 0)
1443 return r;
7fb3ee51 1444
718db961 1445 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
7410616c 1446 if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
718db961 1447 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
7fb3ee51
LP
1448
1449 if (mode != UNIT_CHECK) {
b9ec9359 1450 _cleanup_free_ char *label = NULL;
7fb3ee51 1451
eef85c4a 1452 r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE);
7fb3ee51
LP
1453 if (r < 0)
1454 return r;
1455
605405c6 1456 label = strjoin(name, "-", other);
7fb3ee51
LP
1457 if (!label)
1458 return -ENOMEM;
1459
b27b4b51 1460 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other);
7fb3ee51
LP
1461 }
1462
7fb3ee51 1463 }
718db961
LP
1464 if (r < 0)
1465 return r;
7fb3ee51 1466
6ce270b1
LP
1467 r = sd_bus_message_exit_container(message);
1468 if (r < 0)
1469 return r;
1470
7fb3ee51 1471 return 1;
05a98afd
LP
1472
1473 } else if (streq(name, "AddRef")) {
1474
1475 int b;
1476
1477 /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
1478 * on the Unit interface, and it's probably not a good idea to expose a property and a method on the
1479 * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for
1480 * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference
1481 * dependency type, hence let's not confuse things with that.
1482 *
1483 * Note that we don't acually add the reference to the bus track. We do that only after the setup of
1484 * the transient unit is complete, so that setting this property multiple times in the same transient
1485 * unit creation call doesn't count as individual references. */
1486
1487 r = sd_bus_message_read(message, "b", &b);
1488 if (r < 0)
1489 return r;
1490
1491 if (mode != UNIT_CHECK)
1492 u->bus_track_add = b;
1493
1494 return 1;
9f2e86af
LP
1495 }
1496
1497 return 0;
1498}
1499
c2756a68
LP
1500int bus_unit_set_properties(
1501 Unit *u,
718db961 1502 sd_bus_message *message,
c2756a68
LP
1503 UnitSetPropertiesMode mode,
1504 bool commit,
718db961 1505 sd_bus_error *error) {
c2756a68 1506
8e2af478 1507 bool for_real = false;
8e2af478
LP
1508 unsigned n = 0;
1509 int r;
1510
1511 assert(u);
718db961 1512 assert(message);
8e2af478
LP
1513
1514 /* We iterate through the array twice. First run we just check
1515 * if all passed data is valid, second run actually applies
1516 * it. This is to implement transaction-like behaviour without
1517 * actually providing full transactions. */
1518
718db961
LP
1519 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1520 if (r < 0)
1521 return r;
8e2af478 1522
8e2af478 1523 for (;;) {
8e2af478
LP
1524 const char *name;
1525
718db961
LP
1526 r = sd_bus_message_enter_container(message, 'r', "sv");
1527 if (r < 0)
1528 return r;
1529 if (r == 0) {
a255a7f1 1530 if (for_real || mode == UNIT_CHECK)
8e2af478
LP
1531 break;
1532
1533 /* Reached EOF. Let's try again, and this time for realz... */
718db961
LP
1534 r = sd_bus_message_rewind(message, false);
1535 if (r < 0)
1536 return r;
6ce270b1 1537
8e2af478
LP
1538 for_real = true;
1539 continue;
1540 }
1541
718db961
LP
1542 r = sd_bus_message_read(message, "s", &name);
1543 if (r < 0)
1544 return r;
8e2af478 1545
718db961
LP
1546 if (!UNIT_VTABLE(u)->bus_set_property)
1547 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
8e2af478 1548
718db961
LP
1549 r = sd_bus_message_enter_container(message, 'v', NULL);
1550 if (r < 0)
1551 return r;
8e2af478 1552
718db961 1553 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
9f2e86af 1554 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
718db961
LP
1555 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1556 if (r < 0)
1557 return r;
1558 if (r == 0)
1559 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1560
1561 r = sd_bus_message_exit_container(message);
8e2af478
LP
1562 if (r < 0)
1563 return r;
8e2af478 1564
718db961
LP
1565 r = sd_bus_message_exit_container(message);
1566 if (r < 0)
1567 return r;
8e2af478
LP
1568
1569 n += for_real;
1570 }
1571
6ce270b1
LP
1572 r = sd_bus_message_exit_container(message);
1573 if (r < 0)
1574 return r;
1575
c2756a68 1576 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
8e2af478
LP
1577 UNIT_VTABLE(u)->bus_commit_properties(u);
1578
241da328 1579 return n;
8e2af478 1580}
000a996d
FB
1581
1582int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
6eb7c172 1583 assert(u);
000a996d
FB
1584
1585 if (u->load_state == UNIT_LOADED)
1586 return 0;
1587
1588 /* Give a better description of the unit error when
1589 * possible. Note that in the case of UNIT_MASKED, load_error
1590 * is not set. */
1591 if (u->load_state == UNIT_MASKED)
b21d2f81 1592 return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id);
000a996d
FB
1593
1594 if (u->load_state == UNIT_NOT_FOUND)
b21d2f81 1595 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id);
000a996d 1596
b21d2f81 1597 return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
000a996d 1598}
05a98afd 1599
c5a97ed1 1600static int bus_unit_track_handler(sd_bus_track *t, void *userdata) {
05a98afd
LP
1601 Unit *u = userdata;
1602
1603 assert(t);
1604 assert(u);
1605
1606 u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */
1607
1608 unit_add_to_gc_queue(u);
1609 return 0;
1610}
1611
c5a97ed1 1612static int bus_unit_allocate_bus_track(Unit *u) {
05a98afd
LP
1613 int r;
1614
1615 assert(u);
1616
1617 if (u->bus_track)
1618 return 0;
1619
c5a97ed1 1620 r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_unit_track_handler, u);
05a98afd
LP
1621 if (r < 0)
1622 return r;
1623
1624 r = sd_bus_track_set_recursive(u->bus_track, true);
1625 if (r < 0) {
1626 u->bus_track = sd_bus_track_unref(u->bus_track);
1627 return r;
1628 }
1629
1630 return 0;
1631}
1632
1633int bus_unit_track_add_name(Unit *u, const char *name) {
1634 int r;
1635
1636 assert(u);
1637
c5a97ed1 1638 r = bus_unit_allocate_bus_track(u);
05a98afd
LP
1639 if (r < 0)
1640 return r;
1641
1642 return sd_bus_track_add_name(u->bus_track, name);
1643}
1644
1645int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
1646 int r;
1647
1648 assert(u);
1649
c5a97ed1 1650 r = bus_unit_allocate_bus_track(u);
05a98afd
LP
1651 if (r < 0)
1652 return r;
1653
1654 return sd_bus_track_add_sender(u->bus_track, m);
1655}
1656
1657int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
1658 assert(u);
1659
1660 /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
1661 * error */
1662 if (!u->bus_track)
1663 return -EUNATCH;
1664
1665 return sd_bus_track_remove_sender(u->bus_track, m);
1666}