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