]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-util.c
Merge pull request #1530 from teg/network-fixes-2
[thirdparty/systemd.git] / src / shared / bus-util.c
CommitLineData
40ca29a1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
0c842e0a
TG
22#include <sys/socket.h>
23
ebd011d9
LP
24#include "sd-daemon.h"
25#include "sd-event.h"
d53d9474
LP
26#include "sd-bus.h"
27
28#include "bus-error.h"
29#include "bus-internal.h"
30#include "bus-label.h"
31#include "bus-message.h"
32#include "cgroup-util.h"
40ca29a1 33#include "def.h"
d53d9474 34#include "macro.h"
2bba9a57 35#include "missing.h"
d53d9474 36#include "path-util.h"
ebd011d9 37#include "set.h"
24882e06 38#include "signal-util.h"
d53d9474 39#include "strv.h"
d5cad221 40#include "unit-name.h"
d53d9474 41#include "util.h"
40ca29a1
LP
42
43#include "bus-util.h"
44
19070062 45static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40ca29a1
LP
46 sd_event *e = userdata;
47
40ca29a1
LP
48 assert(m);
49 assert(e);
50
19070062 51 sd_bus_close(sd_bus_message_get_bus(m));
6203e07a 52 sd_event_exit(e, 0);
b27adf35 53
40ca29a1
LP
54 return 1;
55}
56
6203e07a 57int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
40ca29a1 58 _cleanup_free_ char *match = NULL;
11846aa7 59 const char *unique;
40ca29a1
LP
60 int r;
61
62 assert(e);
63 assert(bus);
64 assert(name);
65
6203e07a
LP
66 /* We unregister the name here and then wait for the
67 * NameOwnerChanged signal for this event to arrive before we
68 * quit. We do this in order to make sure that any queued
69 * requests are still processed before we really exit. */
70
11846aa7 71 r = sd_bus_get_unique_name(bus, &unique);
40ca29a1
LP
72 if (r < 0)
73 return r;
74
11846aa7
LP
75 r = asprintf(&match,
76 "sender='org.freedesktop.DBus',"
77 "type='signal',"
78 "interface='org.freedesktop.DBus',"
79 "member='NameOwnerChanged',"
80 "path='/org/freedesktop/DBus',"
81 "arg0='%s',"
82 "arg1='%s',"
83 "arg2=''", name, unique);
84 if (r < 0)
85 return -ENOMEM;
86
19befb2d 87 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
40ca29a1
LP
88 if (r < 0)
89 return r;
90
91 r = sd_bus_release_name(bus, name);
92 if (r < 0)
93 return r;
94
40ca29a1
LP
95 return 0;
96}
97
37224a5f
LP
98int bus_event_loop_with_idle(
99 sd_event *e,
100 sd_bus *bus,
101 const char *name,
102 usec_t timeout,
103 check_idle_t check_idle,
104 void *userdata) {
40ca29a1 105 bool exiting = false;
6203e07a 106 int r, code;
40ca29a1
LP
107
108 assert(e);
109 assert(bus);
110 assert(name);
111
112 for (;;) {
37224a5f
LP
113 bool idle;
114
40ca29a1
LP
115 r = sd_event_get_state(e);
116 if (r < 0)
117 return r;
40ca29a1
LP
118 if (r == SD_EVENT_FINISHED)
119 break;
120
37224a5f
LP
121 if (check_idle)
122 idle = check_idle(userdata);
123 else
124 idle = true;
125
126 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
40ca29a1
LP
127 if (r < 0)
128 return r;
129
a8ba6cd1 130 if (r == 0 && !exiting && idle) {
b27adf35
LP
131
132 r = sd_bus_try_close(bus);
133 if (r == -EBUSY)
134 continue;
135
430e21c2
LP
136 /* Fallback for dbus1 connections: we
137 * unregister the name and wait for the
138 * response to come through for it */
15411c0c 139 if (r == -EOPNOTSUPP) {
430e21c2
LP
140
141 /* Inform the service manager that we
142 * are going down, so that it will
143 * queue all further start requests,
144 * instead of assuming we are already
145 * running. */
146 sd_notify(false, "STOPPING=1");
b27adf35
LP
147
148 r = bus_async_unregister_and_exit(e, bus, name);
149 if (r < 0)
150 return r;
151
152 exiting = true;
153 continue;
154 }
155
40ca29a1
LP
156 if (r < 0)
157 return r;
158
b27adf35
LP
159 sd_event_exit(e, 0);
160 break;
40ca29a1
LP
161 }
162 }
163
6203e07a
LP
164 r = sd_event_get_exit_code(e, &code);
165 if (r < 0)
166 return r;
167
168 return code;
40ca29a1
LP
169}
170
5fd38859
DH
171int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
172 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
173 int r, has_owner = 0;
174
175 assert(c);
176 assert(name);
177
178 r = sd_bus_call_method(c,
179 "org.freedesktop.DBus",
180 "/org/freedesktop/dbus",
181 "org.freedesktop.DBus",
182 "NameHasOwner",
183 error,
184 &rep,
185 "s",
186 name);
187 if (r < 0)
188 return r;
189
190 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
191 if (r < 0)
192 return sd_bus_error_set_errno(error, r);
193
194 return has_owner;
195}
196
c529695e
LP
197static int check_good_user(sd_bus_message *m, uid_t good_user) {
198 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
199 uid_t sender_uid;
200 int r;
201
202 assert(m);
203
204 if (good_user == UID_INVALID)
205 return 0;
206
207 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
208 if (r < 0)
209 return r;
210
0f514420
LP
211 /* Don't trust augmented credentials for authorization */
212 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
213
c529695e
LP
214 r = sd_bus_creds_get_euid(creds, &sender_uid);
215 if (r < 0)
216 return r;
217
218 return sender_uid == good_user;
219}
220
ceb24229 221int bus_test_polkit(
f3885791 222 sd_bus_message *call,
def9a7aa 223 int capability,
40ca29a1 224 const char *action,
403ed0e5 225 const char **details,
c529695e 226 uid_t good_user,
40ca29a1
LP
227 bool *_challenge,
228 sd_bus_error *e) {
229
40ca29a1
LP
230 int r;
231
f3885791 232 assert(call);
40ca29a1
LP
233 assert(action);
234
ceb24229
LP
235 /* Tests non-interactively! */
236
c529695e
LP
237 r = check_good_user(call, good_user);
238 if (r != 0)
239 return r;
240
f3885791 241 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
242 if (r < 0)
243 return r;
f3885791 244 else if (r > 0)
40ca29a1 245 return 1;
40ca29a1
LP
246#ifdef ENABLE_POLKIT
247 else {
403ed0e5 248 _cleanup_bus_message_unref_ sd_bus_message *request = NULL;
40ca29a1 249 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ceb24229 250 int authorized = false, challenge = false;
403ed0e5 251 const char *sender, **k, **v;
5b12334d 252
f3885791 253 sender = sd_bus_message_get_sender(call);
5b12334d
LP
254 if (!sender)
255 return -EBADMSG;
40ca29a1 256
403ed0e5 257 r = sd_bus_message_new_method_call(
f3885791 258 call->bus,
403ed0e5 259 &request,
40ca29a1
LP
260 "org.freedesktop.PolicyKit1",
261 "/org/freedesktop/PolicyKit1/Authority",
262 "org.freedesktop.PolicyKit1.Authority",
403ed0e5
MC
263 "CheckAuthorization");
264 if (r < 0)
265 return r;
266
267 r = sd_bus_message_append(
268 request,
269 "(sa{sv})s",
40ca29a1 270 "system-bus-name", 1, "name", "s", sender,
403ed0e5
MC
271 action);
272 if (r < 0)
273 return r;
274
275 r = sd_bus_message_open_container(request, 'a', "{ss}");
276 if (r < 0)
277 return r;
40ca29a1 278
403ed0e5
MC
279 STRV_FOREACH_PAIR(k, v, details) {
280 r = sd_bus_message_append(request, "{ss}", *k, *v);
281 if (r < 0)
282 return r;
283 }
284
285 r = sd_bus_message_close_container(request);
286 if (r < 0)
287 return r;
288
289 r = sd_bus_message_append(request, "us", 0, NULL);
290 if (r < 0)
291 return r;
292
293 r = sd_bus_call(call->bus, request, 0, e, &reply);
40ca29a1
LP
294 if (r < 0) {
295 /* Treat no PK available as access denied */
296 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
297 sd_bus_error_free(e);
298 return -EACCES;
299 }
300
301 return r;
302 }
303
313333b4 304 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
2b49a470
TA
305 if (r < 0)
306 return r;
307
308 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
309 if (r < 0)
310 return r;
40ca29a1
LP
311
312 if (authorized)
313 return 1;
314
315 if (_challenge) {
316 *_challenge = challenge;
317 return 0;
318 }
319 }
320#endif
321
322 return -EACCES;
323}
324
325#ifdef ENABLE_POLKIT
326
327typedef struct AsyncPolkitQuery {
328 sd_bus_message *request, *reply;
329 sd_bus_message_handler_t callback;
330 void *userdata;
19befb2d 331 sd_bus_slot *slot;
ebcf1f97 332 Hashmap *registry;
40ca29a1
LP
333} AsyncPolkitQuery;
334
19befb2d 335static void async_polkit_query_free(AsyncPolkitQuery *q) {
ebcf1f97
LP
336
337 if (!q)
338 return;
339
19befb2d 340 sd_bus_slot_unref(q->slot);
ebcf1f97
LP
341
342 if (q->registry && q->request)
343 hashmap_remove(q->registry, q->request);
344
345 sd_bus_message_unref(q->request);
346 sd_bus_message_unref(q->reply);
347
348 free(q);
349}
350
19070062 351static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
ebcf1f97 352 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
ebcf1f97 353 AsyncPolkitQuery *q = userdata;
40ca29a1
LP
354 int r;
355
40ca29a1
LP
356 assert(reply);
357 assert(q);
358
19befb2d 359 q->slot = sd_bus_slot_unref(q->slot);
40ca29a1 360 q->reply = sd_bus_message_ref(reply);
40ca29a1 361
ebcf1f97
LP
362 r = sd_bus_message_rewind(q->request, true);
363 if (r < 0) {
364 r = sd_bus_reply_method_errno(q->request, r, NULL);
365 goto finish;
366 }
40ca29a1 367
19070062 368 r = q->callback(q->request, q->userdata, &error_buffer);
ebcf1f97 369 r = bus_maybe_reply_error(q->request, r, &error_buffer);
40ca29a1 370
ebcf1f97 371finish:
19befb2d
LP
372 async_polkit_query_free(q);
373
ebcf1f97 374 return r;
40ca29a1
LP
375}
376
377#endif
378
379int bus_verify_polkit_async(
f3885791 380 sd_bus_message *call,
def9a7aa 381 int capability,
40ca29a1 382 const char *action,
403ed0e5 383 const char **details,
40ca29a1 384 bool interactive,
c529695e 385 uid_t good_user,
f3885791
LP
386 Hashmap **registry,
387 sd_bus_error *error) {
40ca29a1
LP
388
389#ifdef ENABLE_POLKIT
390 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
391 AsyncPolkitQuery *q;
403ed0e5 392 const char *sender, **k, **v;
f3885791
LP
393 sd_bus_message_handler_t callback;
394 void *userdata;
b911eb15 395 int c;
5b12334d 396#endif
40ca29a1
LP
397 int r;
398
f3885791 399 assert(call);
40ca29a1 400 assert(action);
f3885791 401 assert(registry);
40ca29a1 402
c529695e
LP
403 r = check_good_user(call, good_user);
404 if (r != 0)
405 return r;
406
40ca29a1 407#ifdef ENABLE_POLKIT
f3885791 408 q = hashmap_get(*registry, call);
40ca29a1 409 if (q) {
102d8f81 410 int authorized, challenge;
40ca29a1
LP
411
412 /* This is the second invocation of this function, and
413 * there's already a response from polkit, let's
414 * process it */
415 assert(q->reply);
416
417 if (sd_bus_message_is_method_error(q->reply, NULL)) {
418 const sd_bus_error *e;
419
ebcf1f97 420 /* Copy error from polkit reply */
40ca29a1
LP
421 e = sd_bus_message_get_error(q->reply);
422 sd_bus_error_copy(error, e);
40ca29a1 423
ebcf1f97
LP
424 /* Treat no PK available as access denied */
425 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
426 return -EACCES;
427
5958d089 428 return -sd_bus_error_get_errno(e);
40ca29a1
LP
429 }
430
431 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
432 if (r >= 0)
433 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
434
40ca29a1
LP
435 if (r < 0)
436 return r;
437
438 if (authorized)
439 return 1;
440
f2288cc6
LP
441 if (challenge)
442 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
443
40ca29a1
LP
444 return -EACCES;
445 }
446#endif
447
f3885791 448 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
449 if (r < 0)
450 return r;
f3885791 451 else if (r > 0)
40ca29a1 452 return 1;
5b12334d 453
40ca29a1 454#ifdef ENABLE_POLKIT
f3885791
LP
455 if (sd_bus_get_current_message(call->bus) != call)
456 return -EINVAL;
457
458 callback = sd_bus_get_current_handler(call->bus);
459 if (!callback)
460 return -EINVAL;
461
462 userdata = sd_bus_get_current_userdata(call->bus);
463
464 sender = sd_bus_message_get_sender(call);
5b12334d
LP
465 if (!sender)
466 return -EBADMSG;
40ca29a1 467
b911eb15
LP
468 c = sd_bus_message_get_allow_interactive_authorization(call);
469 if (c < 0)
470 return c;
471 if (c > 0)
472 interactive = true;
473
d5099efc 474 r = hashmap_ensure_allocated(registry, NULL);
40ca29a1
LP
475 if (r < 0)
476 return r;
477
478 r = sd_bus_message_new_method_call(
f3885791 479 call->bus,
151b9b96 480 &pk,
40ca29a1
LP
481 "org.freedesktop.PolicyKit1",
482 "/org/freedesktop/PolicyKit1/Authority",
483 "org.freedesktop.PolicyKit1.Authority",
151b9b96 484 "CheckAuthorization");
40ca29a1
LP
485 if (r < 0)
486 return r;
487
488 r = sd_bus_message_append(
489 pk,
403ed0e5 490 "(sa{sv})s",
40ca29a1 491 "system-bus-name", 1, "name", "s", sender,
403ed0e5
MC
492 action);
493 if (r < 0)
494 return r;
495
496 r = sd_bus_message_open_container(pk, 'a', "{ss}");
497 if (r < 0)
498 return r;
499
500 STRV_FOREACH_PAIR(k, v, details) {
501 r = sd_bus_message_append(pk, "{ss}", *k, *v);
502 if (r < 0)
503 return r;
504 }
505
506 r = sd_bus_message_close_container(pk);
507 if (r < 0)
508 return r;
509
510 r = sd_bus_message_append(pk, "us", !!interactive, NULL);
40ca29a1
LP
511 if (r < 0)
512 return r;
513
514 q = new0(AsyncPolkitQuery, 1);
515 if (!q)
516 return -ENOMEM;
517
f3885791 518 q->request = sd_bus_message_ref(call);
40ca29a1
LP
519 q->callback = callback;
520 q->userdata = userdata;
521
f3885791 522 r = hashmap_put(*registry, call, q);
40ca29a1 523 if (r < 0) {
19befb2d 524 async_polkit_query_free(q);
40ca29a1
LP
525 return r;
526 }
527
ebcf1f97
LP
528 q->registry = *registry;
529
f3885791 530 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
ebcf1f97 531 if (r < 0) {
19befb2d 532 async_polkit_query_free(q);
40ca29a1 533 return r;
ebcf1f97 534 }
40ca29a1
LP
535
536 return 0;
537#endif
538
539 return -EACCES;
540}
541
36e34057 542void bus_verify_polkit_async_registry_free(Hashmap *registry) {
40ca29a1
LP
543#ifdef ENABLE_POLKIT
544 AsyncPolkitQuery *q;
545
546 while ((q = hashmap_steal_first(registry)))
19befb2d 547 async_polkit_query_free(q);
40ca29a1
LP
548
549 hashmap_free(registry);
550#endif
551}
0c842e0a 552
718db961 553int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
554 struct ucred ucred;
555 socklen_t l;
0f8bd8de 556 int fd;
0c842e0a
TG
557
558 assert(c);
559
560 fd = sd_bus_get_fd(c);
0f8bd8de
LP
561 if (fd < 0)
562 return fd;
0c842e0a
TG
563
564 l = sizeof(struct ucred);
0f8bd8de 565 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 566 return -errno;
0c842e0a 567
0f8bd8de 568 if (l != sizeof(struct ucred))
0c842e0a 569 return -E2BIG;
0c842e0a
TG
570
571 if (ucred.uid != 0 && ucred.uid != geteuid())
572 return -EPERM;
573
574 return 1;
575}
576
266f3e26 577int bus_connect_system_systemd(sd_bus **_bus) {
0f8bd8de 578 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 579 int r;
0c842e0a
TG
580
581 assert(_bus);
582
0f8bd8de 583 if (geteuid() != 0)
266f3e26 584 return sd_bus_default_system(_bus);
a1da8583 585
a6aa8912
LP
586 /* If we are root and kdbus is not available, then let's talk
587 * directly to the system instance, instead of going via the
588 * bus */
a1da8583 589
0f8bd8de
LP
590 r = sd_bus_new(&bus);
591 if (r < 0)
592 return r;
a1da8583 593
e3afaf6b 594 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
0f8bd8de
LP
595 if (r < 0)
596 return r;
a1da8583 597
a6aa8912
LP
598 bus->bus_client = true;
599
0f8bd8de 600 r = sd_bus_start(bus);
a6aa8912
LP
601 if (r >= 0) {
602 *_bus = bus;
603 bus = NULL;
604 return 0;
605 }
606
607 bus = sd_bus_unref(bus);
a6aa8912
LP
608
609 r = sd_bus_new(&bus);
0f8bd8de
LP
610 if (r < 0)
611 return r;
a1da8583 612
a6aa8912
LP
613 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
614 if (r < 0)
615 return r;
616
617 r = sd_bus_start(bus);
618 if (r < 0)
266f3e26 619 return sd_bus_default_system(_bus);
a6aa8912 620
0f8bd8de 621 r = bus_check_peercred(bus);
a1da8583
TG
622 if (r < 0)
623 return r;
624
625 *_bus = bus;
0f8bd8de
LP
626 bus = NULL;
627
a1da8583
TG
628 return 0;
629}
630
266f3e26 631int bus_connect_user_systemd(sd_bus **_bus) {
41dd15e4 632 _cleanup_bus_unref_ sd_bus *bus = NULL;
a6aa8912 633 _cleanup_free_ char *ee = NULL;
41dd15e4
LP
634 const char *e;
635 int r;
636
a6aa8912 637 /* Try via kdbus first, and then directly */
41dd15e4
LP
638
639 assert(_bus);
640
a6aa8912
LP
641 r = sd_bus_new(&bus);
642 if (r < 0)
643 return r;
644
e3afaf6b 645 if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
a6aa8912
LP
646 return -ENOMEM;
647
648 bus->bus_client = true;
649
650 r = sd_bus_start(bus);
651 if (r >= 0) {
652 *_bus = bus;
653 bus = NULL;
654 return 0;
655 }
656
657 bus = sd_bus_unref(bus);
a6aa8912 658
41dd15e4 659 e = secure_getenv("XDG_RUNTIME_DIR");
537220d9 660 if (!e)
266f3e26 661 return sd_bus_default_user(_bus);
537220d9 662
a6aa8912
LP
663 ee = bus_address_escape(e);
664 if (!ee)
537220d9 665 return -ENOMEM;
41dd15e4
LP
666
667 r = sd_bus_new(&bus);
668 if (r < 0)
669 return r;
670
a6aa8912
LP
671 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
672 if (!bus->address)
673 return -ENOMEM;
41dd15e4
LP
674
675 r = sd_bus_start(bus);
676 if (r < 0)
266f3e26 677 return sd_bus_default_user(_bus);
41dd15e4
LP
678
679 r = bus_check_peercred(bus);
680 if (r < 0)
681 return r;
682
683 *_bus = bus;
684 bus = NULL;
685
686 return 0;
687}
688
9f6eb1cd 689int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
690 char type;
691 const char *contents;
9f6eb1cd 692 int r;
a1da8583
TG
693
694 assert(name);
695 assert(property);
696
9f6eb1cd
KS
697 r = sd_bus_message_peek_type(property, &type, &contents);
698 if (r < 0)
699 return r;
a1da8583
TG
700
701 switch (type) {
702
703 case SD_BUS_TYPE_STRING: {
704 const char *s;
9f6eb1cd
KS
705
706 r = sd_bus_message_read_basic(property, type, &s);
707 if (r < 0)
708 return r;
a1da8583 709
27e9c5af
LP
710 if (all || !isempty(s)) {
711 _cleanup_free_ char *escaped = NULL;
712
713 escaped = xescape(s, "\n");
714 if (!escaped)
715 return -ENOMEM;
716
717 printf("%s=%s\n", name, escaped);
718 }
a1da8583
TG
719
720 return 1;
721 }
722
723 case SD_BUS_TYPE_BOOLEAN: {
c2fa048c 724 int b;
a1da8583 725
9f6eb1cd
KS
726 r = sd_bus_message_read_basic(property, type, &b);
727 if (r < 0)
728 return r;
729
a1da8583
TG
730 printf("%s=%s\n", name, yes_no(b));
731
732 return 1;
733 }
734
735 case SD_BUS_TYPE_UINT64: {
736 uint64_t u;
737
9f6eb1cd
KS
738 r = sd_bus_message_read_basic(property, type, &u);
739 if (r < 0)
740 return r;
a1da8583
TG
741
742 /* Yes, heuristics! But we can change this check
743 * should it turn out to not be sufficient */
744
745 if (endswith(name, "Timestamp")) {
746 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
747
748 t = format_timestamp(timestamp, sizeof(timestamp), u);
749 if (t || all)
750 printf("%s=%s\n", name, strempty(t));
751
752 } else if (strstr(name, "USec")) {
753 char timespan[FORMAT_TIMESPAN_MAX];
754
755 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
756 } else
757 printf("%s=%llu\n", name, (unsigned long long) u);
758
759 return 1;
760 }
761
d7161865
DM
762 case SD_BUS_TYPE_INT64: {
763 int64_t i;
764
765 r = sd_bus_message_read_basic(property, type, &i);
766 if (r < 0)
767 return r;
768
769 printf("%s=%lld\n", name, (long long) i);
770
771 return 1;
772 }
773
a1da8583
TG
774 case SD_BUS_TYPE_UINT32: {
775 uint32_t u;
776
9f6eb1cd
KS
777 r = sd_bus_message_read_basic(property, type, &u);
778 if (r < 0)
779 return r;
a1da8583
TG
780
781 if (strstr(name, "UMask") || strstr(name, "Mode"))
782 printf("%s=%04o\n", name, u);
783 else
784 printf("%s=%u\n", name, (unsigned) u);
785
786 return 1;
787 }
788
789 case SD_BUS_TYPE_INT32: {
790 int32_t i;
791
9f6eb1cd
KS
792 r = sd_bus_message_read_basic(property, type, &i);
793 if (r < 0)
794 return r;
a1da8583
TG
795
796 printf("%s=%i\n", name, (int) i);
797 return 1;
798 }
799
800 case SD_BUS_TYPE_DOUBLE: {
801 double d;
802
9f6eb1cd
KS
803 r = sd_bus_message_read_basic(property, type, &d);
804 if (r < 0)
805 return r;
a1da8583
TG
806
807 printf("%s=%g\n", name, d);
808 return 1;
809 }
810
811 case SD_BUS_TYPE_ARRAY:
a1da8583 812 if (streq(contents, "s")) {
261afec5
MAP
813 bool first = true;
814 const char *str;
a1da8583 815
9f6eb1cd
KS
816 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
817 if (r < 0)
818 return r;
819
261afec5 820 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
27e9c5af
LP
821 _cleanup_free_ char *escaped = NULL;
822
261afec5
MAP
823 if (first)
824 printf("%s=", name);
825
27e9c5af
LP
826 escaped = xescape(str, "\n ");
827 if (!escaped)
828 return -ENOMEM;
829
830 printf("%s%s", first ? "" : " ", escaped);
261afec5
MAP
831
832 first = false;
833 }
9f6eb1cd
KS
834 if (r < 0)
835 return r;
a1da8583 836
261afec5 837 if (first && all)
a1da8583 838 printf("%s=", name);
261afec5 839 if (!first || all)
a1da8583 840 puts("");
a1da8583 841
9f6eb1cd
KS
842 r = sd_bus_message_exit_container(property);
843 if (r < 0)
844 return r;
a1da8583
TG
845
846 return 1;
847
848 } else if (streq(contents, "y")) {
849 const uint8_t *u;
850 size_t n;
851
9f6eb1cd
KS
852 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
853 if (r < 0)
854 return r;
855
a1da8583
TG
856 if (all || n > 0) {
857 unsigned int i;
858
859 printf("%s=", name);
860
861 for (i = 0; i < n; i++)
862 printf("%02x", u[i]);
863
864 puts("");
865 }
866
867 return 1;
868
869 } else if (streq(contents, "u")) {
870 uint32_t *u;
871 size_t n;
872
9f6eb1cd
KS
873 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
874 if (r < 0)
875 return r;
876
a1da8583
TG
877 if (all || n > 0) {
878 unsigned int i;
879
880 printf("%s=", name);
881
882 for (i = 0; i < n; i++)
883 printf("%08x", u[i]);
884
885 puts("");
886 }
887
888 return 1;
889 }
890
891 break;
892 }
893
894 return 0;
895}
d21ed1ea 896
27e72d6b 897int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 898 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
899 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
900 int r;
901
9f6eb1cd
KS
902 assert(bus);
903 assert(path);
904
905 r = sd_bus_call_method(bus,
27e72d6b 906 dest,
ffc06c35
KS
907 path,
908 "org.freedesktop.DBus.Properties",
909 "GetAll",
910 &error,
9f6eb1cd 911 &reply,
ffc06c35 912 "s", "");
9f6eb1cd 913 if (r < 0)
ffc06c35 914 return r;
ffc06c35 915
9f6eb1cd 916 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
917 if (r < 0)
918 return r;
919
9f6eb1cd 920 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 921 const char *name;
ffc06c35 922 const char *contents;
ffc06c35 923
9f6eb1cd 924 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
925 if (r < 0)
926 return r;
927
9f6eb1cd
KS
928 if (!filter || strv_find(filter, name)) {
929 r = sd_bus_message_peek_type(reply, NULL, &contents);
930 if (r < 0)
931 return r;
932
933 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
934 if (r < 0)
935 return r;
ffc06c35 936
9f6eb1cd
KS
937 r = bus_print_property(name, reply, all);
938 if (r < 0)
939 return r;
27e72d6b
SP
940 if (r == 0) {
941 if (all)
942 printf("%s=[unprintable]\n", name);
943 /* skip what we didn't read */
944 r = sd_bus_message_skip(reply, contents);
945 if (r < 0)
946 return r;
947 }
9f6eb1cd
KS
948
949 r = sd_bus_message_exit_container(reply);
950 if (r < 0)
951 return r;
952 } else {
953 r = sd_bus_message_skip(reply, "v");
954 if (r < 0)
955 return r;
956 }
957
958 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
959 if (r < 0)
960 return r;
9f6eb1cd
KS
961 }
962 if (r < 0)
963 return r;
ffc06c35 964
9f6eb1cd
KS
965 r = sd_bus_message_exit_container(reply);
966 if (r < 0)
967 return r;
ffc06c35 968
9f6eb1cd
KS
969 return 0;
970}
ffc06c35 971
9f6eb1cd
KS
972int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
973 sd_id128_t *p = userdata;
974 const void *v;
975 size_t n;
976 int r;
ffc06c35 977
9f6eb1cd
KS
978 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
979 if (r < 0)
980 return r;
ffc06c35 981
9f6eb1cd
KS
982 if (n == 0)
983 *p = SD_ID128_NULL;
984 else if (n == 16)
985 memcpy((*p).bytes, v, n);
986 else
987 return -EINVAL;
ffc06c35 988
9f6eb1cd
KS
989 return 0;
990}
ffc06c35 991
9f6eb1cd
KS
992static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
993 char type;
994 int r;
ffc06c35 995
9f6eb1cd
KS
996 r = sd_bus_message_peek_type(m, &type, NULL);
997 if (r < 0)
998 return r;
ffc06c35 999
9f6eb1cd
KS
1000 switch (type) {
1001 case SD_BUS_TYPE_STRING: {
1002 const char *s;
9f6eb1cd 1003 char **p = userdata;
ffc06c35 1004
9f6eb1cd
KS
1005 r = sd_bus_message_read_basic(m, type, &s);
1006 if (r < 0)
1007 break;
ffc06c35 1008
9f6eb1cd
KS
1009 if (isempty(s))
1010 break;
ffc06c35 1011
0704ea57 1012 r = free_and_strdup(p, s);
9f6eb1cd
KS
1013 break;
1014 }
ffc06c35 1015
9f6eb1cd 1016 case SD_BUS_TYPE_ARRAY: {
7d6884b6
TA
1017 _cleanup_strv_free_ char **l = NULL;
1018 char ***p = userdata;
ffc06c35 1019
9f6eb1cd
KS
1020 r = bus_message_read_strv_extend(m, &l);
1021 if (r < 0)
1022 break;
ffc06c35 1023
9f6eb1cd
KS
1024 strv_free(*p);
1025 *p = l;
1026 l = NULL;
ffc06c35 1027
9f6eb1cd
KS
1028 break;
1029 }
ffc06c35 1030
9f6eb1cd
KS
1031 case SD_BUS_TYPE_BOOLEAN: {
1032 unsigned b;
1033 bool *p = userdata;
ffc06c35 1034
9f6eb1cd
KS
1035 r = sd_bus_message_read_basic(m, type, &b);
1036 if (r < 0)
1037 break;
ffc06c35 1038
9f6eb1cd 1039 *p = b;
ffc06c35 1040
9f6eb1cd
KS
1041 break;
1042 }
ffc06c35 1043
9f6eb1cd
KS
1044 case SD_BUS_TYPE_UINT32: {
1045 uint64_t u;
1046 uint32_t *p = userdata;
1047
1048 r = sd_bus_message_read_basic(m, type, &u);
1049 if (r < 0)
ffc06c35 1050 break;
ffc06c35 1051
9f6eb1cd
KS
1052 *p = u;
1053
1054 break;
1055 }
1056
1057 case SD_BUS_TYPE_UINT64: {
1058 uint64_t t;
1059 uint64_t *p = userdata;
1060
1061 r = sd_bus_message_read_basic(m, type, &t);
1062 if (r < 0)
ffc06c35 1063 break;
ffc06c35 1064
9f6eb1cd
KS
1065 *p = t;
1066
1067 break;
1068 }
1069
1070 default:
1071 break;
1072 }
1073
1074 return r;
1075}
1076
fe506d56
LP
1077int bus_message_map_all_properties(
1078 sd_bus_message *m,
1079 const struct bus_properties_map *map,
1080 void *userdata) {
1081
9f6eb1cd
KS
1082 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1083 int r;
1084
aae2b488 1085 assert(m);
9f6eb1cd
KS
1086 assert(map);
1087
9f6eb1cd
KS
1088 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1089 if (r < 0)
1090 return r;
1091
1092 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1093 const struct bus_properties_map *prop;
1094 const char *member;
1095 const char *contents;
1096 void *v;
1097 unsigned i;
1098
1099 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
1100 if (r < 0)
1101 return r;
1102
9f6eb1cd
KS
1103 for (i = 0, prop = NULL; map[i].member; i++)
1104 if (streq(map[i].member, member)) {
1105 prop = &map[i];
1106 break;
1107 }
1108
1109 if (prop) {
1110 r = sd_bus_message_peek_type(m, NULL, &contents);
1111 if (r < 0)
1112 return r;
1113
1114 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1115 if (r < 0)
1116 return r;
1117
1118 v = (uint8_t *)userdata + prop->offset;
27e72d6b 1119 if (map[i].set)
fe506d56 1120 r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
9f6eb1cd 1121 else
fe506d56 1122 r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
2b49a470
TA
1123 if (r < 0)
1124 return r;
9f6eb1cd
KS
1125
1126 r = sd_bus_message_exit_container(m);
1127 if (r < 0)
1128 return r;
1129 } else {
1130 r = sd_bus_message_skip(m, "v");
1131 if (r < 0)
6c1508b8 1132 return r;
9f6eb1cd
KS
1133 }
1134
ffc06c35
KS
1135 r = sd_bus_message_exit_container(m);
1136 if (r < 0)
1137 return r;
1138 }
fe506d56
LP
1139 if (r < 0)
1140 return r;
ffc06c35 1141
aae2b488
DH
1142 return sd_bus_message_exit_container(m);
1143}
1144
fe506d56
LP
1145int bus_message_map_properties_changed(
1146 sd_bus_message *m,
1147 const struct bus_properties_map *map,
1148 void *userdata) {
1149
aae2b488
DH
1150 const char *member;
1151 int r, invalidated, i;
1152
aae2b488
DH
1153 assert(m);
1154 assert(map);
1155
fe506d56 1156 r = bus_message_map_all_properties(m, map, userdata);
aae2b488
DH
1157 if (r < 0)
1158 return r;
1159
1160 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1161 if (r < 0)
1162 return r;
1163
1164 invalidated = 0;
1165 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1166 for (i = 0; map[i].member; i++)
1167 if (streq(map[i].member, member)) {
1168 ++invalidated;
1169 break;
1170 }
fe506d56
LP
1171 if (r < 0)
1172 return r;
aae2b488
DH
1173
1174 r = sd_bus_message_exit_container(m);
1175 if (r < 0)
1176 return r;
1177
1178 return invalidated;
1179}
1180
fe506d56
LP
1181int bus_map_all_properties(
1182 sd_bus *bus,
1183 const char *destination,
1184 const char *path,
1185 const struct bus_properties_map *map,
1186 void *userdata) {
1187
aae2b488
DH
1188 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1189 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1190 int r;
1191
1192 assert(bus);
1193 assert(destination);
1194 assert(path);
1195 assert(map);
1196
1197 r = sd_bus_call_method(
1198 bus,
1199 destination,
1200 path,
1201 "org.freedesktop.DBus.Properties",
1202 "GetAll",
1203 &error,
1204 &m,
1205 "s", "");
1206 if (r < 0)
1207 return r;
1208
fe506d56 1209 return bus_message_map_all_properties(m, map, userdata);
ffc06c35
KS
1210}
1211
266f3e26 1212int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
d21ed1ea
LP
1213 int r;
1214
1215 assert(transport >= 0);
1216 assert(transport < _BUS_TRANSPORT_MAX);
1217 assert(bus);
1218
1219 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1220 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
d21ed1ea
LP
1221
1222 switch (transport) {
1223
1224 case BUS_TRANSPORT_LOCAL:
1225 if (user)
76b54375 1226 r = sd_bus_default_user(bus);
d21ed1ea 1227 else
76b54375 1228 r = sd_bus_default_system(bus);
d21ed1ea
LP
1229
1230 break;
1231
1232 case BUS_TRANSPORT_REMOTE:
3db729cb 1233 r = sd_bus_open_system_remote(bus, host);
41dd15e4
LP
1234 break;
1235
de33fc62
LP
1236 case BUS_TRANSPORT_MACHINE:
1237 r = sd_bus_open_system_machine(bus, host);
41dd15e4
LP
1238 break;
1239
1240 default:
1241 assert_not_reached("Hmm, unknown transport type.");
1242 }
1243
1244 return r;
1245}
1246
266f3e26 1247int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
41dd15e4
LP
1248 int r;
1249
1250 assert(transport >= 0);
1251 assert(transport < _BUS_TRANSPORT_MAX);
1252 assert(bus);
1253
1254 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1255 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
41dd15e4
LP
1256
1257 switch (transport) {
1258
1259 case BUS_TRANSPORT_LOCAL:
1260 if (user)
266f3e26 1261 r = bus_connect_user_systemd(bus);
41dd15e4 1262 else
266f3e26 1263 r = bus_connect_system_systemd(bus);
41dd15e4
LP
1264
1265 break;
1266
1267 case BUS_TRANSPORT_REMOTE:
3db729cb 1268 r = sd_bus_open_system_remote(bus, host);
d21ed1ea
LP
1269 break;
1270
de33fc62
LP
1271 case BUS_TRANSPORT_MACHINE:
1272 r = sd_bus_open_system_machine(bus, host);
d21ed1ea
LP
1273 break;
1274
1275 default:
1276 assert_not_reached("Hmm, unknown transport type.");
1277 }
1278
1279 return r;
1280}
e6504030
LP
1281
1282int bus_property_get_bool(
1283 sd_bus *bus,
1284 const char *path,
1285 const char *interface,
1286 const char *property,
1287 sd_bus_message *reply,
ebcf1f97
LP
1288 void *userdata,
1289 sd_bus_error *error) {
e6504030
LP
1290
1291 int b = *(bool*) userdata;
1292
1293 return sd_bus_message_append_basic(reply, 'b', &b);
1294}
1295
718db961
LP
1296#if __SIZEOF_SIZE_T__ != 8
1297int bus_property_get_size(
e6504030
LP
1298 sd_bus *bus,
1299 const char *path,
1300 const char *interface,
1301 const char *property,
1302 sd_bus_message *reply,
ebcf1f97
LP
1303 void *userdata,
1304 sd_bus_error *error) {
e6504030 1305
718db961 1306 uint64_t sz = *(size_t*) userdata;
e6504030 1307
718db961 1308 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1309}
718db961
LP
1310#endif
1311
1312#if __SIZEOF_LONG__ != 8
1313int bus_property_get_long(
1314 sd_bus *bus,
1315 const char *path,
1316 const char *interface,
1317 const char *property,
1318 sd_bus_message *reply,
ebcf1f97
LP
1319 void *userdata,
1320 sd_bus_error *error) {
718db961
LP
1321
1322 int64_t l = *(long*) userdata;
1323
1324 return sd_bus_message_append_basic(reply, 'x', &l);
1325}
1326
1327int bus_property_get_ulong(
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) {
718db961
LP
1335
1336 uint64_t ul = *(unsigned long*) userdata;
1337
1338 return sd_bus_message_append_basic(reply, 't', &ul);
1339}
1340#endif
5b30bef8
LP
1341
1342int bus_log_parse_error(int r) {
23bbb0de 1343 return log_error_errno(r, "Failed to parse bus message: %m");
5b30bef8 1344}
f459b602
MAP
1345
1346int bus_log_create_error(int r) {
23bbb0de 1347 return log_error_errno(r, "Failed to create bus message: %m");
f459b602
MAP
1348}
1349
1350int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1351 assert(message);
1352 assert(u);
1353
1238ee09
LP
1354 u->machine = NULL;
1355
f459b602
MAP
1356 return sd_bus_message_read(
1357 message,
1358 "(ssssssouso)",
1359 &u->id,
1360 &u->description,
1361 &u->load_state,
1362 &u->active_state,
1363 &u->sub_state,
1364 &u->following,
1365 &u->unit_path,
1366 &u->job_id,
1367 &u->job_type,
1368 &u->job_path);
1369}
ebcf1f97 1370
df31a6c0
LP
1371int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1372 const char *eq, *field;
1373 int r;
1374
1375 assert(m);
1376 assert(assignment);
1377
1378 eq = strchr(assignment, '=');
1379 if (!eq) {
1380 log_error("Not an assignment: %s", assignment);
1381 return -EINVAL;
1382 }
1383
1384 field = strndupa(assignment, eq - assignment);
1385 eq ++;
1386
b2f8b02e
LP
1387 if (streq(field, "CPUQuota")) {
1388
1389 if (isempty(eq)) {
1390
1391 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1392 if (r < 0)
1393 return bus_log_create_error(r);
1394
3a43da28 1395 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
b2f8b02e
LP
1396
1397 } else if (endswith(eq, "%")) {
1398 double percent;
1399
1400 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1401 log_error("CPU quota '%s' invalid.", eq);
1402 return -EINVAL;
1403 }
1404
1405 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1406 if (r < 0)
1407 return bus_log_create_error(r);
1408
1409 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1410 } else {
9a054909 1411 log_error("CPU quota needs to be in percent.");
b2f8b02e
LP
1412 return -EINVAL;
1413 }
1414
b2f8b02e
LP
1415 if (r < 0)
1416 return bus_log_create_error(r);
1417
1418 return 0;
1419 }
1420
df31a6c0
LP
1421 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1422 if (r < 0)
1423 return bus_log_create_error(r);
1424
e567439e 1425 if (STR_IN_SET(field,
03a7b521 1426 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
8bed4cbc 1427 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
b9c50073 1428 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
047d9933
EV
1429 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1430 "SyslogLevelPrefix")) {
df31a6c0
LP
1431
1432 r = parse_boolean(eq);
1433 if (r < 0) {
1434 log_error("Failed to parse boolean assignment %s.", assignment);
1435 return -EINVAL;
1436 }
1437
1438 r = sd_bus_message_append(m, "v", "b", r);
1439
1440 } else if (streq(field, "MemoryLimit")) {
59f448cf 1441 uint64_t bytes;
df31a6c0 1442
03a7b521
LP
1443 if (isempty(eq) || streq(eq, "infinity"))
1444 bytes = (uint64_t) -1;
1445 else {
1446 r = parse_size(eq, 1024, &bytes);
1447 if (r < 0) {
1448 log_error("Failed to parse bytes specification %s", assignment);
1449 return -EINVAL;
1450 }
df31a6c0
LP
1451 }
1452
59f448cf 1453 r = sd_bus_message_append(m, "v", "t", bytes);
df31a6c0 1454
03a7b521
LP
1455 } else if (streq(field, "TasksMax")) {
1456 uint64_t n;
1457
1458 if (isempty(eq) || streq(eq, "infinity"))
1459 n = (uint64_t) -1;
1460 else {
1461 r = safe_atou64(eq, &n);
1462 if (r < 0) {
1463 log_error("Failed to parse maximum tasks specification %s", assignment);
1464 return -EINVAL;
1465 }
1466 }
1467
1468 r = sd_bus_message_append(m, "v", "t", n);
1469
d53d9474
LP
1470 } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
1471 uint64_t u;
1472
1473 r = cg_cpu_shares_parse(eq, &u);
1474 if (r < 0) {
1475 log_error("Failed to parse %s value %s.", field, eq);
1476 return -EINVAL;
1477 }
1478
1479 r = sd_bus_message_append(m, "v", "t", u);
1480
1481 } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
df31a6c0
LP
1482 uint64_t u;
1483
d53d9474 1484 r = cg_cpu_shares_parse(eq, &u);
df31a6c0
LP
1485 if (r < 0) {
1486 log_error("Failed to parse %s value %s.", field, eq);
1487 return -EINVAL;
1488 }
1489
1490 r = sd_bus_message_append(m, "v", "t", u);
1491
8bed4cbc
LP
1492 } else if (STR_IN_SET(field,
1493 "User", "Group", "DevicePolicy", "KillMode",
1494 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1495 "StandardInput", "StandardOutput", "StandardError",
602b8355 1496 "Description", "Slice", "Type", "WorkingDirectory",
de53c417 1497 "RootDirectory", "SyslogIdentifier"))
df31a6c0
LP
1498 r = sd_bus_message_append(m, "v", "s", eq);
1499
1500 else if (streq(field, "DeviceAllow")) {
1501
1502 if (isempty(eq))
1503 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1504 else {
1505 const char *path, *rwm, *e;
1506
1507 e = strchr(eq, ' ');
1508 if (e) {
1509 path = strndupa(eq, e - eq);
1510 rwm = e+1;
1511 } else {
1512 path = eq;
1513 rwm = "";
1514 }
1515
1516 if (!path_startswith(path, "/dev")) {
1517 log_error("%s is not a device file in /dev.", path);
1518 return -EINVAL;
1519 }
1520
1521 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1522 }
1523
1524 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1525
1526 if (isempty(eq))
1527 r = sd_bus_message_append(m, "v", "a(st)", 0);
1528 else {
1529 const char *path, *bandwidth, *e;
59f448cf 1530 uint64_t bytes;
df31a6c0
LP
1531
1532 e = strchr(eq, ' ');
1533 if (e) {
1534 path = strndupa(eq, e - eq);
1535 bandwidth = e+1;
1536 } else {
1537 log_error("Failed to parse %s value %s.", field, eq);
1538 return -EINVAL;
1539 }
1540
1541 if (!path_startswith(path, "/dev")) {
1542 log_error("%s is not a device file in /dev.", path);
1543 return -EINVAL;
1544 }
1545
1546 r = parse_size(bandwidth, 1000, &bytes);
1547 if (r < 0) {
1548 log_error("Failed to parse byte value %s.", bandwidth);
1549 return -EINVAL;
1550 }
1551
59f448cf 1552 r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
df31a6c0
LP
1553 }
1554
1555 } else if (streq(field, "BlockIODeviceWeight")) {
1556
1557 if (isempty(eq))
1558 r = sd_bus_message_append(m, "v", "a(st)", 0);
1559 else {
1560 const char *path, *weight, *e;
1561 uint64_t u;
1562
1563 e = strchr(eq, ' ');
1564 if (e) {
1565 path = strndupa(eq, e - eq);
1566 weight = e+1;
1567 } else {
1568 log_error("Failed to parse %s value %s.", field, eq);
1569 return -EINVAL;
1570 }
1571
1572 if (!path_startswith(path, "/dev")) {
1573 log_error("%s is not a device file in /dev.", path);
1574 return -EINVAL;
1575 }
1576
1577 r = safe_atou64(weight, &u);
1578 if (r < 0) {
1579 log_error("Failed to parse %s value %s.", field, weight);
1580 return -EINVAL;
1581 }
1582 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1583 }
1584
d584f638
LP
1585 } else if (rlimit_from_string(field) >= 0) {
1586 uint64_t rl;
1587
1588 if (streq(eq, "infinity"))
1589 rl = (uint64_t) -1;
1590 else {
1591 r = safe_atou64(eq, &rl);
1592 if (r < 0) {
1593 log_error("Invalid resource limit: %s", eq);
1594 return -EINVAL;
1595 }
1596 }
1597
1598 r = sd_bus_message_append(m, "v", "t", rl);
1599
e567439e
LP
1600 } else if (streq(field, "Nice")) {
1601 int32_t i;
1602
1603 r = safe_atoi32(eq, &i);
1604 if (r < 0) {
1605 log_error("Failed to parse %s value %s.", field, eq);
1606 return -EINVAL;
1607 }
1608
1609 r = sd_bus_message_append(m, "v", "i", i);
1610
1611 } else if (streq(field, "Environment")) {
1612
1613 r = sd_bus_message_append(m, "v", "as", 1, eq);
1614
1615 } else if (streq(field, "KillSignal")) {
1616 int sig;
1617
1618 sig = signal_from_string_try_harder(eq);
1619 if (sig < 0) {
1620 log_error("Failed to parse %s value %s.", field, eq);
1621 return -EINVAL;
1622 }
1623
1624 r = sd_bus_message_append(m, "v", "i", sig);
1625
4c213d6c
WC
1626 } else if (streq(field, "AccuracySec")) {
1627 usec_t u;
1628
1629 r = parse_sec(eq, &u);
1630 if (r < 0) {
1631 log_error("Failed to parse %s value %s", field, eq);
1632 return -EINVAL;
1633 }
1634
1635 r = sd_bus_message_append(m, "v", "t", u);
1636
df31a6c0
LP
1637 } else {
1638 log_error("Unknown assignment %s.", assignment);
1639 return -EINVAL;
1640 }
1641
1642 if (r < 0)
1643 return bus_log_create_error(r);
1644
1645 return 0;
1646}
ebd011d9
LP
1647
1648typedef struct BusWaitForJobs {
1649 sd_bus *bus;
1650 Set *jobs;
1651
1652 char *name;
1653 char *result;
1654
1655 sd_bus_slot *slot_job_removed;
1656 sd_bus_slot *slot_disconnected;
1657} BusWaitForJobs;
1658
19070062 1659static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
ebd011d9
LP
1660 assert(m);
1661
1662 log_error("Warning! D-Bus connection terminated.");
19070062 1663 sd_bus_close(sd_bus_message_get_bus(m));
ebd011d9
LP
1664
1665 return 0;
1666}
1667
19070062 1668static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
ebd011d9
LP
1669 const char *path, *unit, *result;
1670 BusWaitForJobs *d = userdata;
1671 uint32_t id;
1672 char *found;
1673 int r;
1674
ebd011d9
LP
1675 assert(m);
1676 assert(d);
1677
1678 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1679 if (r < 0) {
1680 bus_log_parse_error(r);
1681 return 0;
1682 }
1683
1684 found = set_remove(d->jobs, (char*) path);
1685 if (!found)
1686 return 0;
1687
1688 free(found);
1689
1690 if (!isempty(result))
1691 d->result = strdup(result);
1692
1693 if (!isempty(unit))
1694 d->name = strdup(unit);
1695
1696 return 0;
1697}
1698
1699void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1700 if (!d)
1701 return;
1702
1703 set_free_free(d->jobs);
1704
1705 sd_bus_slot_unref(d->slot_disconnected);
1706 sd_bus_slot_unref(d->slot_job_removed);
1707
1708 sd_bus_unref(d->bus);
1709
1710 free(d->name);
1711 free(d->result);
1712
1713 free(d);
1714}
1715
1716int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1717 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1718 int r;
1719
1720 assert(bus);
1721 assert(ret);
1722
1723 d = new0(BusWaitForJobs, 1);
1724 if (!d)
1725 return -ENOMEM;
1726
1727 d->bus = sd_bus_ref(bus);
1728
b798e7ba
LP
1729 /* When we are a bus client we match by sender. Direct
1730 * connections OTOH have no initialized sender field, and
1731 * hence we ignore the sender then */
ebd011d9
LP
1732 r = sd_bus_add_match(
1733 bus,
1734 &d->slot_job_removed,
b798e7ba 1735 bus->bus_client ?
ebd011d9
LP
1736 "type='signal',"
1737 "sender='org.freedesktop.systemd1',"
1738 "interface='org.freedesktop.systemd1.Manager',"
1739 "member='JobRemoved',"
b798e7ba
LP
1740 "path='/org/freedesktop/systemd1'" :
1741 "type='signal',"
1742 "interface='org.freedesktop.systemd1.Manager',"
1743 "member='JobRemoved',"
ebd011d9
LP
1744 "path='/org/freedesktop/systemd1'",
1745 match_job_removed, d);
1746 if (r < 0)
1747 return r;
1748
1749 r = sd_bus_add_match(
1750 bus,
1751 &d->slot_disconnected,
1752 "type='signal',"
1753 "sender='org.freedesktop.DBus.Local',"
1754 "interface='org.freedesktop.DBus.Local',"
1755 "member='Disconnected'",
1756 match_disconnected, d);
1757 if (r < 0)
1758 return r;
1759
1760 *ret = d;
1761 d = NULL;
1762
1763 return 0;
1764}
1765
1766static int bus_process_wait(sd_bus *bus) {
1767 int r;
1768
1769 for (;;) {
1770 r = sd_bus_process(bus, NULL);
1771 if (r < 0)
1772 return r;
1773 if (r > 0)
1774 return 0;
1775
1776 r = sd_bus_wait(bus, (uint64_t) -1);
1777 if (r < 0)
1778 return r;
1779 }
1780}
1781
d5cad221
MS
1782static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
1783 _cleanup_free_ char *dbus_path = NULL;
1784
1785 assert(d);
1786 assert(d->name);
1787 assert(result);
1788
1789 dbus_path = unit_dbus_path_from_name(d->name);
1790 if (!dbus_path)
1791 return -ENOMEM;
1792
1793 return sd_bus_get_property_string(d->bus,
1794 "org.freedesktop.systemd1",
1795 dbus_path,
1796 "org.freedesktop.systemd1.Service",
1797 "Result",
1798 NULL,
1799 result);
1800}
1801
1802static const struct {
1803 const char *result, *explanation;
1804} explanations [] = {
a61cc460
ZJS
1805 { "resources", "a configured resource limit was exceeded" },
1806 { "timeout", "a timeout was exceeded" },
1807 { "exit-code", "the control process exited with error code" },
1808 { "signal", "a fatal signal was delivered to the control process" },
1809 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1810 { "watchdog", "the service failed to send watchdog ping" },
1811 { "start-limit", "start of the service was attempted too often" }
d5cad221
MS
1812};
1813
1814static void log_job_error_with_service_result(const char* service, const char *result) {
d5cad221
MS
1815 _cleanup_free_ char *service_shell_quoted = NULL;
1816
1817 assert(service);
d5cad221
MS
1818
1819 service_shell_quoted = shell_maybe_quote(service);
1820
373a99e4
LP
1821 if (!isempty(result)) {
1822 unsigned i;
d5cad221 1823
373a99e4
LP
1824 for (i = 0; i < ELEMENTSOF(explanations); ++i)
1825 if (streq(result, explanations[i].result))
1826 break;
1827
1828 if (i < ELEMENTSOF(explanations)) {
1829 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1830 service,
1831 explanations[i].explanation,
1832 strna(service_shell_quoted));
d5cad221 1833
373a99e4
LP
1834 goto finish;
1835 }
1836 }
1837
1838 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1839 service,
1840 strna(service_shell_quoted));
1841
1842finish:
d5cad221
MS
1843 /* For some results maybe additional explanation is required */
1844 if (streq_ptr(result, "start-limit"))
a61cc460 1845 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
d5cad221
MS
1846 strna(service_shell_quoted));
1847}
1848
ebd011d9
LP
1849static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1850 int r = 0;
1851
1852 assert(d->result);
1853
1854 if (!quiet) {
1855 if (streq(d->result, "canceled"))
1856 log_error("Job for %s canceled.", strna(d->name));
1857 else if (streq(d->result, "timeout"))
1858 log_error("Job for %s timed out.", strna(d->name));
1859 else if (streq(d->result, "dependency"))
1860 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1861 else if (streq(d->result, "invalid"))
1862 log_error("Job for %s invalid.", strna(d->name));
1863 else if (streq(d->result, "assert"))
1864 log_error("Assertion failed on job for %s.", strna(d->name));
1865 else if (streq(d->result, "unsupported"))
1866 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1867 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
d5cad221
MS
1868 if (d->name) {
1869 int q;
1870 _cleanup_free_ char *result = NULL;
ebd011d9 1871
d5cad221
MS
1872 q = bus_job_get_service_result(d, &result);
1873 if (q < 0)
1874 log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
ebd011d9 1875
d5cad221
MS
1876 log_job_error_with_service_result(d->name, result);
1877 } else
1878 log_error("Job failed. See \"journalctl -xe\" for details.");
ebd011d9
LP
1879 }
1880 }
1881
1882 if (streq(d->result, "canceled"))
1883 r = -ECANCELED;
1884 else if (streq(d->result, "timeout"))
1885 r = -ETIME;
1886 else if (streq(d->result, "dependency"))
1887 r = -EIO;
1888 else if (streq(d->result, "invalid"))
1889 r = -ENOEXEC;
1890 else if (streq(d->result, "assert"))
1891 r = -EPROTO;
1892 else if (streq(d->result, "unsupported"))
15411c0c 1893 r = -EOPNOTSUPP;
ebd011d9
LP
1894 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1895 r = -EIO;
1896
1897 return r;
1898}
1899
1900int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1901 int r = 0;
1902
1903 assert(d);
1904
1905 while (!set_isempty(d->jobs)) {
1906 int q;
1907
1908 q = bus_process_wait(d->bus);
1909 if (q < 0)
1910 return log_error_errno(q, "Failed to wait for response: %m");
1911
1912 if (d->result) {
1913 q = check_wait_response(d, quiet);
1914 /* Return the first error as it is most likely to be
1915 * meaningful. */
1916 if (q < 0 && r == 0)
1917 r = q;
1918
1919 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1920 }
1921
a1e58e8e
LP
1922 d->name = mfree(d->name);
1923 d->result = mfree(d->result);
ebd011d9
LP
1924 }
1925
1926 return r;
1927}
1928
1929int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1930 int r;
1931
1932 assert(d);
1933
1934 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1935 if (r < 0)
1936 return r;
1937
1938 return set_put_strdup(d->jobs, path);
1939}
d8f52ed2 1940
de158ed2
LP
1941int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
1942 int r;
1943
1944 r = bus_wait_for_jobs_add(d, path);
1945 if (r < 0)
1946 return log_oom();
1947
1948 return bus_wait_for_jobs(d, quiet);
1949}
1950
57ab2eab 1951int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
d8f52ed2
LP
1952 const char *type, *path, *source;
1953 int r;
1954
1955 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1956 if (r < 0)
1957 return bus_log_parse_error(r);
1958
1959 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1960 if (!quiet) {
1961 if (streq(type, "symlink"))
1962 log_info("Created symlink from %s to %s.", path, source);
1963 else
1964 log_info("Removed symlink %s.", path);
1965 }
57ab2eab
JS
1966
1967 r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
1968 if (r < 0)
1969 return r;
d8f52ed2
LP
1970 }
1971 if (r < 0)
1972 return bus_log_parse_error(r);
1973
1974 r = sd_bus_message_exit_container(m);
1975 if (r < 0)
1976 return bus_log_parse_error(r);
1977
1978 return 0;
1979}
98a4c30b
DH
1980
1981/**
1982 * bus_path_encode_unique() - encode unique object path
1983 * @b: bus connection or NULL
1984 * @prefix: object path prefix
1985 * @sender_id: unique-name of client, or NULL
1986 * @external_id: external ID to be chosen by client, or NULL
1987 * @ret_path: storage for encoded object path pointer
1988 *
1989 * Whenever we provide a bus API that allows clients to create and manage
1990 * server-side objects, we need to provide a unique name for these objects. If
1991 * we let the server choose the name, we suffer from a race condition: If a
1992 * client creates an object asynchronously, it cannot destroy that object until
1993 * it received the method reply. It cannot know the name of the new object,
1994 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1995 *
1996 * Therefore, many APIs allow the client to choose the unique name for newly
1997 * created objects. There're two problems to solve, though:
1998 * 1) Object names are usually defined via dbus object paths, which are
1999 * usually globally namespaced. Therefore, multiple clients must be able
2000 * to choose unique object names without interference.
2001 * 2) If multiple libraries share the same bus connection, they must be
2002 * able to choose unique object names without interference.
2003 * The first problem is solved easily by prefixing a name with the
2004 * unique-bus-name of a connection. The server side must enforce this and
2005 * reject any other name. The second problem is solved by providing unique
2006 * suffixes from within sd-bus.
2007 *
2008 * This helper allows clients to create unique object-paths. It uses the
2009 * template '/prefix/sender_id/external_id' and returns the new path in
2010 * @ret_path (must be freed by the caller).
2011 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2012 * NULL, this function allocates a unique suffix via @b (by requesting a new
2013 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2014 * NULL.
2015 *
2016 * Returns: 0 on success, negative error code on failure.
2017 */
2018int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
2019 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
2020 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
2021 int r;
2022
2023 assert_return(b || (sender_id && external_id), -EINVAL);
2024 assert_return(object_path_is_valid(prefix), -EINVAL);
2025 assert_return(ret_path, -EINVAL);
2026
2027 if (!sender_id) {
2028 r = sd_bus_get_unique_name(b, &sender_id);
2029 if (r < 0)
2030 return r;
2031 }
2032
2033 if (!external_id) {
2034 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
2035 external_id = external_buf;
2036 }
2037
2038 sender_label = bus_label_escape(sender_id);
2039 if (!sender_label)
2040 return -ENOMEM;
2041
2042 external_label = bus_label_escape(external_id);
2043 if (!external_label)
2044 return -ENOMEM;
2045
2046 p = strjoin(prefix, "/", sender_label, "/", external_label, NULL);
2047 if (!p)
2048 return -ENOMEM;
2049
2050 *ret_path = p;
2051 return 0;
2052}
2053
2054/**
2055 * bus_path_decode_unique() - decode unique object path
2056 * @path: object path to decode
2057 * @prefix: object path prefix
2058 * @ret_sender: output parameter for sender-id label
2059 * @ret_external: output parameter for external-id label
2060 *
2061 * This does the reverse of bus_path_encode_unique() (see its description for
2062 * details). Both trailing labels, sender-id and external-id, are unescaped and
2063 * returned in the given output parameters (the caller must free them).
2064 *
2065 * Note that this function returns 0 if the path does not match the template
2066 * (see bus_path_encode_unique()), 1 if it matched.
2067 *
2068 * Returns: Negative error code on failure, 0 if the given object path does not
2069 * match the template (return parameters are set to NULL), 1 if it was
2070 * parsed successfully (return parameters contain allocated labels).
2071 */
2072int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
2073 const char *p, *q;
2074 char *sender, *external;
2075
2076 assert(object_path_is_valid(path));
2077 assert(object_path_is_valid(prefix));
2078 assert(ret_sender);
2079 assert(ret_external);
2080
2081 p = object_path_startswith(path, prefix);
2082 if (!p) {
2083 *ret_sender = NULL;
2084 *ret_external = NULL;
2085 return 0;
2086 }
2087
2088 q = strchr(p, '/');
2089 if (!q) {
2090 *ret_sender = NULL;
2091 *ret_external = NULL;
2092 return 0;
2093 }
2094
2095 sender = bus_label_unescape_n(p, q - p);
2096 external = bus_label_unescape(q + 1);
2097 if (!sender || !external) {
2098 free(sender);
2099 free(external);
2100 return -ENOMEM;
2101 }
2102
2103 *ret_sender = sender;
2104 *ret_external = external;
2105 return 1;
2106}
057171ef
DH
2107
2108bool is_kdbus_wanted(void) {
2109 _cleanup_free_ char *value = NULL;
2110#ifdef ENABLE_KDBUS
2111 const bool configured = true;
2112#else
2113 const bool configured = false;
2114#endif
2115
2116 int r;
2117
2118 if (get_proc_cmdline_key("kdbus", NULL) > 0)
2119 return true;
2120
2121 r = get_proc_cmdline_key("kdbus=", &value);
2122 if (r <= 0)
2123 return configured;
2124
2125 return parse_boolean(value) == 1;
2126}
2127
2128bool is_kdbus_available(void) {
2129 _cleanup_close_ int fd = -1;
2130 struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE };
2131
2132 if (!is_kdbus_wanted())
2133 return false;
2134
2135 fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
2136 if (fd < 0)
2137 return false;
2138
2139 return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
2140}
c9d031c3
EV
2141
2142int bus_property_get_rlimit(
2143 sd_bus *bus,
2144 const char *path,
2145 const char *interface,
2146 const char *property,
2147 sd_bus_message *reply,
2148 void *userdata,
2149 sd_bus_error *error) {
2150
2151 struct rlimit *rl;
2152 uint64_t u;
2153 rlim_t x;
2154
2155 assert(bus);
2156 assert(reply);
2157 assert(userdata);
2158
2159 rl = *(struct rlimit**) userdata;
2160 if (rl)
2161 x = rl->rlim_max;
2162 else {
2163 struct rlimit buf = {};
2164 int z;
2165
f6bcaf4c 2166 z = rlimit_from_string(strstr(property, "Limit"));
c9d031c3
EV
2167 assert(z >= 0);
2168
2169 getrlimit(z, &buf);
2170 x = buf.rlim_max;
2171 }
2172
2173 /* rlim_t might have different sizes, let's map
2174 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2175 * all archs */
2176 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
2177
2178 return sd_bus_message_append(reply, "t", u);
2179}