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