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