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