]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
core: re-sync bus name list after deserializing during daemon-reload
[thirdparty/systemd.git] / src / core / dbus.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986 22#include <errno.h>
07630cea 23#include <sys/epoll.h>
ea430986
LP
24#include <unistd.h>
25
718db961 26#include "sd-bus.h"
07630cea 27
b5efdb8a 28#include "alloc-util.h"
07630cea
LP
29#include "bus-common-errors.h"
30#include "bus-error.h"
31#include "bus-internal.h"
32#include "bus-util.h"
33#include "dbus-cgroup.h"
718db961 34#include "dbus-execute.h"
07630cea 35#include "dbus-job.h"
718db961 36#include "dbus-kill.h"
07630cea
LP
37#include "dbus-manager.h"
38#include "dbus-unit.h"
3ffd4af2
LP
39#include "dbus.h"
40#include "fd-util.h"
07630cea
LP
41#include "log.h"
42#include "missing.h"
43#include "mkdir.h"
44#include "selinux-access.h"
8f6df3fa 45#include "special.h"
07630cea
LP
46#include "string-util.h"
47#include "strv.h"
718db961 48#include "strxcpyx.h"
ee104e11 49#include "user-util.h"
4288f619 50
cbecf9bf 51#define CONNECTIONS_MAX 4096
5e8d1c9a 52
718db961
LP
53static void destroy_bus(Manager *m, sd_bus **bus);
54
55int bus_send_queued_message(Manager *m) {
56 int r;
8e274523 57
8e274523 58 assert(m);
2e317f52 59
718db961
LP
60 if (!m->queued_message)
61 return 0;
8e274523 62
718db961
LP
63 /* If we cannot get rid of this message we won't dispatch any
64 * D-Bus messages, so that we won't end up wanting to queue
65 * another message. */
ea430986 66
8f88ecf6 67 r = sd_bus_send(NULL, m->queued_message, NULL);
718db961 68 if (r < 0)
da927ba9 69 log_warning_errno(r, "Failed to send queued message: %m");
ea430986 70
718db961 71 m->queued_message = sd_bus_message_unref(m->queued_message);
ea430986 72
718db961 73 return 0;
ea430986
LP
74}
75
19070062 76static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 77 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
0a069ce6 78 const char *cgroup, *me;
718db961 79 Manager *m = userdata;
0a069ce6
DH
80 uid_t sender_uid;
81 sd_bus *bus;
718db961 82 int r;
ea430986 83
718db961 84 assert(message);
ea430986
LP
85 assert(m);
86
0a069ce6
DH
87 /* ignore recursive events sent by us on the system/user bus */
88 bus = sd_bus_message_get_bus(message);
89 if (!sd_bus_is_server(bus)) {
90 r = sd_bus_get_unique_name(bus, &me);
91 if (r < 0)
92 return r;
93
94 if (streq_ptr(sd_bus_message_get_sender(message), me))
95 return 0;
96 }
97
98 /* only accept org.freedesktop.systemd1.Agent from UID=0 */
99 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
100 if (r < 0)
101 return r;
102
103 r = sd_bus_creds_get_euid(creds, &sender_uid);
104 if (r < 0 || sender_uid != 0)
105 return 0;
106
107 /* parse 'cgroup-empty' notification */
718db961
LP
108 r = sd_bus_message_read(message, "s", &cgroup);
109 if (r < 0) {
110 bus_log_parse_error(r);
111 return 0;
112 }
ea430986 113
718db961 114 manager_notify_cgroup_empty(m, cgroup);
ea430986 115
a0c8526a
DH
116 /* if running as system-instance, forward under our name */
117 if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
118 r = sd_bus_message_rewind(message, 1);
119 if (r >= 0)
120 r = sd_bus_send(m->system_bus, message, NULL);
121 if (r < 0)
122 log_warning_errno(r, "Failed to forward Released message: %m");
123 }
39881ed2 124
718db961
LP
125 return 0;
126}
ea430986 127
19070062 128static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 129 Manager *m = userdata;
19070062 130 sd_bus *bus;
ea430986 131
718db961
LP
132 assert(message);
133 assert(m);
19070062 134 assert_se(bus = sd_bus_message_get_bus(message));
ea430986 135
718db961
LP
136 if (bus == m->api_bus)
137 destroy_bus(m, &m->api_bus);
138 if (bus == m->system_bus)
139 destroy_bus(m, &m->system_bus);
140 if (set_remove(m->private_buses, bus)) {
141 log_debug("Got disconnect on private connection.");
142 destroy_bus(m, &bus);
ea430986
LP
143 }
144
718db961 145 return 0;
ea430986
LP
146}
147
19070062 148static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
4afd3348
LP
149 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
150 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
718db961
LP
151 Manager *m = userdata;
152 const char *name;
153 Unit *u;
154 int r;
ea430986 155
718db961 156 assert(message);
ea430986
LP
157 assert(m);
158
718db961
LP
159 r = sd_bus_message_read(message, "s", &name);
160 if (r < 0) {
161 bus_log_parse_error(r);
162 return 0;
163 }
ea430986 164
718db961
LP
165 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
166 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
167 r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
168 goto failed;
169 }
ea430986 170
718db961
LP
171 r = manager_load_unit(m, name, NULL, &error, &u);
172 if (r < 0)
173 goto failed;
ea430986 174
718db961 175 if (u->refuse_manual_start) {
d14ab08b 176 r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
718db961 177 goto failed;
ea430986
LP
178 }
179
4bd29fe5 180 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
718db961
LP
181 if (r < 0)
182 goto failed;
ea430986 183
718db961 184 /* Successfully queued, that's it for us */
ea430986 185 return 0;
ea430986 186
718db961
LP
187failed:
188 if (!sd_bus_error_is_set(&error))
189 sd_bus_error_set_errno(&error, r);
ea430986 190
718db961 191 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
ea430986 192
966c66e3 193 r = sd_bus_message_new_signal(sd_bus_message_get_bus(message), &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
718db961
LP
194 if (r < 0) {
195 bus_log_create_error(r);
196 return 0;
197 }
198
fa0fed49 199 r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
718db961
LP
200 if (r < 0) {
201 bus_log_create_error(r);
202 return 0;
203 }
204
966c66e3 205 r = sd_bus_send_to(NULL, reply, "org.freedesktop.DBus", NULL);
23bbb0de
MS
206 if (r < 0)
207 return log_error_errno(r, "Failed to respond with to bus activation request: %m");
ea430986 208
718db961 209 return 0;
ea430986
LP
210}
211
ad5b215d 212#ifdef HAVE_SELINUX
19070062 213static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_error *error) {
969987ea
LP
214 Manager *m = userdata;
215 const char *verb, *path;
216 Unit *u = NULL;
217 Job *j;
218 int r;
219
969987ea
LP
220 assert(message);
221
222 /* Our own method calls are all protected individually with
223 * selinux checks, but the built-in interfaces need to be
224 * protected too. */
225
226 if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
227 verb = "reload";
228 else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
229 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
230 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
231 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
232 verb = "status";
233 else
234 return 0;
235
236 path = sd_bus_message_get_path(message);
237
238 if (object_path_startswith("/org/freedesktop/systemd1", path)) {
239
8a188de9 240 r = mac_selinux_access_check(message, verb, error);
969987ea
LP
241 if (r < 0)
242 return r;
243
244 return 0;
245 }
246
247 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
4afd3348 248 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
969987ea
LP
249 pid_t pid;
250
5b12334d
LP
251 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
252 if (r < 0)
253 return 0;
254
255 r = sd_bus_creds_get_pid(creds, &pid);
969987ea
LP
256 if (r < 0)
257 return 0;
258
259 u = manager_get_unit_by_pid(m, pid);
260 } else {
261 r = manager_get_job_from_dbus_path(m, path, &j);
262 if (r >= 0)
263 u = j->unit;
264 else
265 manager_load_unit_from_dbus_path(m, path, NULL, &u);
266 }
267
268 if (!u)
269 return 0;
270
8a188de9 271 r = mac_selinux_unit_access_check(u, message, verb, error);
969987ea
LP
272 if (r < 0)
273 return r;
274
275 return 0;
276}
ad5b215d 277#endif
969987ea 278
f00c3121 279static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
280 Manager *m = userdata;
281 Job *j;
282 int r;
ea430986 283
718db961
LP
284 assert(bus);
285 assert(path);
286 assert(interface);
287 assert(found);
ea430986
LP
288 assert(m);
289
718db961
LP
290 r = manager_get_job_from_dbus_path(m, path, &j);
291 if (r < 0)
292 return 0;
ea430986 293
718db961
LP
294 *found = j;
295 return 1;
296}
ea430986 297
f00c3121 298static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
718db961
LP
299 Unit *u;
300 int r;
ea430986 301
718db961
LP
302 assert(m);
303 assert(bus);
304 assert(path);
ea430986 305
718db961 306 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
4afd3348 307 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
718db961
LP
308 sd_bus_message *message;
309 pid_t pid;
ea430986 310
19befb2d 311 message = sd_bus_get_current_message(bus);
718db961 312 if (!message)
f00c3121 313 return 0;
ea430986 314
5b12334d 315 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
718db961 316 if (r < 0)
5b12334d
LP
317 return r;
318
319 r = sd_bus_creds_get_pid(creds, &pid);
320 if (r < 0)
321 return r;
ea430986 322
718db961
LP
323 u = manager_get_unit_by_pid(m, pid);
324 } else {
f00c3121 325 r = manager_load_unit_from_dbus_path(m, path, error, &u);
718db961 326 if (r < 0)
f00c3121 327 return 0;
718db961 328 }
ea430986 329
f00c3121
LP
330 if (!u)
331 return 0;
332
333 *unit = u;
334 return 1;
ea430986
LP
335}
336
f00c3121 337static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961 338 Manager *m = userdata;
ea430986 339
718db961
LP
340 assert(bus);
341 assert(path);
342 assert(interface);
343 assert(found);
ea430986
LP
344 assert(m);
345
f00c3121 346 return find_unit(m, bus, path, (Unit**) found, error);
ea430986
LP
347}
348
f00c3121 349static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
350 Manager *m = userdata;
351 Unit *u;
f00c3121 352 int r;
ea430986 353
718db961
LP
354 assert(bus);
355 assert(path);
356 assert(interface);
357 assert(found);
ea430986
LP
358 assert(m);
359
f00c3121
LP
360 r = find_unit(m, bus, path, &u, error);
361 if (r <= 0)
362 return r;
3df5bf61 363
21b735e7 364 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 365 return 0;
ea430986 366
718db961
LP
367 *found = u;
368 return 1;
ea430986
LP
369}
370
f00c3121 371static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
372 Manager *m = userdata;
373 Unit *u;
f00c3121 374 int r;
c1e1601e 375
718db961
LP
376 assert(bus);
377 assert(path);
378 assert(interface);
379 assert(found);
c1e1601e
LP
380 assert(m);
381
f00c3121
LP
382 r = find_unit(m, bus, path, &u, error);
383 if (r <= 0)
384 return r;
05e343b7 385
21b735e7 386 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 387 return 0;
05e343b7 388
35b7ff80 389 if (!UNIT_HAS_CGROUP_CONTEXT(u))
718db961 390 return 0;
0034c15c 391
718db961
LP
392 *found = u;
393 return 1;
394}
0034c15c 395
f00c3121 396static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
397 Manager *m = userdata;
398 CGroupContext *c;
399 Unit *u;
f00c3121 400 int r;
af25ec12 401
718db961
LP
402 assert(bus);
403 assert(path);
404 assert(interface);
405 assert(found);
406 assert(m);
0034c15c 407
f00c3121
LP
408 r = find_unit(m, bus, path, &u, error);
409 if (r <= 0)
410 return r;
0034c15c 411
21b735e7 412 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 413 return 0;
0034c15c 414
718db961
LP
415 c = unit_get_cgroup_context(u);
416 if (!c)
417 return 0;
c1e1601e 418
718db961
LP
419 *found = c;
420 return 1;
421}
0034c15c 422
f00c3121 423static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
424 Manager *m = userdata;
425 ExecContext *c;
426 Unit *u;
f00c3121 427 int r;
0034c15c 428
718db961
LP
429 assert(bus);
430 assert(path);
431 assert(interface);
432 assert(found);
433 assert(m);
0034c15c 434
f00c3121
LP
435 r = find_unit(m, bus, path, &u, error);
436 if (r <= 0)
437 return r;
0034c15c 438
21b735e7 439 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 440 return 0;
0034c15c 441
718db961
LP
442 c = unit_get_exec_context(u);
443 if (!c)
444 return 0;
0034c15c 445
718db961
LP
446 *found = c;
447 return 1;
c1e1601e
LP
448}
449
f00c3121 450static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
451 Manager *m = userdata;
452 KillContext *c;
453 Unit *u;
f00c3121 454 int r;
8e274523 455
718db961
LP
456 assert(bus);
457 assert(path);
458 assert(interface);
459 assert(found);
8e274523
LP
460 assert(m);
461
f00c3121
LP
462 r = find_unit(m, bus, path, &u, error);
463 if (r <= 0)
464 return r;
8e274523 465
21b735e7 466 if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
718db961 467 return 0;
8e274523 468
718db961
LP
469 c = unit_get_kill_context(u);
470 if (!c)
471 return 0;
53c6a358 472
718db961
LP
473 *found = c;
474 return 1;
475}
8e274523 476
f00c3121 477static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
478 _cleanup_free_ char **l = NULL;
479 Manager *m = userdata;
480 unsigned k = 0;
481 Iterator i;
482 Job *j;
8e274523 483
718db961
LP
484 l = new0(char*, hashmap_size(m->jobs)+1);
485 if (!l)
486 return -ENOMEM;
8e274523 487
718db961
LP
488 HASHMAP_FOREACH(j, m->jobs, i) {
489 l[k] = job_dbus_path(j);
490 if (!l[k])
491 return -ENOMEM;
5e8d1c9a 492
718db961
LP
493 k++;
494 }
5e8d1c9a 495
718db961 496 assert(hashmap_size(m->jobs) == k);
3c661fad 497
718db961
LP
498 *nodes = l;
499 l = NULL;
5e8d1c9a 500
718db961
LP
501 return k;
502}
53c6a358 503
f00c3121 504static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
505 _cleanup_free_ char **l = NULL;
506 Manager *m = userdata;
507 unsigned k = 0;
508 Iterator i;
509 Unit *u;
3c661fad 510
718db961
LP
511 l = new0(char*, hashmap_size(m->units)+1);
512 if (!l)
513 return -ENOMEM;
53c6a358 514
718db961
LP
515 HASHMAP_FOREACH(u, m->units, i) {
516 l[k] = unit_dbus_path(u);
517 if (!l[k])
518 return -ENOMEM;
53c6a358 519
718db961 520 k++;
3c661fad
LP
521 }
522
718db961
LP
523 *nodes = l;
524 l = NULL;
5e8d1c9a 525
718db961 526 return k;
5e8d1c9a
LP
527}
528
718db961
LP
529static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
530 UnitType t;
531 int r;
5e8d1c9a 532
ea430986 533 assert(m);
718db961 534 assert(bus);
ea430986 535
ad5b215d 536#ifdef HAVE_SELINUX
8a188de9 537 r = sd_bus_add_filter(bus, NULL, mac_selinux_filter, m);
23bbb0de
MS
538 if (r < 0)
539 return log_error_errno(r, "Failed to add SELinux access filter: %m");
ad5b215d 540#endif
969987ea 541
19befb2d 542 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
23bbb0de
MS
543 if (r < 0)
544 return log_error_errno(r, "Failed to register Manager vtable: %m");
a16e1123 545
19befb2d 546 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
23bbb0de
MS
547 if (r < 0)
548 return log_error_errno(r, "Failed to register Job vtable: %m");
c1e1601e 549
19befb2d 550 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
23bbb0de
MS
551 if (r < 0)
552 return log_error_errno(r, "Failed to add job enumerator: %m");
61902ea3 553
19befb2d 554 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
23bbb0de
MS
555 if (r < 0)
556 return log_error_errno(r, "Failed to register Unit vtable: %m");
61902ea3 557
19befb2d 558 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
23bbb0de
MS
559 if (r < 0)
560 return log_error_errno(r, "Failed to add job enumerator: %m");
61902ea3 561
718db961 562 for (t = 0; t < _UNIT_TYPE_MAX; t++) {
21b735e7
LP
563 const char *interface;
564
565 assert_se(interface = unit_dbus_interface_from_type(t));
566
567 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
23bbb0de 568 if (r < 0)
21b735e7 569 return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface);
61902ea3 570
718db961 571 if (unit_vtable[t]->cgroup_context_offset > 0) {
21b735e7 572 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
23bbb0de 573 if (r < 0)
21b735e7 574 return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface);
61902ea3 575
21b735e7 576 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
23bbb0de 577 if (r < 0)
21b735e7 578 return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface);
61902ea3
LP
579 }
580
718db961 581 if (unit_vtable[t]->exec_context_offset > 0) {
21b735e7 582 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m);
23bbb0de 583 if (r < 0)
21b735e7 584 return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface);
718db961 585 }
61902ea3 586
718db961 587 if (unit_vtable[t]->kill_context_offset > 0) {
21b735e7 588 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m);
23bbb0de 589 if (r < 0)
21b735e7 590 return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface);
718db961 591 }
61902ea3
LP
592 }
593
718db961 594 return 0;
61902ea3
LP
595}
596
718db961
LP
597static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
598 int r;
61902ea3 599
718db961
LP
600 assert(m);
601 assert(bus);
61902ea3 602
718db961
LP
603 r = sd_bus_add_match(
604 bus,
19befb2d 605 NULL,
27fc65e1 606 "sender='org.freedesktop.DBus.Local',"
718db961
LP
607 "type='signal',"
608 "path='/org/freedesktop/DBus/Local',"
609 "interface='org.freedesktop.DBus.Local',"
610 "member='Disconnected'",
611 signal_disconnected, m);
05e343b7 612
23bbb0de
MS
613 if (r < 0)
614 return log_error_errno(r, "Failed to register match for Disconnected message: %m");
05e343b7 615
718db961 616 return 0;
ea430986
LP
617}
618
718db961 619static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
4afd3348 620 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
718db961 621 _cleanup_close_ int nfd = -1;
6dded4c7 622 Manager *m = userdata;
718db961
LP
623 sd_id128_t id;
624 int r;
6dded4c7 625
718db961 626 assert(s);
6dded4c7
LP
627 assert(m);
628
718db961
LP
629 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
630 if (nfd < 0) {
56f64d95 631 log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
718db961
LP
632 return 0;
633 }
6dded4c7 634
718db961
LP
635 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
636 log_warning("Too many concurrent connections, refusing");
637 return 0;
638 }
6dded4c7 639
d5099efc 640 r = set_ensure_allocated(&m->private_buses, NULL);
718db961
LP
641 if (r < 0) {
642 log_oom();
643 return 0;
644 }
6dded4c7 645
718db961
LP
646 r = sd_bus_new(&bus);
647 if (r < 0) {
da927ba9 648 log_warning_errno(r, "Failed to allocate new private connection bus: %m");
718db961
LP
649 return 0;
650 }
6dded4c7 651
718db961
LP
652 r = sd_bus_set_fd(bus, nfd, nfd);
653 if (r < 0) {
da927ba9 654 log_warning_errno(r, "Failed to set fd on new connection bus: %m");
718db961
LP
655 return 0;
656 }
6dded4c7 657
718db961 658 nfd = -1;
6dded4c7 659
718db961
LP
660 r = bus_check_peercred(bus);
661 if (r < 0) {
da927ba9 662 log_warning_errno(r, "Incoming private connection from unprivileged client, refusing: %m");
718db961
LP
663 return 0;
664 }
6dded4c7 665
718db961 666 assert_se(sd_id128_randomize(&id) >= 0);
6dded4c7 667
718db961
LP
668 r = sd_bus_set_server(bus, 1, id);
669 if (r < 0) {
da927ba9 670 log_warning_errno(r, "Failed to enable server support for new connection bus: %m");
718db961
LP
671 return 0;
672 }
6dded4c7 673
0674bbea
LP
674 r = sd_bus_negotiate_creds(bus, 1,
675 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
676 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
677 SD_BUS_CREDS_SELINUX_CONTEXT);
678 if (r < 0) {
679 log_warning_errno(r, "Failed to enable credentials for new connection: %m");
680 return 0;
681 }
682
718db961
LP
683 r = sd_bus_start(bus);
684 if (r < 0) {
da927ba9 685 log_warning_errno(r, "Failed to start new connection bus: %m");
718db961 686 return 0;
6dded4c7
LP
687 }
688
718db961
LP
689 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
690 if (r < 0) {
da927ba9 691 log_warning_errno(r, "Failed to attach new connection bus to event loop: %m");
718db961 692 return 0;
6dded4c7
LP
693 }
694
b2c23da8 695 if (m->running_as == MANAGER_SYSTEM) {
718db961
LP
696 /* When we run as system instance we get the Released
697 * signal via a direct connection */
698
699 r = sd_bus_add_match(
700 bus,
19befb2d 701 NULL,
718db961
LP
702 "type='signal',"
703 "interface='org.freedesktop.systemd1.Agent',"
704 "member='Released',"
705 "path='/org/freedesktop/systemd1/agent'",
706 signal_agent_released, m);
707
708 if (r < 0) {
da927ba9 709 log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
718db961
LP
710 return 0;
711 }
712 }
6dded4c7 713
718db961
LP
714 r = bus_setup_disconnected_match(m, bus);
715 if (r < 0)
716 return 0;
6dded4c7 717
718db961
LP
718 r = bus_setup_api_vtables(m, bus);
719 if (r < 0) {
da927ba9 720 log_warning_errno(r, "Failed to set up API vtables on new connection bus: %m");
718db961
LP
721 return 0;
722 }
6dded4c7 723
718db961
LP
724 r = set_put(m->private_buses, bus);
725 if (r < 0) {
05a08cb6 726 log_warning_errno(r, "Failed to add new connection bus to set: %m");
718db961 727 return 0;
6dded4c7
LP
728 }
729
718db961 730 bus = NULL;
6dded4c7 731
718db961 732 log_debug("Accepted new private connection.");
6dded4c7 733
8e274523
LP
734 return 0;
735}
736
8936a5e3 737int manager_sync_bus_names(Manager *m, sd_bus *bus) {
0e7be129 738 _cleanup_strv_free_ char **names = NULL;
d8ccf5fd
DM
739 const char *name;
740 Iterator i;
741 Unit *u;
718db961 742 int r;
5e8d1c9a
LP
743
744 assert(m);
718db961 745 assert(bus);
5e8d1c9a 746
0e7be129 747 r = sd_bus_list_names(bus, &names, NULL);
23bbb0de
MS
748 if (r < 0)
749 return log_error_errno(r, "Failed to get initial list of names: %m");
5e8d1c9a 750
d8ccf5fd
DM
751 /* We have to synchronize the current bus names with the
752 * list of active services. To do this, walk the list of
753 * all units with bus names. */
754 HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
755 Service *s = SERVICE(u);
756
757 assert(s);
bbc29086 758
d8ccf5fd
DM
759 if (!streq_ptr(s->bus_name, name)) {
760 log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
761 continue;
762 }
763
764 /* Check if a service's bus name is in the list of currently
765 * active names */
766 if (strv_contains(names, name)) {
767 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
768 const char *unique;
769
770 /* If it is, determine its current owner */
771 r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds);
772 if (r < 0) {
773 log_error_errno(r, "Failed to get bus name owner %s: %m", name);
774 continue;
775 }
776
777 r = sd_bus_creds_get_unique_name(creds, &unique);
778 if (r < 0) {
779 log_error_errno(r, "Failed to get unique name for %s: %m", name);
780 continue;
781 }
782
783 /* Now, let's compare that to the previous bus owner, and
784 * if it's still the same, all is fine, so just don't
785 * bother the service. Otherwise, the name has apparently
786 * changed, so synthesize a name owner changed signal. */
787
788 if (!streq_ptr(unique, s->bus_name_owner))
789 UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, unique);
790 } else {
791 /* So, the name we're watching is not on the bus.
792 * This either means it simply hasn't appeared yet,
793 * or it was lost during the daemon reload.
794 * Check if the service has a stored name owner,
795 * and synthesize a name loss signal in this case. */
796
797 if (s->bus_name_owner)
798 UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, NULL);
799 }
bbc29086 800 }
5e8d1c9a 801
718db961 802 return 0;
5e8d1c9a
LP
803}
804
718db961 805static int bus_setup_api(Manager *m, sd_bus *bus) {
bbc29086
DM
806 Iterator i;
807 char *name;
808 Unit *u;
718db961 809 int r;
f278026d 810
718db961
LP
811 assert(m);
812 assert(bus);
c1e1601e 813
8fd00193
LP
814 /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
815 r = sd_bus_negotiate_creds(bus, 1,
816 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
817 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
818 SD_BUS_CREDS_SELINUX_CONTEXT);
819 if (r < 0)
da927ba9 820 log_warning_errno(r, "Failed to enable credential passing, ignoring: %m");
8fd00193 821
718db961
LP
822 r = bus_setup_api_vtables(m, bus);
823 if (r < 0)
824 return r;
cbd37330 825
bbc29086 826 HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
9806e87d 827 r = unit_install_bus_match(u, bus, name);
bbc29086 828 if (r < 0)
8ea823b6 829 log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
bbc29086 830 }
718db961
LP
831
832 r = sd_bus_add_match(
833 bus,
19befb2d 834 NULL,
718db961
LP
835 "type='signal',"
836 "sender='org.freedesktop.DBus',"
837 "path='/org/freedesktop/DBus',"
838 "interface='org.freedesktop.systemd1.Activator',"
839 "member='ActivationRequest'",
840 signal_activation_request, m);
841 if (r < 0)
da927ba9 842 log_warning_errno(r, "Failed to subscribe to activation signal: %m");
cbd37330 843
718db961
LP
844 /* Allow replacing of our name, to ease implementation of
845 * reexecution, where we keep the old connection open until
846 * after the new connection is set up and the name installed
847 * to allow clients to synchronously wait for reexecution to
848 * finish */
29a07cdb 849 r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
23bbb0de
MS
850 if (r < 0)
851 return log_error_errno(r, "Failed to register name: %m");
53c6a358 852
8936a5e3 853 r = manager_sync_bus_names(m, bus);
d8ccf5fd
DM
854 if (r < 0)
855 return r;
f278026d 856
718db961 857 log_debug("Successfully connected to API bus.");
f278026d
LP
858 return 0;
859}
860
718db961 861static int bus_init_api(Manager *m) {
4afd3348 862 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
f278026d
LP
863 int r;
864
718db961
LP
865 if (m->api_bus)
866 return 0;
cbd37330 867
718db961 868 /* The API and system bus is the same if we are running in system mode */
b2c23da8 869 if (m->running_as == MANAGER_SYSTEM && m->system_bus)
718db961
LP
870 bus = sd_bus_ref(m->system_bus);
871 else {
b2c23da8 872 if (m->running_as == MANAGER_SYSTEM)
718db961
LP
873 r = sd_bus_open_system(&bus);
874 else
875 r = sd_bus_open_user(&bus);
cbd37330 876
718db961
LP
877 if (r < 0) {
878 log_debug("Failed to connect to API bus, retrying later...");
879 return 0;
cbd37330
MS
880 }
881
718db961
LP
882 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
883 if (r < 0) {
da927ba9 884 log_error_errno(r, "Failed to attach API bus to event loop: %m");
718db961 885 return 0;
cbd37330
MS
886 }
887
718db961
LP
888 r = bus_setup_disconnected_match(m, bus);
889 if (r < 0)
890 return 0;
cbd37330
MS
891 }
892
718db961 893 r = bus_setup_api(m, bus);
cbd37330 894 if (r < 0) {
da927ba9 895 log_error_errno(r, "Failed to set up API bus: %m");
718db961 896 return 0;
cbd37330 897 }
cbd37330 898
718db961
LP
899 m->api_bus = bus;
900 bus = NULL;
cbd37330
MS
901
902 return 0;
cbd37330
MS
903}
904
718db961
LP
905static int bus_setup_system(Manager *m, sd_bus *bus) {
906 int r;
cbd37330 907
718db961
LP
908 assert(m);
909 assert(bus);
cbd37330 910
f5b51ea7 911 /* On kdbus or if we are a user instance we get the Released message via the system bus */
b2c23da8 912 if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
f5b51ea7
DH
913 r = sd_bus_add_match(
914 bus,
915 NULL,
916 "type='signal',"
917 "interface='org.freedesktop.systemd1.Agent',"
918 "member='Released',"
919 "path='/org/freedesktop/systemd1/agent'",
920 signal_agent_released, m);
921 if (r < 0)
922 log_warning_errno(r, "Failed to register Released match on system bus: %m");
923 }
718db961
LP
924
925 log_debug("Successfully connected to system bus.");
926 return 0;
cbd37330
MS
927}
928
929static int bus_init_system(Manager *m) {
4afd3348 930 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
cbd37330
MS
931 int r;
932
933 if (m->system_bus)
934 return 0;
935
718db961 936 /* The API and system bus is the same if we are running in system mode */
b2c23da8 937 if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
718db961
LP
938 m->system_bus = sd_bus_ref(m->api_bus);
939 return 0;
9014a8bd 940 }
8e274523 941
718db961
LP
942 r = sd_bus_open_system(&bus);
943 if (r < 0) {
944 log_debug("Failed to connect to system bus, retrying later...");
945 return 0;
946 }
cbd37330 947
718db961 948 r = bus_setup_disconnected_match(m, bus);
cbd37330 949 if (r < 0)
cbd37330
MS
950 return 0;
951
718db961
LP
952 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
953 if (r < 0) {
da927ba9 954 log_error_errno(r, "Failed to attach system bus to event loop: %m");
cbd37330
MS
955 return 0;
956 }
957
718db961
LP
958 r = bus_setup_system(m, bus);
959 if (r < 0) {
da927ba9 960 log_error_errno(r, "Failed to set up system bus: %m");
718db961 961 return 0;
cbd37330
MS
962 }
963
718db961
LP
964 m->system_bus = bus;
965 bus = NULL;
cbd37330
MS
966
967 return 0;
5e8d1c9a
LP
968}
969
970static int bus_init_private(Manager *m) {
718db961
LP
971 _cleanup_close_ int fd = -1;
972 union sockaddr_union sa = {
973 .un.sun_family = AF_UNIX
5e8d1c9a 974 };
718db961
LP
975 sd_event_source *s;
976 socklen_t salen;
977 int r;
5e8d1c9a
LP
978
979 assert(m);
980
718db961 981 if (m->private_listen_fd >= 0)
5e8d1c9a
LP
982 return 0;
983
a6aa8912
LP
984 /* We don't need the private socket if we have kdbus */
985 if (m->kdbus_fd >= 0)
986 return 0;
987
b2c23da8 988 if (m->running_as == MANAGER_SYSTEM) {
be81bfc4
LP
989
990 /* We want the private bus only when running as init */
991 if (getpid() != 1)
992 return 0;
993
718db961 994 strcpy(sa.un.sun_path, "/run/systemd/private");
f8294e41 995 salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
be81bfc4 996 } else {
718db961
LP
997 size_t left = sizeof(sa.un.sun_path);
998 char *p = sa.un.sun_path;
be81bfc4 999 const char *e;
be81bfc4 1000
4db17f29 1001 e = secure_getenv("XDG_RUNTIME_DIR");
718db961
LP
1002 if (!e) {
1003 log_error("Failed to determine XDG_RUNTIME_DIR");
1004 return -EHOSTDOWN;
be81bfc4
LP
1005 }
1006
718db961
LP
1007 left = strpcpy(&p, left, e);
1008 left = strpcpy(&p, left, "/systemd/private");
92f30349 1009
718db961 1010 salen = sizeof(sa.un) - left;
be81bfc4 1011 }
5e8d1c9a 1012
f0e62e89
LP
1013 (void) mkdir_parents_label(sa.un.sun_path, 0755);
1014 (void) unlink(sa.un.sun_path);
718db961
LP
1015
1016 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710
MS
1017 if (fd < 0)
1018 return log_error_errno(errno, "Failed to allocate private socket: %m");
5e8d1c9a 1019
718db961 1020 r = bind(fd, &sa.sa, salen);
4a62c710
MS
1021 if (r < 0)
1022 return log_error_errno(errno, "Failed to bind private socket: %m");
5e8d1c9a 1023
718db961 1024 r = listen(fd, SOMAXCONN);
4a62c710
MS
1025 if (r < 0)
1026 return log_error_errno(errno, "Failed to make private socket listening: %m");
5e8d1c9a 1027
151b9b96 1028 r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
23bbb0de
MS
1029 if (r < 0)
1030 return log_error_errno(r, "Failed to allocate event source: %m");
5e8d1c9a 1031
7dfbe2e3
TG
1032 (void) sd_event_source_set_description(s, "bus-connection");
1033
718db961
LP
1034 m->private_listen_fd = fd;
1035 m->private_listen_event_source = s;
1036 fd = -1;
5e8d1c9a 1037
718db961 1038 log_debug("Successfully created private D-Bus server.");
5e8d1c9a 1039
718db961 1040 return 0;
5e8d1c9a
LP
1041}
1042
3996fbe2 1043int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
1044 int r;
1045
3996fbe2 1046 if (try_bus_connect) {
718db961
LP
1047 r = bus_init_system(m);
1048 if (r < 0)
1049 return r;
1050
1051 r = bus_init_api(m);
1052 if (r < 0)
3996fbe2
LP
1053 return r;
1054 }
1055
6fa48533
LP
1056 r = bus_init_private(m);
1057 if (r < 0)
5e8d1c9a 1058 return r;
f278026d 1059
ea430986
LP
1060 return 0;
1061}
1062
718db961 1063static void destroy_bus(Manager *m, sd_bus **bus) {
a567261a 1064 Iterator i;
718db961 1065 Job *j;
a567261a 1066
718db961
LP
1067 assert(m);
1068 assert(bus);
5e8d1c9a 1069
718db961 1070 if (!*bus)
cbd37330 1071 return;
f278026d 1072
718db961 1073 /* Get rid of tracked clients on this bus */
8f8f05a9
LP
1074 if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus)
1075 m->subscribed = sd_bus_track_unref(m->subscribed);
1076
718db961 1077 HASHMAP_FOREACH(j, m->jobs, i)
b39a2770
SW
1078 if (j->clients && sd_bus_track_get_bus(j->clients) == *bus)
1079 j->clients = sd_bus_track_unref(j->clients);
c1e1601e 1080
718db961 1081 /* Get rid of queued message on this bus */
8f88ecf6
LP
1082 if (m->queued_message && sd_bus_message_get_bus(m->queued_message) == *bus)
1083 m->queued_message = sd_bus_message_unref(m->queued_message);
f278026d 1084
718db961
LP
1085 /* Possibly flush unwritten data, but only if we are
1086 * unprivileged, since we don't want to sync here */
b2c23da8 1087 if (m->running_as != MANAGER_SYSTEM)
718db961 1088 sd_bus_flush(*bus);
5e8d1c9a 1089
718db961
LP
1090 /* And destroy the object */
1091 sd_bus_close(*bus);
1092 *bus = sd_bus_unref(*bus);
5e8d1c9a
LP
1093}
1094
1095void bus_done(Manager *m) {
718db961 1096 sd_bus *b;
05e343b7
LP
1097
1098 assert(m);
05e343b7 1099
718db961
LP
1100 if (m->api_bus)
1101 destroy_bus(m, &m->api_bus);
1102 if (m->system_bus)
1103 destroy_bus(m, &m->system_bus);
1104 while ((b = set_steal_first(m->private_buses)))
1105 destroy_bus(m, &b);
05e343b7 1106
525d3cc7 1107 m->private_buses = set_free(m->private_buses);
8f8f05a9
LP
1108
1109 m->subscribed = sd_bus_track_unref(m->subscribed);
6796073e 1110 m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
05e343b7 1111
718db961
LP
1112 if (m->private_listen_event_source)
1113 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
05e343b7 1114
03e334a1 1115 m->private_listen_fd = safe_close(m->private_listen_fd);
283868e1
SW
1116
1117 bus_verify_polkit_async_registry_free(m->polkit_registry);
a567261a 1118}
b23de6af
LP
1119
1120int bus_fdset_add_all(Manager *m, FDSet *fds) {
1121 Iterator i;
718db961
LP
1122 sd_bus *b;
1123 int fd;
b23de6af
LP
1124
1125 assert(m);
1126 assert(fds);
1127
1128 /* When we are about to reexecute we add all D-Bus fds to the
1129 * set to pass over to the newly executed systemd. They won't
718db961 1130 * be used there however, except thatt they are closed at the
b23de6af 1131 * very end of deserialization, those making it possible for
44143309 1132 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1133 * simply waiting for disconnection */
1134
718db961
LP
1135 if (m->api_bus) {
1136 fd = sd_bus_get_fd(m->api_bus);
1137 if (fd >= 0) {
b23de6af 1138 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1139 if (fd < 0)
1140 return fd;
1141 }
1142 }
1143
718db961
LP
1144 SET_FOREACH(b, m->private_buses, i) {
1145 fd = sd_bus_get_fd(b);
1146 if (fd >= 0) {
b23de6af 1147 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1148 if (fd < 0)
1149 return fd;
1150 }
1151 }
1152
718db961
LP
1153 /* We don't offer any APIs on the system bus (well, unless it
1154 * is the same as the API bus) hence we don't bother with it
1155 * here */
6fa48533 1156
718db961 1157 return 0;
6fa48533
LP
1158}
1159
8f8f05a9
LP
1160int bus_foreach_bus(
1161 Manager *m,
1162 sd_bus_track *subscribed2,
1163 int (*send_message)(sd_bus *bus, void *userdata),
1164 void *userdata) {
1165
1166 Iterator i;
1167 sd_bus *b;
1168 int r, ret = 0;
1169
ff9b60f3 1170 /* Send to all direct buses, unconditionally */
8f8f05a9
LP
1171 SET_FOREACH(b, m->private_buses, i) {
1172 r = send_message(b, userdata);
1173 if (r < 0)
1174 ret = r;
1175 }
1176
1177 /* Send to API bus, but only if somebody is subscribed */
1178 if (sd_bus_track_count(m->subscribed) > 0 ||
1179 sd_bus_track_count(subscribed2) > 0) {
1180 r = send_message(m->api_bus, userdata);
1181 if (r < 0)
1182 ret = r;
1183 }
1184
1185 return ret;
1186}
1187
1188void bus_track_serialize(sd_bus_track *t, FILE *f) {
1189 const char *n;
1190
6fa48533
LP
1191 assert(f);
1192
8f8f05a9
LP
1193 for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
1194 fprintf(f, "subscribed=%s\n", n);
6fa48533
LP
1195}
1196
8f8f05a9
LP
1197int bus_track_deserialize_item(char ***l, const char *line) {
1198 const char *e;
230314d7 1199 int r;
8f8f05a9
LP
1200
1201 assert(l);
6fa48533
LP
1202 assert(line);
1203
8f8f05a9
LP
1204 e = startswith(line, "subscribed=");
1205 if (!e)
230314d7
LP
1206 return 0;
1207
1208 r = strv_extend(l, e);
1209 if (r < 0)
1210 return r;
8f8f05a9 1211
230314d7 1212 return 1;
8f8f05a9
LP
1213}
1214
1215int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
1216 int r = 0;
1217
1218 assert(m);
1219 assert(t);
1220 assert(l);
1221
1222 if (!strv_isempty(*l) && m->api_bus) {
1223 char **i;
1224
1225 if (!*t) {
1226 r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
1227 if (r < 0)
1228 return r;
1229 }
1230
1231 r = 0;
1232 STRV_FOREACH(i, *l) {
1233 int k;
1234
1235 k = sd_bus_track_add_name(*t, *i);
1236 if (k < 0)
1237 r = k;
1238 }
1239 }
1240
6796073e 1241 *l = strv_free(*l);
8f8f05a9
LP
1242
1243 return r;
6fa48533 1244}
283868e1 1245
1d22e906 1246int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1247 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1
SW
1248}
1249
283868e1 1250int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1251 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1
SW
1252}
1253
1254int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1255 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", NULL, false, UID_INVALID, &m->polkit_registry, error);
283868e1 1256}
1d22e906
LP
1257
1258int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
403ed0e5 1259 return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error);
1d22e906 1260}