]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-util.c
sd-bus: make name validation functions public
[thirdparty/systemd.git] / src / shared / bus-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
40ca29a1 2
a8fbdf54
TA
3#include <errno.h>
4#include <fcntl.h>
5#include <inttypes.h>
a8fbdf54 6#include <stdlib.h>
a8fbdf54
TA
7#include <sys/ioctl.h>
8#include <sys/resource.h>
0c842e0a 9#include <sys/socket.h>
a8fbdf54 10#include <unistd.h>
0c842e0a 11
4f5dd394 12#include "sd-bus.h"
ebd011d9
LP
13#include "sd-daemon.h"
14#include "sd-event.h"
a8fbdf54 15#include "sd-id128.h"
d53d9474 16
b5efdb8a 17#include "alloc-util.h"
d53d9474 18#include "bus-internal.h"
1e9bc92d 19#include "bus-introspect.h"
d53d9474
LP
20#include "bus-label.h"
21#include "bus-message.h"
3ffd4af2 22#include "bus-util.h"
52610b02 23#include "cap-list.h"
21771f33 24#include "cgroup-util.h"
241c4b6a 25#include "escape.h"
049af8ad 26#include "mountpoint-util.h"
73186d53 27#include "nsflags.h"
6bedfcbb 28#include "parse-util.h"
657ee2d8 29#include "path-util.h"
78f22b97 30#include "rlimit-util.h"
269e4d2d 31#include "socket-util.h"
15a5e950 32#include "stdio-util.h"
d53d9474 33#include "strv.h"
ee104e11 34#include "user-util.h"
40ca29a1 35
19070062 36static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40ca29a1
LP
37 sd_event *e = userdata;
38
40ca29a1
LP
39 assert(m);
40 assert(e);
41
19070062 42 sd_bus_close(sd_bus_message_get_bus(m));
6203e07a 43 sd_event_exit(e, 0);
b27adf35 44
40ca29a1
LP
45 return 1;
46}
47
6203e07a 48int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
75152a4d 49 const char *match;
11846aa7 50 const char *unique;
40ca29a1
LP
51 int r;
52
53 assert(e);
54 assert(bus);
55 assert(name);
56
6203e07a
LP
57 /* We unregister the name here and then wait for the
58 * NameOwnerChanged signal for this event to arrive before we
59 * quit. We do this in order to make sure that any queued
60 * requests are still processed before we really exit. */
61
11846aa7 62 r = sd_bus_get_unique_name(bus, &unique);
40ca29a1
LP
63 if (r < 0)
64 return r;
65
75152a4d
LP
66 match = strjoina(
67 "sender='org.freedesktop.DBus',"
68 "type='signal',"
69 "interface='org.freedesktop.DBus',"
70 "member='NameOwnerChanged',"
71 "path='/org/freedesktop/DBus',"
72 "arg0='", name, "',",
73 "arg1='", unique, "',",
74 "arg2=''");
75
76 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
40ca29a1
LP
77 if (r < 0)
78 return r;
79
75152a4d 80 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
40ca29a1
LP
81 if (r < 0)
82 return r;
83
40ca29a1
LP
84 return 0;
85}
86
37224a5f
LP
87int bus_event_loop_with_idle(
88 sd_event *e,
89 sd_bus *bus,
90 const char *name,
91 usec_t timeout,
92 check_idle_t check_idle,
93 void *userdata) {
40ca29a1 94 bool exiting = false;
6203e07a 95 int r, code;
40ca29a1
LP
96
97 assert(e);
98 assert(bus);
99 assert(name);
100
101 for (;;) {
37224a5f
LP
102 bool idle;
103
40ca29a1
LP
104 r = sd_event_get_state(e);
105 if (r < 0)
106 return r;
40ca29a1
LP
107 if (r == SD_EVENT_FINISHED)
108 break;
109
37224a5f
LP
110 if (check_idle)
111 idle = check_idle(userdata);
112 else
113 idle = true;
114
115 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
40ca29a1
LP
116 if (r < 0)
117 return r;
118
a8ba6cd1 119 if (r == 0 && !exiting && idle) {
99cde098
ZJS
120 /* Inform the service manager that we are going down, so that it will queue all
121 * further start requests, instead of assuming we are already running. */
122 sd_notify(false, "STOPPING=1");
b27adf35 123
99cde098 124 r = bus_async_unregister_and_exit(e, bus, name);
40ca29a1
LP
125 if (r < 0)
126 return r;
127
99cde098
ZJS
128 exiting = true;
129 continue;
40ca29a1
LP
130 }
131 }
132
6203e07a
LP
133 r = sd_event_get_exit_code(e, &code);
134 if (r < 0)
135 return r;
136
137 return code;
40ca29a1
LP
138}
139
5fd38859 140int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
4afd3348 141 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
5fd38859
DH
142 int r, has_owner = 0;
143
144 assert(c);
145 assert(name);
146
147 r = sd_bus_call_method(c,
148 "org.freedesktop.DBus",
149 "/org/freedesktop/dbus",
150 "org.freedesktop.DBus",
151 "NameHasOwner",
152 error,
153 &rep,
154 "s",
155 name);
156 if (r < 0)
157 return r;
158
159 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
160 if (r < 0)
161 return sd_bus_error_set_errno(error, r);
162
163 return has_owner;
164}
165
718db961 166int bus_check_peercred(sd_bus *c) {
0c842e0a 167 struct ucred ucred;
3e641e36 168 int fd, r;
0c842e0a
TG
169
170 assert(c);
171
172 fd = sd_bus_get_fd(c);
0f8bd8de
LP
173 if (fd < 0)
174 return fd;
0c842e0a 175
3e641e36
LP
176 r = getpeercred(fd, &ucred);
177 if (r < 0)
178 return r;
0c842e0a
TG
179
180 if (ucred.uid != 0 && ucred.uid != geteuid())
181 return -EPERM;
182
183 return 1;
184}
185
266f3e26 186int bus_connect_system_systemd(sd_bus **_bus) {
b1a4981a 187 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
0c842e0a 188 int r;
0c842e0a
TG
189
190 assert(_bus);
191
0f8bd8de 192 if (geteuid() != 0)
266f3e26 193 return sd_bus_default_system(_bus);
a1da8583 194
a132bef0
ZJS
195 /* If we are root then let's talk directly to the system
196 * instance, instead of going via the bus */
a6aa8912
LP
197
198 r = sd_bus_new(&bus);
0f8bd8de
LP
199 if (r < 0)
200 return r;
a1da8583 201
a6aa8912
LP
202 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
203 if (r < 0)
204 return r;
205
206 r = sd_bus_start(bus);
207 if (r < 0)
266f3e26 208 return sd_bus_default_system(_bus);
a6aa8912 209
0f8bd8de 210 r = bus_check_peercred(bus);
a1da8583
TG
211 if (r < 0)
212 return r;
213
1cc6c93a 214 *_bus = TAKE_PTR(bus);
0f8bd8de 215
a1da8583
TG
216 return 0;
217}
218
266f3e26 219int bus_connect_user_systemd(sd_bus **_bus) {
b1a4981a 220 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
a6aa8912 221 _cleanup_free_ char *ee = NULL;
41dd15e4
LP
222 const char *e;
223 int r;
224
41dd15e4
LP
225 assert(_bus);
226
227 e = secure_getenv("XDG_RUNTIME_DIR");
537220d9 228 if (!e)
266f3e26 229 return sd_bus_default_user(_bus);
537220d9 230
a6aa8912
LP
231 ee = bus_address_escape(e);
232 if (!ee)
537220d9 233 return -ENOMEM;
41dd15e4
LP
234
235 r = sd_bus_new(&bus);
236 if (r < 0)
237 return r;
238
605405c6 239 bus->address = strjoin("unix:path=", ee, "/systemd/private");
a6aa8912
LP
240 if (!bus->address)
241 return -ENOMEM;
41dd15e4
LP
242
243 r = sd_bus_start(bus);
244 if (r < 0)
266f3e26 245 return sd_bus_default_user(_bus);
41dd15e4
LP
246
247 r = bus_check_peercred(bus);
248 if (r < 0)
249 return r;
250
1cc6c93a 251 *_bus = TAKE_PTR(bus);
41dd15e4
LP
252
253 return 0;
254}
255
102b0214
YW
256int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value) {
257 assert(name);
258
259 if (expected_value && !streq_ptr(expected_value, value))
260 return 0;
261
262 if (only_value)
263 puts(value);
264 else
265 printf("%s=%s\n", name, value);
266
267 return 0;
268}
269
270int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
eda19357
YW
271 va_list ap;
272 int r;
273
274 assert(name);
275 assert(fmt);
276
277 if (expected_value) {
278 _cleanup_free_ char *s = NULL;
279
280 va_start(ap, fmt);
281 r = vasprintf(&s, fmt, ap);
282 va_end(ap);
283 if (r < 0)
284 return -ENOMEM;
285
286 if (streq_ptr(expected_value, s)) {
287 if (only_value)
288 puts(s);
289 else
290 printf("%s=%s\n", name, s);
291 }
292
293 return 0;
294 }
295
296 if (!only_value)
297 printf("%s=", name);
298 va_start(ap, fmt);
299 vprintf(fmt, ap);
300 va_end(ap);
301 puts("");
302
303 return 0;
304}
305
306static int bus_print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
a1da8583
TG
307 char type;
308 const char *contents;
9f6eb1cd 309 int r;
a1da8583
TG
310
311 assert(name);
07636114 312 assert(m);
a1da8583 313
07636114 314 r = sd_bus_message_peek_type(m, &type, &contents);
9f6eb1cd
KS
315 if (r < 0)
316 return r;
a1da8583
TG
317
318 switch (type) {
319
320 case SD_BUS_TYPE_STRING: {
321 const char *s;
9f6eb1cd 322
07636114 323 r = sd_bus_message_read_basic(m, type, &s);
9f6eb1cd
KS
324 if (r < 0)
325 return r;
a1da8583 326
5993d46a
ZJS
327 if (all || !isempty(s)) {
328 bool good;
329
330 /* This property has a single value, so we need to take
331 * care not to print a new line, everything else is OK. */
332 good = !strchr(s, '\n');
102b0214 333 bus_print_property_value(name, expected_value, value, good ? s : "[unprintable]");
5993d46a 334 }
a1da8583
TG
335
336 return 1;
337 }
338
339 case SD_BUS_TYPE_BOOLEAN: {
c2fa048c 340 int b;
a1da8583 341
07636114 342 r = sd_bus_message_read_basic(m, type, &b);
9f6eb1cd
KS
343 if (r < 0)
344 return r;
345
eda19357
YW
346 if (expected_value && parse_boolean(expected_value) != b)
347 return 1;
a1da8583 348
102b0214 349 bus_print_property_value(name, NULL, value, yes_no(b));
a1da8583
TG
350 return 1;
351 }
352
353 case SD_BUS_TYPE_UINT64: {
354 uint64_t u;
355
07636114 356 r = sd_bus_message_read_basic(m, type, &u);
9f6eb1cd
KS
357 if (r < 0)
358 return r;
a1da8583
TG
359
360 /* Yes, heuristics! But we can change this check
361 * should it turn out to not be sufficient */
362
ead0adb1
YW
363 if (endswith(name, "Timestamp") ||
364 STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) {
4d9685be
ZJS
365 char timestamp[FORMAT_TIMESTAMP_MAX];
366 const char *t;
a1da8583
TG
367
368 t = format_timestamp(timestamp, sizeof(timestamp), u);
369 if (t || all)
102b0214 370 bus_print_property_value(name, expected_value, value, strempty(t));
a1da8583
TG
371
372 } else if (strstr(name, "USec")) {
373 char timespan[FORMAT_TIMESPAN_MAX];
374
eda19357 375 (void) format_timespan(timespan, sizeof(timespan), u, 0);
102b0214 376 bus_print_property_value(name, expected_value, value, timespan);
eda19357 377
ad21e542
ZJS
378 } else if (streq(name, "CoredumpFilter")) {
379 char buf[STRLEN("0xFFFFFFFF")];
380
381 xsprintf(buf, "0x%"PRIx64, u);
382 bus_print_property_value(name, expected_value, value, buf);
383
73186d53
DH
384 } else if (streq(name, "RestrictNamespaces")) {
385 _cleanup_free_ char *s = NULL;
ae978b9f 386 const char *result;
73186d53
DH
387
388 if ((u & NAMESPACE_FLAGS_ALL) == 0)
389 result = "yes";
0c21dafb 390 else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL))
73186d53
DH
391 result = "no";
392 else {
86c2a9f1 393 r = namespace_flags_to_string(u, &s);
73186d53
DH
394 if (r < 0)
395 return r;
396
dd0395b5 397 result = strempty(s);
73186d53
DH
398 }
399
102b0214 400 bus_print_property_value(name, expected_value, value, result);
21771f33
YW
401
402 } else if (streq(name, "MountFlags")) {
ae978b9f 403 const char *result;
21771f33
YW
404
405 result = mount_propagation_flags_to_string(u);
406 if (!result)
407 return -EINVAL;
408
102b0214 409 bus_print_property_value(name, expected_value, value, result);
21771f33 410
52610b02
YW
411 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
412 _cleanup_free_ char *s = NULL;
413
414 r = capability_set_to_string_alloc(u, &s);
415 if (r < 0)
416 return r;
417
102b0214 418 bus_print_property_value(name, expected_value, value, s);
52610b02 419
21771f33
YW
420 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
421 (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
422 (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
423 (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
424 (endswith(name, "NSec") && u == (uint64_t) -1))
425
102b0214 426 bus_print_property_value(name, expected_value, value, "[not set]");
21771f33 427
7e7223b3 428 else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
21771f33
YW
429 (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
430 (startswith(name, "Limit") && u == (uint64_t) -1) ||
431 (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
432
102b0214 433 bus_print_property_value(name, expected_value, value, "infinity");
56c6b690
YW
434 else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1)
435 bus_print_property_value(name, expected_value, value, "[no data]");
21771f33 436 else
102b0214 437 bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u);
a1da8583
TG
438
439 return 1;
440 }
441
d7161865
DM
442 case SD_BUS_TYPE_INT64: {
443 int64_t i;
444
07636114 445 r = sd_bus_message_read_basic(m, type, &i);
d7161865
DM
446 if (r < 0)
447 return r;
448
102b0214 449 bus_print_property_valuef(name, expected_value, value, "%"PRIi64, i);
d7161865
DM
450 return 1;
451 }
452
a1da8583
TG
453 case SD_BUS_TYPE_UINT32: {
454 uint32_t u;
455
07636114 456 r = sd_bus_message_read_basic(m, type, &u);
9f6eb1cd
KS
457 if (r < 0)
458 return r;
a1da8583
TG
459
460 if (strstr(name, "UMask") || strstr(name, "Mode"))
102b0214 461 bus_print_property_valuef(name, expected_value, value, "%04o", u);
eda19357 462
c533658a
ZJS
463 else if (streq(name, "UID")) {
464 if (u == UID_INVALID)
102b0214 465 bus_print_property_value(name, expected_value, value, "[not set]");
c533658a 466 else
102b0214 467 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
c533658a
ZJS
468 } else if (streq(name, "GID")) {
469 if (u == GID_INVALID)
102b0214 470 bus_print_property_value(name, expected_value, value, "[not set]");
c533658a 471 else
102b0214 472 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
c533658a 473 } else
102b0214 474 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
a1da8583
TG
475
476 return 1;
477 }
478
479 case SD_BUS_TYPE_INT32: {
480 int32_t i;
481
07636114 482 r = sd_bus_message_read_basic(m, type, &i);
9f6eb1cd
KS
483 if (r < 0)
484 return r;
a1da8583 485
102b0214 486 bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
a1da8583
TG
487 return 1;
488 }
489
490 case SD_BUS_TYPE_DOUBLE: {
491 double d;
492
07636114 493 r = sd_bus_message_read_basic(m, type, &d);
9f6eb1cd
KS
494 if (r < 0)
495 return r;
a1da8583 496
102b0214 497 bus_print_property_valuef(name, expected_value, value, "%g", d);
a1da8583
TG
498 return 1;
499 }
500
501 case SD_BUS_TYPE_ARRAY:
a1da8583 502 if (streq(contents, "s")) {
261afec5
MAP
503 bool first = true;
504 const char *str;
a1da8583 505
07636114 506 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
9f6eb1cd
KS
507 if (r < 0)
508 return r;
509
07636114 510 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
241c4b6a 511 _cleanup_free_ char *e = NULL;
5993d46a 512
241c4b6a
ZJS
513 e = shell_maybe_quote(str, ESCAPE_BACKSLASH_ONELINE);
514 if (!e)
515 return -ENOMEM;
261afec5 516
241c4b6a
ZJS
517 if (first) {
518 if (!value)
519 printf("%s=", name);
520 first = false;
521 } else
522 fputs(" ", stdout);
5993d46a 523
241c4b6a 524 fputs(e, stdout);
261afec5 525 }
9f6eb1cd
KS
526 if (r < 0)
527 return r;
a1da8583 528
4f9a9105 529 if (first && all && !value)
a1da8583 530 printf("%s=", name);
261afec5 531 if (!first || all)
a1da8583 532 puts("");
a1da8583 533
07636114 534 r = sd_bus_message_exit_container(m);
9f6eb1cd
KS
535 if (r < 0)
536 return r;
a1da8583
TG
537
538 return 1;
539
540 } else if (streq(contents, "y")) {
541 const uint8_t *u;
542 size_t n;
543
07636114 544 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
9f6eb1cd
KS
545 if (r < 0)
546 return r;
547
a1da8583 548 if (all || n > 0) {
14cb109d 549 unsigned i;
a1da8583 550
4f9a9105
ZJS
551 if (!value)
552 printf("%s=", name);
a1da8583
TG
553
554 for (i = 0; i < n; i++)
555 printf("%02x", u[i]);
556
557 puts("");
558 }
559
560 return 1;
561
562 } else if (streq(contents, "u")) {
563 uint32_t *u;
564 size_t n;
565
07636114 566 r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
9f6eb1cd
KS
567 if (r < 0)
568 return r;
569
a1da8583 570 if (all || n > 0) {
14cb109d 571 unsigned i;
a1da8583 572
4f9a9105
ZJS
573 if (!value)
574 printf("%s=", name);
a1da8583
TG
575
576 for (i = 0; i < n; i++)
577 printf("%08x", u[i]);
578
579 puts("");
580 }
581
582 return 1;
583 }
584
585 break;
586 }
587
588 return 0;
589}
d21ed1ea 590
07636114
YW
591int bus_message_print_all_properties(
592 sd_bus_message *m,
593 bus_message_print_t func,
594 char **filter,
595 bool value,
596 bool all,
597 Set **found_properties) {
ffc06c35 598
07636114 599 int r;
9f6eb1cd 600
07636114 601 assert(m);
ffc06c35 602
07636114 603 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
604 if (r < 0)
605 return r;
606
07636114 607 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
eda19357
YW
608 _cleanup_free_ char *name_with_equal = NULL;
609 const char *name, *contents, *expected_value = NULL;
ffc06c35 610
07636114 611 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
612 if (r < 0)
613 return r;
614
07636114
YW
615 if (found_properties) {
616 r = set_ensure_allocated(found_properties, &string_hash_ops);
617 if (r < 0)
618 return log_oom();
619
620 r = set_put(*found_properties, name);
0ceff906 621 if (r < 0 && r != -EEXIST)
07636114
YW
622 return log_oom();
623 }
624
b910cc72 625 name_with_equal = strjoin(name, "=");
eda19357
YW
626 if (!name_with_equal)
627 return log_oom();
628
629 if (!filter || strv_find(filter, name) ||
630 (expected_value = strv_find_startswith(filter, name_with_equal))) {
07636114 631 r = sd_bus_message_peek_type(m, NULL, &contents);
9f6eb1cd
KS
632 if (r < 0)
633 return r;
634
07636114 635 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
9f6eb1cd
KS
636 if (r < 0)
637 return r;
ffc06c35 638
07636114 639 if (func)
eda19357 640 r = func(name, expected_value, m, value, all);
07636114 641 if (!func || r == 0)
eda19357 642 r = bus_print_property(name, expected_value, m, value, all);
9f6eb1cd
KS
643 if (r < 0)
644 return r;
27e72d6b 645 if (r == 0) {
eda19357 646 if (all && !expected_value)
27e72d6b
SP
647 printf("%s=[unprintable]\n", name);
648 /* skip what we didn't read */
07636114 649 r = sd_bus_message_skip(m, contents);
27e72d6b
SP
650 if (r < 0)
651 return r;
652 }
9f6eb1cd 653
07636114 654 r = sd_bus_message_exit_container(m);
9f6eb1cd
KS
655 if (r < 0)
656 return r;
657 } else {
07636114 658 r = sd_bus_message_skip(m, "v");
9f6eb1cd
KS
659 if (r < 0)
660 return r;
661 }
662
07636114 663 r = sd_bus_message_exit_container(m);
ffc06c35
KS
664 if (r < 0)
665 return r;
9f6eb1cd
KS
666 }
667 if (r < 0)
668 return r;
ffc06c35 669
07636114 670 r = sd_bus_message_exit_container(m);
9f6eb1cd
KS
671 if (r < 0)
672 return r;
ffc06c35 673
9f6eb1cd
KS
674 return 0;
675}
ffc06c35 676
07636114
YW
677int bus_print_all_properties(
678 sd_bus *bus,
679 const char *dest,
680 const char *path,
681 bus_message_print_t func,
682 char **filter,
683 bool value,
684 bool all,
685 Set **found_properties) {
686
687 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
688 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
689 int r;
690
691 assert(bus);
692 assert(path);
693
694 r = sd_bus_call_method(bus,
695 dest,
696 path,
697 "org.freedesktop.DBus.Properties",
698 "GetAll",
699 &error,
700 &reply,
701 "s", "");
702 if (r < 0)
703 return r;
704
705 return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
706}
707
9f6eb1cd
KS
708int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
709 sd_id128_t *p = userdata;
710 const void *v;
711 size_t n;
712 int r;
ffc06c35 713
9f6eb1cd
KS
714 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
715 if (r < 0)
716 return r;
ffc06c35 717
9f6eb1cd
KS
718 if (n == 0)
719 *p = SD_ID128_NULL;
720 else if (n == 16)
721 memcpy((*p).bytes, v, n);
722 else
723 return -EINVAL;
ffc06c35 724
9f6eb1cd
KS
725 return 0;
726}
ffc06c35 727
a7e4861c 728static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
9f6eb1cd
KS
729 char type;
730 int r;
ffc06c35 731
9f6eb1cd
KS
732 r = sd_bus_message_peek_type(m, &type, NULL);
733 if (r < 0)
734 return r;
ffc06c35 735
9f6eb1cd 736 switch (type) {
8b3b6f58 737
16a8f172
YW
738 case SD_BUS_TYPE_STRING:
739 case SD_BUS_TYPE_OBJECT_PATH: {
f37f8a61 740 const char **p = userdata;
8b3b6f58 741 const char *s;
ffc06c35 742
9f6eb1cd
KS
743 r = sd_bus_message_read_basic(m, type, &s);
744 if (r < 0)
8b3b6f58 745 return r;
ffc06c35 746
9f6eb1cd 747 if (isempty(s))
0b83b8a4 748 s = NULL;
ffc06c35 749
a7e4861c 750 if (flags & BUS_MAP_STRDUP)
f37f8a61
YW
751 return free_and_strdup((char **) userdata, s);
752
753 *p = s;
754 return 0;
9f6eb1cd 755 }
ffc06c35 756
9f6eb1cd 757 case SD_BUS_TYPE_ARRAY: {
7d6884b6
TA
758 _cleanup_strv_free_ char **l = NULL;
759 char ***p = userdata;
ffc06c35 760
9f6eb1cd
KS
761 r = bus_message_read_strv_extend(m, &l);
762 if (r < 0)
8b3b6f58 763 return r;
ffc06c35 764
411975ce 765 return strv_extend_strv(p, l, false);
9f6eb1cd 766 }
ffc06c35 767
9f6eb1cd 768 case SD_BUS_TYPE_BOOLEAN: {
a7e4861c 769 int b;
ffc06c35 770
9f6eb1cd
KS
771 r = sd_bus_message_read_basic(m, type, &b);
772 if (r < 0)
8b3b6f58 773 return r;
ffc06c35 774
a7e4861c 775 if (flags & BUS_MAP_BOOLEAN_AS_BOOL)
5d904a6a 776 *(bool*) userdata = b;
a7e4861c 777 else
5d904a6a 778 *(int*) userdata = b;
a7e4861c 779
8b3b6f58 780 return 0;
9f6eb1cd 781 }
ffc06c35 782
bdf97b8a 783 case SD_BUS_TYPE_INT32:
9f6eb1cd 784 case SD_BUS_TYPE_UINT32: {
bdf97b8a 785 uint32_t u, *p = userdata;
9f6eb1cd
KS
786
787 r = sd_bus_message_read_basic(m, type, &u);
788 if (r < 0)
8b3b6f58 789 return r;
ffc06c35 790
9f6eb1cd 791 *p = u;
8b3b6f58 792 return 0;
9f6eb1cd
KS
793 }
794
bdf97b8a 795 case SD_BUS_TYPE_INT64:
9f6eb1cd 796 case SD_BUS_TYPE_UINT64: {
bdf97b8a 797 uint64_t t, *p = userdata;
9f6eb1cd
KS
798
799 r = sd_bus_message_read_basic(m, type, &t);
800 if (r < 0)
8b3b6f58 801 return r;
ffc06c35 802
9f6eb1cd 803 *p = t;
8b3b6f58 804 return 0;
9f6eb1cd
KS
805 }
806
52e045f9 807 case SD_BUS_TYPE_DOUBLE: {
8b3b6f58 808 double d, *p = userdata;
52e045f9
SS
809
810 r = sd_bus_message_read_basic(m, type, &d);
811 if (r < 0)
8b3b6f58 812 return r;
52e045f9
SS
813
814 *p = d;
8b3b6f58
LP
815 return 0;
816 }}
52e045f9 817
8b3b6f58 818 return -EOPNOTSUPP;
9f6eb1cd
KS
819}
820
fe506d56
LP
821int bus_message_map_all_properties(
822 sd_bus_message *m,
823 const struct bus_properties_map *map,
a7e4861c 824 unsigned flags,
f9e0eefc 825 sd_bus_error *error,
fe506d56
LP
826 void *userdata) {
827
9f6eb1cd
KS
828 int r;
829
aae2b488 830 assert(m);
9f6eb1cd
KS
831 assert(map);
832
9f6eb1cd
KS
833 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
834 if (r < 0)
835 return r;
836
837 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
838 const struct bus_properties_map *prop;
839 const char *member;
840 const char *contents;
841 void *v;
842 unsigned i;
843
844 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
845 if (r < 0)
846 return r;
847
9f6eb1cd
KS
848 for (i = 0, prop = NULL; map[i].member; i++)
849 if (streq(map[i].member, member)) {
850 prop = &map[i];
851 break;
852 }
853
854 if (prop) {
855 r = sd_bus_message_peek_type(m, NULL, &contents);
856 if (r < 0)
857 return r;
858
859 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
860 if (r < 0)
861 return r;
862
863 v = (uint8_t *)userdata + prop->offset;
27e72d6b 864 if (map[i].set)
f9e0eefc 865 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
9f6eb1cd 866 else
a7e4861c 867 r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
2b49a470
TA
868 if (r < 0)
869 return r;
9f6eb1cd
KS
870
871 r = sd_bus_message_exit_container(m);
872 if (r < 0)
873 return r;
874 } else {
875 r = sd_bus_message_skip(m, "v");
876 if (r < 0)
6c1508b8 877 return r;
9f6eb1cd
KS
878 }
879
ffc06c35
KS
880 r = sd_bus_message_exit_container(m);
881 if (r < 0)
882 return r;
883 }
fe506d56
LP
884 if (r < 0)
885 return r;
ffc06c35 886
aae2b488
DH
887 return sd_bus_message_exit_container(m);
888}
889
fe506d56
LP
890int bus_map_all_properties(
891 sd_bus *bus,
892 const char *destination,
893 const char *path,
894 const struct bus_properties_map *map,
a7e4861c 895 unsigned flags,
f9e0eefc 896 sd_bus_error *error,
f37f8a61 897 sd_bus_message **reply,
fe506d56
LP
898 void *userdata) {
899
4afd3348 900 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
aae2b488
DH
901 int r;
902
903 assert(bus);
904 assert(destination);
905 assert(path);
906 assert(map);
a7e4861c 907 assert(reply || (flags & BUS_MAP_STRDUP));
aae2b488
DH
908
909 r = sd_bus_call_method(
910 bus,
911 destination,
912 path,
913 "org.freedesktop.DBus.Properties",
914 "GetAll",
f9e0eefc 915 error,
aae2b488
DH
916 &m,
917 "s", "");
918 if (r < 0)
919 return r;
920
a7e4861c 921 r = bus_message_map_all_properties(m, map, flags, error, userdata);
f37f8a61
YW
922 if (r < 0)
923 return r;
924
925 if (reply)
926 *reply = sd_bus_message_ref(m);
927
928 return r;
ffc06c35
KS
929}
930
38303498 931int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
b1a4981a 932 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
d21ed1ea
LP
933 int r;
934
935 assert(transport >= 0);
936 assert(transport < _BUS_TRANSPORT_MAX);
38303498 937 assert(ret);
d21ed1ea
LP
938
939 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 940 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
d21ed1ea
LP
941
942 switch (transport) {
943
944 case BUS_TRANSPORT_LOCAL:
945 if (user)
38303498 946 r = sd_bus_default_user(&bus);
fb507898
YW
947 else {
948 if (sd_booted() <= 0) {
949 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
950 log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
d21ed1ea 951
fb507898
YW
952 return -EHOSTDOWN;
953 }
954 r = sd_bus_default_system(&bus);
955 }
d21ed1ea
LP
956 break;
957
958 case BUS_TRANSPORT_REMOTE:
38303498 959 r = sd_bus_open_system_remote(&bus, host);
41dd15e4
LP
960 break;
961
de33fc62 962 case BUS_TRANSPORT_MACHINE:
38303498 963 r = sd_bus_open_system_machine(&bus, host);
41dd15e4
LP
964 break;
965
966 default:
967 assert_not_reached("Hmm, unknown transport type.");
968 }
38303498
LP
969 if (r < 0)
970 return r;
41dd15e4 971
38303498
LP
972 r = sd_bus_set_exit_on_disconnect(bus, true);
973 if (r < 0)
974 return r;
975
1cc6c93a 976 *ret = TAKE_PTR(bus);
38303498
LP
977
978 return 0;
41dd15e4
LP
979}
980
266f3e26 981int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
41dd15e4
LP
982 int r;
983
984 assert(transport >= 0);
985 assert(transport < _BUS_TRANSPORT_MAX);
986 assert(bus);
987
988 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 989 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
41dd15e4
LP
990
991 switch (transport) {
992
993 case BUS_TRANSPORT_LOCAL:
994 if (user)
266f3e26 995 r = bus_connect_user_systemd(bus);
fb507898 996 else {
baaa35ad 997 if (sd_booted() <= 0)
fb507898 998 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
baaa35ad
ZJS
999 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
1000 "System has not been booted with systemd as init system (PID 1). Can't operate.");
fb507898
YW
1001 r = bus_connect_system_systemd(bus);
1002 }
41dd15e4
LP
1003 break;
1004
1005 case BUS_TRANSPORT_REMOTE:
3db729cb 1006 r = sd_bus_open_system_remote(bus, host);
d21ed1ea
LP
1007 break;
1008
de33fc62
LP
1009 case BUS_TRANSPORT_MACHINE:
1010 r = sd_bus_open_system_machine(bus, host);
d21ed1ea
LP
1011 break;
1012
1013 default:
1014 assert_not_reached("Hmm, unknown transport type.");
1015 }
1016
1017 return r;
1018}
e6504030
LP
1019
1020int bus_property_get_bool(
1021 sd_bus *bus,
1022 const char *path,
1023 const char *interface,
1024 const char *property,
1025 sd_bus_message *reply,
ebcf1f97
LP
1026 void *userdata,
1027 sd_bus_error *error) {
e6504030
LP
1028
1029 int b = *(bool*) userdata;
1030
1031 return sd_bus_message_append_basic(reply, 'b', &b);
1032}
1033
43ce15ac
JK
1034int bus_property_set_bool(
1035 sd_bus *bus,
1036 const char *path,
1037 const char *interface,
1038 const char *property,
1039 sd_bus_message *value,
1040 void *userdata,
1041 sd_bus_error *error) {
1042
1043 int b, r;
1044
1045 r = sd_bus_message_read(value, "b", &b);
1046 if (r < 0)
1047 return r;
1048
5d904a6a 1049 *(bool*) userdata = b;
43ce15ac
JK
1050 return 0;
1051}
1052
766c94ad
LP
1053int bus_property_get_id128(
1054 sd_bus *bus,
1055 const char *path,
1056 const char *interface,
1057 const char *property,
1058 sd_bus_message *reply,
1059 void *userdata,
1060 sd_bus_error *error) {
1061
1062 sd_id128_t *id = userdata;
1063
1064 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1065 return sd_bus_message_append(reply, "ay", 0);
1066 else
4b58153d 1067 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
766c94ad
LP
1068}
1069
718db961
LP
1070#if __SIZEOF_SIZE_T__ != 8
1071int bus_property_get_size(
e6504030
LP
1072 sd_bus *bus,
1073 const char *path,
1074 const char *interface,
1075 const char *property,
1076 sd_bus_message *reply,
ebcf1f97
LP
1077 void *userdata,
1078 sd_bus_error *error) {
e6504030 1079
718db961 1080 uint64_t sz = *(size_t*) userdata;
e6504030 1081
718db961 1082 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1083}
718db961
LP
1084#endif
1085
1086#if __SIZEOF_LONG__ != 8
1087int bus_property_get_long(
1088 sd_bus *bus,
1089 const char *path,
1090 const char *interface,
1091 const char *property,
1092 sd_bus_message *reply,
ebcf1f97
LP
1093 void *userdata,
1094 sd_bus_error *error) {
718db961
LP
1095
1096 int64_t l = *(long*) userdata;
1097
1098 return sd_bus_message_append_basic(reply, 'x', &l);
1099}
1100
1101int bus_property_get_ulong(
1102 sd_bus *bus,
1103 const char *path,
1104 const char *interface,
1105 const char *property,
1106 sd_bus_message *reply,
ebcf1f97
LP
1107 void *userdata,
1108 sd_bus_error *error) {
718db961
LP
1109
1110 uint64_t ul = *(unsigned long*) userdata;
1111
1112 return sd_bus_message_append_basic(reply, 't', &ul);
1113}
1114#endif
5b30bef8 1115
98a4c30b
DH
1116/**
1117 * bus_path_encode_unique() - encode unique object path
1118 * @b: bus connection or NULL
1119 * @prefix: object path prefix
1120 * @sender_id: unique-name of client, or NULL
1121 * @external_id: external ID to be chosen by client, or NULL
1122 * @ret_path: storage for encoded object path pointer
1123 *
1124 * Whenever we provide a bus API that allows clients to create and manage
1125 * server-side objects, we need to provide a unique name for these objects. If
1126 * we let the server choose the name, we suffer from a race condition: If a
1127 * client creates an object asynchronously, it cannot destroy that object until
1128 * it received the method reply. It cannot know the name of the new object,
1129 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1130 *
1131 * Therefore, many APIs allow the client to choose the unique name for newly
1132 * created objects. There're two problems to solve, though:
1133 * 1) Object names are usually defined via dbus object paths, which are
1134 * usually globally namespaced. Therefore, multiple clients must be able
1135 * to choose unique object names without interference.
1136 * 2) If multiple libraries share the same bus connection, they must be
1137 * able to choose unique object names without interference.
1138 * The first problem is solved easily by prefixing a name with the
1139 * unique-bus-name of a connection. The server side must enforce this and
1140 * reject any other name. The second problem is solved by providing unique
1141 * suffixes from within sd-bus.
1142 *
1143 * This helper allows clients to create unique object-paths. It uses the
1144 * template '/prefix/sender_id/external_id' and returns the new path in
1145 * @ret_path (must be freed by the caller).
1146 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1147 * NULL, this function allocates a unique suffix via @b (by requesting a new
1148 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1149 * NULL.
1150 *
1151 * Returns: 0 on success, negative error code on failure.
1152 */
1153int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1154 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1155 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1156 int r;
1157
1158 assert_return(b || (sender_id && external_id), -EINVAL);
1159 assert_return(object_path_is_valid(prefix), -EINVAL);
1160 assert_return(ret_path, -EINVAL);
1161
1162 if (!sender_id) {
1163 r = sd_bus_get_unique_name(b, &sender_id);
1164 if (r < 0)
1165 return r;
1166 }
1167
1168 if (!external_id) {
1169 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1170 external_id = external_buf;
1171 }
1172
1173 sender_label = bus_label_escape(sender_id);
1174 if (!sender_label)
1175 return -ENOMEM;
1176
1177 external_label = bus_label_escape(external_id);
1178 if (!external_label)
1179 return -ENOMEM;
1180
657ee2d8 1181 p = path_join(prefix, sender_label, external_label);
98a4c30b
DH
1182 if (!p)
1183 return -ENOMEM;
1184
1185 *ret_path = p;
1186 return 0;
1187}
1188
1189/**
1190 * bus_path_decode_unique() - decode unique object path
1191 * @path: object path to decode
1192 * @prefix: object path prefix
1193 * @ret_sender: output parameter for sender-id label
1194 * @ret_external: output parameter for external-id label
1195 *
1196 * This does the reverse of bus_path_encode_unique() (see its description for
1197 * details). Both trailing labels, sender-id and external-id, are unescaped and
1198 * returned in the given output parameters (the caller must free them).
1199 *
1200 * Note that this function returns 0 if the path does not match the template
1201 * (see bus_path_encode_unique()), 1 if it matched.
1202 *
1203 * Returns: Negative error code on failure, 0 if the given object path does not
1204 * match the template (return parameters are set to NULL), 1 if it was
1205 * parsed successfully (return parameters contain allocated labels).
1206 */
1207int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1208 const char *p, *q;
1209 char *sender, *external;
1210
1211 assert(object_path_is_valid(path));
1212 assert(object_path_is_valid(prefix));
1213 assert(ret_sender);
1214 assert(ret_external);
1215
1216 p = object_path_startswith(path, prefix);
1217 if (!p) {
1218 *ret_sender = NULL;
1219 *ret_external = NULL;
1220 return 0;
1221 }
1222
1223 q = strchr(p, '/');
1224 if (!q) {
1225 *ret_sender = NULL;
1226 *ret_external = NULL;
1227 return 0;
1228 }
1229
1230 sender = bus_label_unescape_n(p, q - p);
1231 external = bus_label_unescape(q + 1);
1232 if (!sender || !external) {
1233 free(sender);
1234 free(external);
1235 return -ENOMEM;
1236 }
1237
1238 *ret_sender = sender;
1239 *ret_external = external;
1240 return 1;
1241}
057171ef 1242
c9d031c3
EV
1243int bus_property_get_rlimit(
1244 sd_bus *bus,
1245 const char *path,
1246 const char *interface,
1247 const char *property,
1248 sd_bus_message *reply,
1249 void *userdata,
1250 sd_bus_error *error) {
1251
6550c24c 1252 const char *is_soft;
c9d031c3
EV
1253 struct rlimit *rl;
1254 uint64_t u;
1255 rlim_t x;
1256
1257 assert(bus);
1258 assert(reply);
1259 assert(userdata);
1260
147f6858 1261 is_soft = endswith(property, "Soft");
6550c24c 1262
c9d031c3
EV
1263 rl = *(struct rlimit**) userdata;
1264 if (rl)
147f6858 1265 x = is_soft ? rl->rlim_cur : rl->rlim_max;
c9d031c3
EV
1266 else {
1267 struct rlimit buf = {};
6550c24c 1268 const char *s, *p;
c9d031c3 1269 int z;
147f6858 1270
6550c24c 1271 /* Chop off "Soft" suffix */
147f6858 1272 s = is_soft ? strndupa(property, is_soft - property) : property;
c9d031c3 1273
6550c24c
LP
1274 /* Skip over any prefix, such as "Default" */
1275 assert_se(p = strstr(s, "Limit"));
1276
1277 z = rlimit_from_string(p + 5);
c9d031c3
EV
1278 assert(z >= 0);
1279
6550c24c 1280 (void) getrlimit(z, &buf);
147f6858 1281 x = is_soft ? buf.rlim_cur : buf.rlim_max;
c9d031c3
EV
1282 }
1283
6550c24c
LP
1284 /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
1285 * archs */
c9d031c3
EV
1286 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1287
1288 return sd_bus_message_append(reply, "t", u);
1289}
984794ba
LP
1290
1291int bus_track_add_name_many(sd_bus_track *t, char **l) {
1292 int r = 0;
1293 char **i;
1294
1295 assert(t);
1296
1297 /* Continues adding after failure, and returns the first failure. */
1298
1299 STRV_FOREACH(i, l) {
1300 int k;
1301
1302 k = sd_bus_track_add_name(t, *i);
1303 if (k < 0 && r >= 0)
1304 r = k;
1305 }
1306
1307 return r;
1308}
d7afd945 1309
0ddf50ff 1310int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
b1a4981a 1311 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
d7afd945
LP
1312 const char *e;
1313 int r;
1314
1315 assert(ret);
1316
61252bae
ZJS
1317 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
1318 * turned on. */
d7afd945
LP
1319
1320 r = sd_bus_new(&bus);
1321 if (r < 0)
1322 return r;
1323
0ddf50ff
YW
1324 if (description) {
1325 r = sd_bus_set_description(bus, description);
1326 if (r < 0)
1327 return r;
1328 }
1329
d7afd945
LP
1330 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1331 if (!e)
1332 e = DEFAULT_SYSTEM_BUS_ADDRESS;
1333
1334 r = sd_bus_set_address(bus, e);
1335 if (r < 0)
1336 return r;
1337
1338 r = sd_bus_set_bus_client(bus, true);
1339 if (r < 0)
1340 return r;
1341
d7afd945
LP
1342 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1343 if (r < 0)
1344 return r;
1345
1346 r = sd_bus_set_watch_bind(bus, true);
1347 if (r < 0)
1348 return r;
1349
1350 r = sd_bus_set_connected_signal(bus, true);
1351 if (r < 0)
1352 return r;
1353
1354 r = sd_bus_start(bus);
1355 if (r < 0)
1356 return r;
1357
1cc6c93a 1358 *ret = TAKE_PTR(bus);
d7afd945
LP
1359
1360 return 0;
1361}
906cb2eb 1362
19017acb
LP
1363int bus_reply_pair_array(sd_bus_message *m, char **l) {
1364 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1365 char **k, **v;
1366 int r;
1367
1368 assert(m);
1369
61252bae
ZJS
1370 /* Reply to the specified message with a message containing a dictionary put together from the
1371 * specified strv */
19017acb
LP
1372
1373 r = sd_bus_message_new_method_return(m, &reply);
1374 if (r < 0)
1375 return r;
1376
1377 r = sd_bus_message_open_container(reply, 'a', "{ss}");
1378 if (r < 0)
1379 return r;
1380
1381 STRV_FOREACH_PAIR(k, v, l) {
1382 r = sd_bus_message_append(reply, "{ss}", *k, *v);
1383 if (r < 0)
1384 return r;
1385 }
1386
1387 r = sd_bus_message_close_container(reply);
1388 if (r < 0)
1389 return r;
1390
1391 return sd_bus_send(NULL, reply, NULL);
1392}
2a66c2a1
LP
1393
1394static void bus_message_unref_wrapper(void *m) {
1395 sd_bus_message_unref(m);
1396}
1397
1398const struct hash_ops bus_message_hash_ops = {
1399 .hash = trivial_hash_func,
1400 .compare = trivial_compare_func,
1401 .free_value = bus_message_unref_wrapper,
1402};
219ab1fb
VC
1403
1404/* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface
1405 * strings encapsulated within a single struct.
1406 */
1407int bus_call_method_async(
1408 sd_bus *bus,
1409 sd_bus_slot **slot,
a028ef14 1410 const BusLocator *locator,
219ab1fb
VC
1411 const char *member,
1412 sd_bus_message_handler_t callback,
1413 void *userdata,
1414 const char *types, ...) {
1415
1416 va_list ap;
1417 int r;
1418
a028ef14 1419 assert(locator);
219ab1fb
VC
1420
1421 va_start(ap, types);
a028ef14 1422 r = sd_bus_call_method_asyncv(bus, slot, locator->destination, locator->path, locator->interface, member, callback, userdata, types, ap);
219ab1fb
VC
1423 va_end(ap);
1424
1425 return r;
1426}
1427
1428int bus_call_method(
1429 sd_bus *bus,
a028ef14 1430 const BusLocator *locator,
219ab1fb
VC
1431 const char *member,
1432 sd_bus_error *error,
1433 sd_bus_message **reply,
1434 const char *types, ...) {
1435
1436 va_list ap;
1437 int r;
1438
a028ef14 1439 assert(locator);
219ab1fb
VC
1440
1441 va_start(ap, types);
a028ef14 1442 r = sd_bus_call_methodv(bus, locator->destination, locator->path, locator->interface, member, error, reply, types, ap);
219ab1fb
VC
1443 va_end(ap);
1444
1445 return r;
1446}
1447
1448int bus_get_property(
1449 sd_bus *bus,
a028ef14 1450 const BusLocator *locator,
219ab1fb
VC
1451 const char *member,
1452 sd_bus_error *error,
1453 sd_bus_message **reply,
1454 const char *type) {
1455
a028ef14 1456 assert(locator);
219ab1fb 1457
a028ef14 1458 return sd_bus_get_property(bus, locator->destination, locator->path, locator->interface, member, error, reply, type);
219ab1fb
VC
1459}
1460
1461int bus_get_property_trivial(
1462 sd_bus *bus,
a028ef14 1463 const BusLocator *locator,
219ab1fb
VC
1464 const char *member,
1465 sd_bus_error *error,
1466 char type, void *ptr) {
1467
a028ef14 1468 assert(locator);
219ab1fb 1469
a028ef14 1470 return sd_bus_get_property_trivial(bus, locator->destination, locator->path, locator->interface, member, error, type, ptr);
219ab1fb
VC
1471}
1472
1473int bus_get_property_string(
1474 sd_bus *bus,
a028ef14 1475 const BusLocator *locator,
219ab1fb
VC
1476 const char *member,
1477 sd_bus_error *error,
1478 char **ret) {
1479
a028ef14 1480 assert(locator);
219ab1fb 1481
a028ef14 1482 return sd_bus_get_property_string(bus, locator->destination, locator->path, locator->interface, member, error, ret);
219ab1fb
VC
1483}
1484
1485int bus_get_property_strv(
1486 sd_bus *bus,
a028ef14 1487 const BusLocator *locator,
219ab1fb
VC
1488 const char *member,
1489 sd_bus_error *error,
1490 char ***ret) {
1491
a028ef14 1492 assert(locator);
219ab1fb 1493
a028ef14 1494 return sd_bus_get_property_strv(bus, locator->destination, locator->path, locator->interface, member, error, ret);
219ab1fb
VC
1495}
1496
1497int bus_set_property(
1498 sd_bus *bus,
a028ef14 1499 const BusLocator *locator,
219ab1fb
VC
1500 const char *member,
1501 sd_bus_error *error,
1502 const char *type, ...) {
1503
1504 va_list ap;
1505 int r;
1506
a028ef14 1507 assert(locator);
219ab1fb
VC
1508
1509 va_start(ap, type);
a028ef14 1510 r = sd_bus_set_propertyv(bus, locator->destination, locator->path, locator->interface, member, error, type, ap);
219ab1fb
VC
1511 va_end(ap);
1512
1513 return r;
1514}
1515
1516int bus_match_signal(
1517 sd_bus *bus,
1518 sd_bus_slot **ret,
a028ef14 1519 const BusLocator *locator,
219ab1fb
VC
1520 const char *member,
1521 sd_bus_message_handler_t callback,
1522 void *userdata) {
1523
a028ef14 1524 assert(locator);
219ab1fb 1525
a028ef14 1526 return sd_bus_match_signal(bus, ret, locator->destination, locator->path, locator->interface, member, callback, userdata);
219ab1fb
VC
1527}
1528
1529int bus_match_signal_async(
1530 sd_bus *bus,
1531 sd_bus_slot **ret,
a028ef14 1532 const BusLocator *locator,
219ab1fb
VC
1533 const char *member,
1534 sd_bus_message_handler_t callback,
1535 sd_bus_message_handler_t install_callback,
1536 void *userdata) {
1537
a028ef14 1538 assert(locator);
219ab1fb 1539
a028ef14 1540 return sd_bus_match_signal_async(bus, ret, locator->destination, locator->path, locator->interface, member, callback, install_callback, userdata);
219ab1fb 1541}
df91e319
VC
1542
1543int bus_message_new_method_call(
1544 sd_bus *bus,
1545 sd_bus_message **m,
1546 const BusLocator *locator,
1547 const char *member) {
1548
1549 assert(locator);
1550
1551 return sd_bus_message_new_method_call(bus, m, locator->destination, locator->path, locator->interface, member);
1552}
6a7e98aa
ZJS
1553
1554int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) {
1555 int r;
1556
1557 log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface);
1558
1559 for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
1560 r = sd_bus_add_object_vtable(bus, NULL,
1561 impl->path,
1562 impl->interface,
1563 *p,
1564 userdata);
1565 if (r < 0)
1566 return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
1567 impl->path,
1568 impl->interface);
1569 }
1570
1571 for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
1572 r = sd_bus_add_fallback_vtable(bus, NULL,
1573 impl->path,
1574 impl->interface,
1575 p->vtable,
1576 p->object_find,
1577 userdata);
1578 if (r < 0)
1579 return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
1580 impl->path,
1581 impl->interface);
1582 }
1583
1584 if (impl->node_enumerator) {
1585 r = sd_bus_add_node_enumerator(bus, NULL,
1586 impl->path,
1587 impl->node_enumerator,
1588 userdata);
1589 if (r < 0)
1590 return log_error_errno(r, "Failed to add node enumerator for %s: %m",
1591 impl->path);
1592 }
1593
2fcbf417
LP
1594 if (impl->manager) {
1595 r = sd_bus_add_object_manager(bus, NULL, impl->path);
1596 if (r < 0)
1597 return log_error_errno(r, "Failed to add object manager for %s: %m", impl->path);
1598 }
1599
6a7e98aa
ZJS
1600 for (size_t i = 0; impl->children && impl->children[i]; i++) {
1601 r = bus_add_implementation(bus, impl->children[i], userdata);
1602 if (r < 0)
1603 return r;
1604 }
1605
1606 return 0;
1607}
1e9bc92d
ZJS
1608
1609static const BusObjectImplementation* find_implementation(
1610 const char *pattern,
1611 const BusObjectImplementation* const* bus_objects) {
1612
1613 for (size_t i = 0; bus_objects && bus_objects[i]; i++) {
1614 const BusObjectImplementation *impl = bus_objects[i];
1615
1616 if (STR_IN_SET(pattern, impl->path, impl->interface))
1617 return impl;
1618
1619 impl = find_implementation(pattern, impl->children);
1620 if (impl)
1621 return impl;
1622 }
1623
1624 return NULL;
1625}
1626
1627static int bus_introspect_implementation(
1628 struct introspect *intro,
1629 const BusObjectImplementation *impl) {
1630 int r;
1631
1632 for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
1633 r = introspect_write_interface(intro, impl->interface, *p);
1634 if (r < 0)
1635 return log_error_errno(r, "Failed to write introspection data: %m");
1636 }
1637
1638 for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
1639 r = introspect_write_interface(intro, impl->interface, p->vtable);
1640 if (r < 0)
1641 return log_error_errno(r, "Failed to write introspection data: %m");
1642 }
1643
1644 return 0;
1645}
1646
8b493397
ZJS
1647static void list_paths(
1648 FILE *out,
1649 const BusObjectImplementation* const* bus_objects) {
1650
1651 for (size_t i = 0; bus_objects[i]; i++) {
1652 fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface);
1653 if (bus_objects[i]->children)
1654 list_paths(out, bus_objects[i]->children);
1655 }
1656}
1657
1e9bc92d
ZJS
1658int bus_introspect_implementations(
1659 FILE *out,
1660 const char *pattern,
1661 const BusObjectImplementation* const* bus_objects) {
1662
1663 const BusObjectImplementation *impl, *main_impl = NULL;
1664 _cleanup_free_ char *s = NULL;
1665 int r;
1666
8b493397
ZJS
1667 if (streq(pattern, "list")) {
1668 list_paths(out, bus_objects);
1669 return 0;
1670 }
1671
1e9bc92d
ZJS
1672 struct introspect intro = {};
1673 bool is_interface = interface_name_is_valid(pattern);
1674
1675 impl = find_implementation(pattern, bus_objects);
1676 if (!impl)
1677 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1678 "%s %s not found",
1679 is_interface ? "Interface" : "Object path",
1680 pattern);
1681
1682 /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */
1683 r = introspect_begin(&intro, false);
1684 if (r < 0)
1685 return log_error_errno(r, "Failed to write introspection data: %m");
1686
1687 r = introspect_write_default_interfaces(&intro, impl->manager);
1688 if (r < 0)
1689 return log_error_errno(r, "Failed to write introspection data: %m");
1690
1691 /* Check if there is a non-fallback path that applies to the given interface, also
1692 * print it. This is useful in the case of units: o.fd.systemd1.Service is declared
1693 * as a fallback vtable for o/fd/systemd1/unit, and we also want to print
1694 * o.fd.systemd1.Unit, which is the non-fallback implementation. */
1695 if (impl->fallback_vtables && is_interface)
1696 main_impl = find_implementation(impl->path, bus_objects);
1697
1698 if (main_impl)
1699 bus_introspect_implementation(&intro, main_impl);
1700
1701 if (impl != main_impl)
1702 bus_introspect_implementation(&intro, impl);
1703
be327321 1704 _cleanup_set_free_ Set *nodes = NULL;
1e9bc92d
ZJS
1705
1706 for (size_t i = 0; impl->children && impl->children[i]; i++) {
be327321 1707 r = set_put_strdup(&nodes, impl->children[i]->path);
1e9bc92d
ZJS
1708 if (r < 0)
1709 return log_oom();
1710 }
1711
1712 r = introspect_write_child_nodes(&intro, nodes, impl->path);
1713 if (r < 0)
1714 return r;
1715
1716 r = introspect_finish(&intro, &s);
1717 if (r < 0)
1718 return log_error_errno(r, "Failed to write introspection data: %m");
1719
1720 fputs(s, out);
1721 return 0;
1722}