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