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