]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-util.c
tree-wide: there is no ENOTSUP on linux
[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"
40ca29a1 33
ffc06c35
KS
34#include "sd-bus.h"
35#include "bus-error.h"
36#include "bus-message.h"
40ca29a1 37#include "bus-util.h"
ebcf1f97 38#include "bus-internal.h"
40ca29a1 39
6203e07a 40static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40ca29a1
LP
41 sd_event *e = userdata;
42
43 assert(bus);
44 assert(m);
45 assert(e);
46
b27adf35 47 sd_bus_close(bus);
6203e07a 48 sd_event_exit(e, 0);
b27adf35 49
40ca29a1
LP
50 return 1;
51}
52
6203e07a 53int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
40ca29a1 54 _cleanup_free_ char *match = NULL;
11846aa7 55 const char *unique;
40ca29a1
LP
56 int r;
57
58 assert(e);
59 assert(bus);
60 assert(name);
61
6203e07a
LP
62 /* We unregister the name here and then wait for the
63 * NameOwnerChanged signal for this event to arrive before we
64 * quit. We do this in order to make sure that any queued
65 * requests are still processed before we really exit. */
66
11846aa7 67 r = sd_bus_get_unique_name(bus, &unique);
40ca29a1
LP
68 if (r < 0)
69 return r;
70
11846aa7
LP
71 r = asprintf(&match,
72 "sender='org.freedesktop.DBus',"
73 "type='signal',"
74 "interface='org.freedesktop.DBus',"
75 "member='NameOwnerChanged',"
76 "path='/org/freedesktop/DBus',"
77 "arg0='%s',"
78 "arg1='%s',"
79 "arg2=''", name, unique);
80 if (r < 0)
81 return -ENOMEM;
82
19befb2d 83 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
40ca29a1
LP
84 if (r < 0)
85 return r;
86
87 r = sd_bus_release_name(bus, name);
88 if (r < 0)
89 return r;
90
40ca29a1
LP
91 return 0;
92}
93
37224a5f
LP
94int bus_event_loop_with_idle(
95 sd_event *e,
96 sd_bus *bus,
97 const char *name,
98 usec_t timeout,
99 check_idle_t check_idle,
100 void *userdata) {
40ca29a1 101 bool exiting = false;
6203e07a 102 int r, code;
40ca29a1
LP
103
104 assert(e);
105 assert(bus);
106 assert(name);
107
108 for (;;) {
37224a5f
LP
109 bool idle;
110
40ca29a1
LP
111 r = sd_event_get_state(e);
112 if (r < 0)
113 return r;
40ca29a1
LP
114 if (r == SD_EVENT_FINISHED)
115 break;
116
37224a5f
LP
117 if (check_idle)
118 idle = check_idle(userdata);
119 else
120 idle = true;
121
122 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
40ca29a1
LP
123 if (r < 0)
124 return r;
125
a8ba6cd1 126 if (r == 0 && !exiting && idle) {
b27adf35
LP
127
128 r = sd_bus_try_close(bus);
129 if (r == -EBUSY)
130 continue;
131
430e21c2
LP
132 /* Fallback for dbus1 connections: we
133 * unregister the name and wait for the
134 * response to come through for it */
15411c0c 135 if (r == -EOPNOTSUPP) {
430e21c2
LP
136
137 /* Inform the service manager that we
138 * are going down, so that it will
139 * queue all further start requests,
140 * instead of assuming we are already
141 * running. */
142 sd_notify(false, "STOPPING=1");
b27adf35
LP
143
144 r = bus_async_unregister_and_exit(e, bus, name);
145 if (r < 0)
146 return r;
147
148 exiting = true;
149 continue;
150 }
151
40ca29a1
LP
152 if (r < 0)
153 return r;
154
b27adf35
LP
155 sd_event_exit(e, 0);
156 break;
40ca29a1
LP
157 }
158 }
159
6203e07a
LP
160 r = sd_event_get_exit_code(e, &code);
161 if (r < 0)
162 return r;
163
164 return code;
40ca29a1
LP
165}
166
5fd38859
DH
167int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
168 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
169 int r, has_owner = 0;
170
171 assert(c);
172 assert(name);
173
174 r = sd_bus_call_method(c,
175 "org.freedesktop.DBus",
176 "/org/freedesktop/dbus",
177 "org.freedesktop.DBus",
178 "NameHasOwner",
179 error,
180 &rep,
181 "s",
182 name);
183 if (r < 0)
184 return r;
185
186 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
187 if (r < 0)
188 return sd_bus_error_set_errno(error, r);
189
190 return has_owner;
191}
192
c529695e
LP
193static int check_good_user(sd_bus_message *m, uid_t good_user) {
194 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
195 uid_t sender_uid;
196 int r;
197
198 assert(m);
199
200 if (good_user == UID_INVALID)
201 return 0;
202
203 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
204 if (r < 0)
205 return r;
206
207 r = sd_bus_creds_get_euid(creds, &sender_uid);
208 if (r < 0)
209 return r;
210
211 return sender_uid == good_user;
212}
213
40ca29a1 214int bus_verify_polkit(
f3885791 215 sd_bus_message *call,
def9a7aa 216 int capability,
40ca29a1
LP
217 const char *action,
218 bool interactive,
c529695e 219 uid_t good_user,
40ca29a1
LP
220 bool *_challenge,
221 sd_bus_error *e) {
222
40ca29a1
LP
223 int r;
224
f3885791 225 assert(call);
40ca29a1
LP
226 assert(action);
227
c529695e
LP
228 r = check_good_user(call, good_user);
229 if (r != 0)
230 return r;
231
f3885791 232 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
233 if (r < 0)
234 return r;
f3885791 235 else if (r > 0)
40ca29a1 236 return 1;
40ca29a1
LP
237#ifdef ENABLE_POLKIT
238 else {
239 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
b911eb15 240 int authorized = false, challenge = false, c;
5b12334d
LP
241 const char *sender;
242
f3885791 243 sender = sd_bus_message_get_sender(call);
5b12334d
LP
244 if (!sender)
245 return -EBADMSG;
40ca29a1 246
b911eb15
LP
247 c = sd_bus_message_get_allow_interactive_authorization(call);
248 if (c < 0)
249 return c;
250 if (c > 0)
251 interactive = true;
252
40ca29a1 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,
b911eb15 265 !!interactive,
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
325static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
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
330 assert(bus);
331 assert(reply);
332 assert(q);
333
19befb2d 334 q->slot = sd_bus_slot_unref(q->slot);
40ca29a1 335 q->reply = sd_bus_message_ref(reply);
40ca29a1 336
ebcf1f97
LP
337 r = sd_bus_message_rewind(q->request, true);
338 if (r < 0) {
339 r = sd_bus_reply_method_errno(q->request, r, NULL);
340 goto finish;
341 }
40ca29a1 342
ebcf1f97
LP
343 r = q->callback(bus, q->request, q->userdata, &error_buffer);
344 r = bus_maybe_reply_error(q->request, r, &error_buffer);
40ca29a1 345
ebcf1f97 346finish:
19befb2d
LP
347 async_polkit_query_free(q);
348
ebcf1f97 349 return r;
40ca29a1
LP
350}
351
352#endif
353
354int bus_verify_polkit_async(
f3885791 355 sd_bus_message *call,
def9a7aa 356 int capability,
40ca29a1
LP
357 const char *action,
358 bool interactive,
c529695e 359 uid_t good_user,
f3885791
LP
360 Hashmap **registry,
361 sd_bus_error *error) {
40ca29a1
LP
362
363#ifdef ENABLE_POLKIT
364 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
365 AsyncPolkitQuery *q;
40ca29a1 366 const char *sender;
f3885791
LP
367 sd_bus_message_handler_t callback;
368 void *userdata;
b911eb15 369 int c;
5b12334d 370#endif
40ca29a1
LP
371 int r;
372
f3885791 373 assert(call);
40ca29a1 374 assert(action);
f3885791 375 assert(registry);
40ca29a1 376
c529695e
LP
377 r = check_good_user(call, good_user);
378 if (r != 0)
379 return r;
380
40ca29a1 381#ifdef ENABLE_POLKIT
f3885791 382 q = hashmap_get(*registry, call);
40ca29a1 383 if (q) {
102d8f81 384 int authorized, challenge;
40ca29a1
LP
385
386 /* This is the second invocation of this function, and
387 * there's already a response from polkit, let's
388 * process it */
389 assert(q->reply);
390
391 if (sd_bus_message_is_method_error(q->reply, NULL)) {
392 const sd_bus_error *e;
393
ebcf1f97 394 /* Copy error from polkit reply */
40ca29a1
LP
395 e = sd_bus_message_get_error(q->reply);
396 sd_bus_error_copy(error, e);
40ca29a1 397
ebcf1f97
LP
398 /* Treat no PK available as access denied */
399 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
400 return -EACCES;
401
5958d089 402 return -sd_bus_error_get_errno(e);
40ca29a1
LP
403 }
404
405 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
406 if (r >= 0)
407 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
408
40ca29a1
LP
409 if (r < 0)
410 return r;
411
412 if (authorized)
413 return 1;
414
f2288cc6
LP
415 if (challenge)
416 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
417
40ca29a1
LP
418 return -EACCES;
419 }
420#endif
421
f3885791 422 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
423 if (r < 0)
424 return r;
f3885791 425 else if (r > 0)
40ca29a1 426 return 1;
5b12334d 427
40ca29a1 428#ifdef ENABLE_POLKIT
f3885791
LP
429 if (sd_bus_get_current_message(call->bus) != call)
430 return -EINVAL;
431
432 callback = sd_bus_get_current_handler(call->bus);
433 if (!callback)
434 return -EINVAL;
435
436 userdata = sd_bus_get_current_userdata(call->bus);
437
438 sender = sd_bus_message_get_sender(call);
5b12334d
LP
439 if (!sender)
440 return -EBADMSG;
40ca29a1 441
b911eb15
LP
442 c = sd_bus_message_get_allow_interactive_authorization(call);
443 if (c < 0)
444 return c;
445 if (c > 0)
446 interactive = true;
447
d5099efc 448 r = hashmap_ensure_allocated(registry, NULL);
40ca29a1
LP
449 if (r < 0)
450 return r;
451
452 r = sd_bus_message_new_method_call(
f3885791 453 call->bus,
151b9b96 454 &pk,
40ca29a1
LP
455 "org.freedesktop.PolicyKit1",
456 "/org/freedesktop/PolicyKit1/Authority",
457 "org.freedesktop.PolicyKit1.Authority",
151b9b96 458 "CheckAuthorization");
40ca29a1
LP
459 if (r < 0)
460 return r;
461
462 r = sd_bus_message_append(
463 pk,
464 "(sa{sv})sa{ss}us",
465 "system-bus-name", 1, "name", "s", sender,
466 action,
467 0,
b911eb15 468 !!interactive,
ebcf1f97 469 NULL);
40ca29a1
LP
470 if (r < 0)
471 return r;
472
473 q = new0(AsyncPolkitQuery, 1);
474 if (!q)
475 return -ENOMEM;
476
f3885791 477 q->request = sd_bus_message_ref(call);
40ca29a1
LP
478 q->callback = callback;
479 q->userdata = userdata;
480
f3885791 481 r = hashmap_put(*registry, call, q);
40ca29a1 482 if (r < 0) {
19befb2d 483 async_polkit_query_free(q);
40ca29a1
LP
484 return r;
485 }
486
ebcf1f97
LP
487 q->registry = *registry;
488
f3885791 489 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
ebcf1f97 490 if (r < 0) {
19befb2d 491 async_polkit_query_free(q);
40ca29a1 492 return r;
ebcf1f97 493 }
40ca29a1
LP
494
495 return 0;
496#endif
497
498 return -EACCES;
499}
500
36e34057 501void bus_verify_polkit_async_registry_free(Hashmap *registry) {
40ca29a1
LP
502#ifdef ENABLE_POLKIT
503 AsyncPolkitQuery *q;
504
505 while ((q = hashmap_steal_first(registry)))
19befb2d 506 async_polkit_query_free(q);
40ca29a1
LP
507
508 hashmap_free(registry);
509#endif
510}
0c842e0a 511
718db961 512int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
513 struct ucred ucred;
514 socklen_t l;
0f8bd8de 515 int fd;
0c842e0a
TG
516
517 assert(c);
518
519 fd = sd_bus_get_fd(c);
0f8bd8de
LP
520 if (fd < 0)
521 return fd;
0c842e0a
TG
522
523 l = sizeof(struct ucred);
0f8bd8de 524 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 525 return -errno;
0c842e0a 526
0f8bd8de 527 if (l != sizeof(struct ucred))
0c842e0a 528 return -E2BIG;
0c842e0a
TG
529
530 if (ucred.uid != 0 && ucred.uid != geteuid())
531 return -EPERM;
532
533 return 1;
534}
535
0f8bd8de
LP
536int bus_open_system_systemd(sd_bus **_bus) {
537 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 538 int r;
0c842e0a
TG
539
540 assert(_bus);
541
0f8bd8de
LP
542 if (geteuid() != 0)
543 return sd_bus_open_system(_bus);
a1da8583 544
a6aa8912
LP
545 /* If we are root and kdbus is not available, then let's talk
546 * directly to the system instance, instead of going via the
547 * bus */
a1da8583 548
a6aa8912 549#ifdef ENABLE_KDBUS
0f8bd8de
LP
550 r = sd_bus_new(&bus);
551 if (r < 0)
552 return r;
a1da8583 553
e3afaf6b 554 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
0f8bd8de
LP
555 if (r < 0)
556 return r;
a1da8583 557
a6aa8912
LP
558 bus->bus_client = true;
559
0f8bd8de 560 r = sd_bus_start(bus);
a6aa8912
LP
561 if (r >= 0) {
562 *_bus = bus;
563 bus = NULL;
564 return 0;
565 }
566
567 bus = sd_bus_unref(bus);
568#endif
569
570 r = sd_bus_new(&bus);
0f8bd8de
LP
571 if (r < 0)
572 return r;
a1da8583 573
a6aa8912
LP
574 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
575 if (r < 0)
576 return r;
577
578 r = sd_bus_start(bus);
579 if (r < 0)
580 return sd_bus_open_system(_bus);
581
0f8bd8de 582 r = bus_check_peercred(bus);
a1da8583
TG
583 if (r < 0)
584 return r;
585
586 *_bus = bus;
0f8bd8de
LP
587 bus = NULL;
588
a1da8583
TG
589 return 0;
590}
591
41dd15e4
LP
592int bus_open_user_systemd(sd_bus **_bus) {
593 _cleanup_bus_unref_ sd_bus *bus = NULL;
a6aa8912 594 _cleanup_free_ char *ee = NULL;
41dd15e4
LP
595 const char *e;
596 int r;
597
a6aa8912 598 /* Try via kdbus first, and then directly */
41dd15e4
LP
599
600 assert(_bus);
601
a6aa8912
LP
602#ifdef ENABLE_KDBUS
603 r = sd_bus_new(&bus);
604 if (r < 0)
605 return r;
606
e3afaf6b 607 if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
a6aa8912
LP
608 return -ENOMEM;
609
610 bus->bus_client = true;
611
612 r = sd_bus_start(bus);
613 if (r >= 0) {
614 *_bus = bus;
615 bus = NULL;
616 return 0;
617 }
618
619 bus = sd_bus_unref(bus);
620#endif
621
41dd15e4 622 e = secure_getenv("XDG_RUNTIME_DIR");
537220d9 623 if (!e)
3f78871b 624 return sd_bus_open_user(_bus);
537220d9 625
a6aa8912
LP
626 ee = bus_address_escape(e);
627 if (!ee)
537220d9 628 return -ENOMEM;
41dd15e4
LP
629
630 r = sd_bus_new(&bus);
631 if (r < 0)
632 return r;
633
a6aa8912
LP
634 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
635 if (!bus->address)
636 return -ENOMEM;
41dd15e4
LP
637
638 r = sd_bus_start(bus);
639 if (r < 0)
3f78871b 640 return sd_bus_open_user(_bus);
41dd15e4
LP
641
642 r = bus_check_peercred(bus);
643 if (r < 0)
644 return r;
645
646 *_bus = bus;
647 bus = NULL;
648
649 return 0;
650}
651
9f6eb1cd 652int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
653 char type;
654 const char *contents;
9f6eb1cd 655 int r;
a1da8583
TG
656
657 assert(name);
658 assert(property);
659
9f6eb1cd
KS
660 r = sd_bus_message_peek_type(property, &type, &contents);
661 if (r < 0)
662 return r;
a1da8583
TG
663
664 switch (type) {
665
666 case SD_BUS_TYPE_STRING: {
667 const char *s;
9f6eb1cd
KS
668
669 r = sd_bus_message_read_basic(property, type, &s);
670 if (r < 0)
671 return r;
a1da8583 672
27e9c5af
LP
673 if (all || !isempty(s)) {
674 _cleanup_free_ char *escaped = NULL;
675
676 escaped = xescape(s, "\n");
677 if (!escaped)
678 return -ENOMEM;
679
680 printf("%s=%s\n", name, escaped);
681 }
a1da8583
TG
682
683 return 1;
684 }
685
686 case SD_BUS_TYPE_BOOLEAN: {
c2fa048c 687 int b;
a1da8583 688
9f6eb1cd
KS
689 r = sd_bus_message_read_basic(property, type, &b);
690 if (r < 0)
691 return r;
692
a1da8583
TG
693 printf("%s=%s\n", name, yes_no(b));
694
695 return 1;
696 }
697
698 case SD_BUS_TYPE_UINT64: {
699 uint64_t u;
700
9f6eb1cd
KS
701 r = sd_bus_message_read_basic(property, type, &u);
702 if (r < 0)
703 return r;
a1da8583
TG
704
705 /* Yes, heuristics! But we can change this check
706 * should it turn out to not be sufficient */
707
708 if (endswith(name, "Timestamp")) {
709 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
710
711 t = format_timestamp(timestamp, sizeof(timestamp), u);
712 if (t || all)
713 printf("%s=%s\n", name, strempty(t));
714
715 } else if (strstr(name, "USec")) {
716 char timespan[FORMAT_TIMESPAN_MAX];
717
718 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
719 } else
720 printf("%s=%llu\n", name, (unsigned long long) u);
721
722 return 1;
723 }
724
725 case SD_BUS_TYPE_UINT32: {
726 uint32_t u;
727
9f6eb1cd
KS
728 r = sd_bus_message_read_basic(property, type, &u);
729 if (r < 0)
730 return r;
a1da8583
TG
731
732 if (strstr(name, "UMask") || strstr(name, "Mode"))
733 printf("%s=%04o\n", name, u);
734 else
735 printf("%s=%u\n", name, (unsigned) u);
736
737 return 1;
738 }
739
740 case SD_BUS_TYPE_INT32: {
741 int32_t i;
742
9f6eb1cd
KS
743 r = sd_bus_message_read_basic(property, type, &i);
744 if (r < 0)
745 return r;
a1da8583
TG
746
747 printf("%s=%i\n", name, (int) i);
748 return 1;
749 }
750
751 case SD_BUS_TYPE_DOUBLE: {
752 double d;
753
9f6eb1cd
KS
754 r = sd_bus_message_read_basic(property, type, &d);
755 if (r < 0)
756 return r;
a1da8583
TG
757
758 printf("%s=%g\n", name, d);
759 return 1;
760 }
761
762 case SD_BUS_TYPE_ARRAY:
a1da8583 763 if (streq(contents, "s")) {
261afec5
MAP
764 bool first = true;
765 const char *str;
a1da8583 766
9f6eb1cd
KS
767 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
768 if (r < 0)
769 return r;
770
261afec5 771 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
27e9c5af
LP
772 _cleanup_free_ char *escaped = NULL;
773
261afec5
MAP
774 if (first)
775 printf("%s=", name);
776
27e9c5af
LP
777 escaped = xescape(str, "\n ");
778 if (!escaped)
779 return -ENOMEM;
780
781 printf("%s%s", first ? "" : " ", escaped);
261afec5
MAP
782
783 first = false;
784 }
9f6eb1cd
KS
785 if (r < 0)
786 return r;
a1da8583 787
261afec5 788 if (first && all)
a1da8583 789 printf("%s=", name);
261afec5 790 if (!first || all)
a1da8583 791 puts("");
a1da8583 792
9f6eb1cd
KS
793 r = sd_bus_message_exit_container(property);
794 if (r < 0)
795 return r;
a1da8583
TG
796
797 return 1;
798
799 } else if (streq(contents, "y")) {
800 const uint8_t *u;
801 size_t n;
802
9f6eb1cd
KS
803 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
804 if (r < 0)
805 return r;
806
a1da8583
TG
807 if (all || n > 0) {
808 unsigned int i;
809
810 printf("%s=", name);
811
812 for (i = 0; i < n; i++)
813 printf("%02x", u[i]);
814
815 puts("");
816 }
817
818 return 1;
819
820 } else if (streq(contents, "u")) {
821 uint32_t *u;
822 size_t n;
823
9f6eb1cd
KS
824 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
825 if (r < 0)
826 return r;
827
a1da8583
TG
828 if (all || n > 0) {
829 unsigned int i;
830
831 printf("%s=", name);
832
833 for (i = 0; i < n; i++)
834 printf("%08x", u[i]);
835
836 puts("");
837 }
838
839 return 1;
840 }
841
842 break;
843 }
844
845 return 0;
846}
d21ed1ea 847
27e72d6b 848int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 849 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
850 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
851 int r;
852
9f6eb1cd
KS
853 assert(bus);
854 assert(path);
855
856 r = sd_bus_call_method(bus,
27e72d6b 857 dest,
ffc06c35
KS
858 path,
859 "org.freedesktop.DBus.Properties",
860 "GetAll",
861 &error,
9f6eb1cd 862 &reply,
ffc06c35 863 "s", "");
9f6eb1cd 864 if (r < 0)
ffc06c35 865 return r;
ffc06c35 866
9f6eb1cd 867 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
868 if (r < 0)
869 return r;
870
9f6eb1cd 871 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 872 const char *name;
ffc06c35 873 const char *contents;
ffc06c35 874
9f6eb1cd 875 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
876 if (r < 0)
877 return r;
878
9f6eb1cd
KS
879 if (!filter || strv_find(filter, name)) {
880 r = sd_bus_message_peek_type(reply, NULL, &contents);
881 if (r < 0)
882 return r;
883
884 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
885 if (r < 0)
886 return r;
ffc06c35 887
9f6eb1cd
KS
888 r = bus_print_property(name, reply, all);
889 if (r < 0)
890 return r;
27e72d6b
SP
891 if (r == 0) {
892 if (all)
893 printf("%s=[unprintable]\n", name);
894 /* skip what we didn't read */
895 r = sd_bus_message_skip(reply, contents);
896 if (r < 0)
897 return r;
898 }
9f6eb1cd
KS
899
900 r = sd_bus_message_exit_container(reply);
901 if (r < 0)
902 return r;
903 } else {
904 r = sd_bus_message_skip(reply, "v");
905 if (r < 0)
906 return r;
907 }
908
909 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
910 if (r < 0)
911 return r;
9f6eb1cd
KS
912 }
913 if (r < 0)
914 return r;
ffc06c35 915
9f6eb1cd
KS
916 r = sd_bus_message_exit_container(reply);
917 if (r < 0)
918 return r;
ffc06c35 919
9f6eb1cd
KS
920 return 0;
921}
ffc06c35 922
9f6eb1cd
KS
923int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
924 sd_id128_t *p = userdata;
925 const void *v;
926 size_t n;
927 int r;
ffc06c35 928
9f6eb1cd
KS
929 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
930 if (r < 0)
931 return r;
ffc06c35 932
9f6eb1cd
KS
933 if (n == 0)
934 *p = SD_ID128_NULL;
935 else if (n == 16)
936 memcpy((*p).bytes, v, n);
937 else
938 return -EINVAL;
ffc06c35 939
9f6eb1cd
KS
940 return 0;
941}
ffc06c35 942
9f6eb1cd
KS
943static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
944 char type;
945 int r;
ffc06c35 946
9f6eb1cd
KS
947 r = sd_bus_message_peek_type(m, &type, NULL);
948 if (r < 0)
949 return r;
ffc06c35 950
9f6eb1cd
KS
951 switch (type) {
952 case SD_BUS_TYPE_STRING: {
953 const char *s;
954 char *str;
955 char **p = userdata;
ffc06c35 956
9f6eb1cd
KS
957 r = sd_bus_message_read_basic(m, type, &s);
958 if (r < 0)
959 break;
ffc06c35 960
9f6eb1cd
KS
961 if (isempty(s))
962 break;
ffc06c35 963
9f6eb1cd
KS
964 str = strdup(s);
965 if (!str) {
966 r = -ENOMEM;
ffc06c35
KS
967 break;
968 }
9f6eb1cd
KS
969 free(*p);
970 *p = str;
ffc06c35 971
9f6eb1cd
KS
972 break;
973 }
ffc06c35 974
9f6eb1cd
KS
975 case SD_BUS_TYPE_ARRAY: {
976 _cleanup_strv_free_ char **l = NULL;
977 char ***p = userdata;
ffc06c35 978
9f6eb1cd
KS
979 r = bus_message_read_strv_extend(m, &l);
980 if (r < 0)
981 break;
ffc06c35 982
9f6eb1cd
KS
983 strv_free(*p);
984 *p = l;
985 l = NULL;
ffc06c35 986
9f6eb1cd
KS
987 break;
988 }
ffc06c35 989
9f6eb1cd
KS
990 case SD_BUS_TYPE_BOOLEAN: {
991 unsigned b;
992 bool *p = userdata;
ffc06c35 993
9f6eb1cd
KS
994 r = sd_bus_message_read_basic(m, type, &b);
995 if (r < 0)
996 break;
ffc06c35 997
9f6eb1cd 998 *p = b;
ffc06c35 999
9f6eb1cd
KS
1000 break;
1001 }
ffc06c35 1002
9f6eb1cd
KS
1003 case SD_BUS_TYPE_UINT32: {
1004 uint64_t u;
1005 uint32_t *p = userdata;
1006
1007 r = sd_bus_message_read_basic(m, type, &u);
1008 if (r < 0)
ffc06c35 1009 break;
ffc06c35 1010
9f6eb1cd
KS
1011 *p = u;
1012
1013 break;
1014 }
1015
1016 case SD_BUS_TYPE_UINT64: {
1017 uint64_t t;
1018 uint64_t *p = userdata;
1019
1020 r = sd_bus_message_read_basic(m, type, &t);
1021 if (r < 0)
ffc06c35 1022 break;
ffc06c35 1023
9f6eb1cd
KS
1024 *p = t;
1025
1026 break;
1027 }
1028
1029 default:
1030 break;
1031 }
1032
1033 return r;
1034}
1035
aae2b488
DH
1036int bus_message_map_all_properties(sd_bus *bus,
1037 sd_bus_message *m,
1038 const struct bus_properties_map *map,
1039 void *userdata) {
9f6eb1cd
KS
1040 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1041 int r;
1042
1043 assert(bus);
aae2b488 1044 assert(m);
9f6eb1cd
KS
1045 assert(map);
1046
9f6eb1cd
KS
1047 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1048 if (r < 0)
1049 return r;
1050
1051 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1052 const struct bus_properties_map *prop;
1053 const char *member;
1054 const char *contents;
1055 void *v;
1056 unsigned i;
1057
1058 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
1059 if (r < 0)
1060 return r;
1061
9f6eb1cd
KS
1062 for (i = 0, prop = NULL; map[i].member; i++)
1063 if (streq(map[i].member, member)) {
1064 prop = &map[i];
1065 break;
1066 }
1067
1068 if (prop) {
1069 r = sd_bus_message_peek_type(m, NULL, &contents);
1070 if (r < 0)
1071 return r;
1072
1073 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1074 if (r < 0)
1075 return r;
1076
1077 v = (uint8_t *)userdata + prop->offset;
27e72d6b 1078 if (map[i].set)
9f6eb1cd
KS
1079 r = prop->set(bus, member, m, &error, v);
1080 else
1081 r = map_basic(bus, member, m, &error, v);
2b49a470
TA
1082 if (r < 0)
1083 return r;
9f6eb1cd
KS
1084
1085 r = sd_bus_message_exit_container(m);
1086 if (r < 0)
1087 return r;
1088 } else {
1089 r = sd_bus_message_skip(m, "v");
1090 if (r < 0)
6c1508b8 1091 return r;
9f6eb1cd
KS
1092 }
1093
ffc06c35
KS
1094 r = sd_bus_message_exit_container(m);
1095 if (r < 0)
1096 return r;
1097 }
1098
aae2b488
DH
1099 return sd_bus_message_exit_container(m);
1100}
1101
1102int bus_message_map_properties_changed(sd_bus *bus,
1103 sd_bus_message *m,
1104 const struct bus_properties_map *map,
1105 void *userdata) {
1106 const char *member;
1107 int r, invalidated, i;
1108
1109 assert(bus);
1110 assert(m);
1111 assert(map);
1112
aae2b488
DH
1113 r = bus_message_map_all_properties(bus, m, map, userdata);
1114 if (r < 0)
1115 return r;
1116
1117 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1118 if (r < 0)
1119 return r;
1120
1121 invalidated = 0;
1122 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1123 for (i = 0; map[i].member; i++)
1124 if (streq(map[i].member, member)) {
1125 ++invalidated;
1126 break;
1127 }
1128
1129 r = sd_bus_message_exit_container(m);
1130 if (r < 0)
1131 return r;
1132
1133 return invalidated;
1134}
1135
1136int bus_map_all_properties(sd_bus *bus,
1137 const char *destination,
1138 const char *path,
1139 const struct bus_properties_map *map,
1140 void *userdata) {
1141 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1142 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1143 int r;
1144
1145 assert(bus);
1146 assert(destination);
1147 assert(path);
1148 assert(map);
1149
1150 r = sd_bus_call_method(
1151 bus,
1152 destination,
1153 path,
1154 "org.freedesktop.DBus.Properties",
1155 "GetAll",
1156 &error,
1157 &m,
1158 "s", "");
1159 if (r < 0)
1160 return r;
1161
1162 return bus_message_map_all_properties(bus, m, map, userdata);
ffc06c35
KS
1163}
1164
d21ed1ea
LP
1165int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1166 int r;
1167
1168 assert(transport >= 0);
1169 assert(transport < _BUS_TRANSPORT_MAX);
1170 assert(bus);
1171
1172 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1173 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
d21ed1ea
LP
1174
1175 switch (transport) {
1176
1177 case BUS_TRANSPORT_LOCAL:
1178 if (user)
76b54375 1179 r = sd_bus_default_user(bus);
d21ed1ea 1180 else
76b54375 1181 r = sd_bus_default_system(bus);
d21ed1ea
LP
1182
1183 break;
1184
1185 case BUS_TRANSPORT_REMOTE:
3db729cb 1186 r = sd_bus_open_system_remote(bus, host);
41dd15e4
LP
1187 break;
1188
de33fc62
LP
1189 case BUS_TRANSPORT_MACHINE:
1190 r = sd_bus_open_system_machine(bus, host);
41dd15e4
LP
1191 break;
1192
1193 default:
1194 assert_not_reached("Hmm, unknown transport type.");
1195 }
1196
1197 return r;
1198}
1199
1200int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1201 int r;
1202
1203 assert(transport >= 0);
1204 assert(transport < _BUS_TRANSPORT_MAX);
1205 assert(bus);
1206
1207 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1208 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
41dd15e4
LP
1209
1210 switch (transport) {
1211
1212 case BUS_TRANSPORT_LOCAL:
1213 if (user)
1214 r = bus_open_user_systemd(bus);
1215 else
1216 r = bus_open_system_systemd(bus);
1217
1218 break;
1219
1220 case BUS_TRANSPORT_REMOTE:
3db729cb 1221 r = sd_bus_open_system_remote(bus, host);
d21ed1ea
LP
1222 break;
1223
de33fc62
LP
1224 case BUS_TRANSPORT_MACHINE:
1225 r = sd_bus_open_system_machine(bus, host);
d21ed1ea
LP
1226 break;
1227
1228 default:
1229 assert_not_reached("Hmm, unknown transport type.");
1230 }
1231
1232 return r;
1233}
e6504030
LP
1234
1235int bus_property_get_bool(
1236 sd_bus *bus,
1237 const char *path,
1238 const char *interface,
1239 const char *property,
1240 sd_bus_message *reply,
ebcf1f97
LP
1241 void *userdata,
1242 sd_bus_error *error) {
e6504030
LP
1243
1244 int b = *(bool*) userdata;
1245
1246 return sd_bus_message_append_basic(reply, 'b', &b);
1247}
1248
718db961
LP
1249#if __SIZEOF_SIZE_T__ != 8
1250int bus_property_get_size(
e6504030
LP
1251 sd_bus *bus,
1252 const char *path,
1253 const char *interface,
1254 const char *property,
1255 sd_bus_message *reply,
ebcf1f97
LP
1256 void *userdata,
1257 sd_bus_error *error) {
e6504030 1258
718db961 1259 uint64_t sz = *(size_t*) userdata;
e6504030 1260
718db961 1261 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1262}
718db961
LP
1263#endif
1264
1265#if __SIZEOF_LONG__ != 8
1266int bus_property_get_long(
1267 sd_bus *bus,
1268 const char *path,
1269 const char *interface,
1270 const char *property,
1271 sd_bus_message *reply,
ebcf1f97
LP
1272 void *userdata,
1273 sd_bus_error *error) {
718db961
LP
1274
1275 int64_t l = *(long*) userdata;
1276
1277 return sd_bus_message_append_basic(reply, 'x', &l);
1278}
1279
1280int bus_property_get_ulong(
1281 sd_bus *bus,
1282 const char *path,
1283 const char *interface,
1284 const char *property,
1285 sd_bus_message *reply,
ebcf1f97
LP
1286 void *userdata,
1287 sd_bus_error *error) {
718db961
LP
1288
1289 uint64_t ul = *(unsigned long*) userdata;
1290
1291 return sd_bus_message_append_basic(reply, 't', &ul);
1292}
1293#endif
5b30bef8
LP
1294
1295int bus_log_parse_error(int r) {
23bbb0de 1296 return log_error_errno(r, "Failed to parse bus message: %m");
5b30bef8 1297}
f459b602
MAP
1298
1299int bus_log_create_error(int r) {
23bbb0de 1300 return log_error_errno(r, "Failed to create bus message: %m");
f459b602
MAP
1301}
1302
1303int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1304 assert(message);
1305 assert(u);
1306
1238ee09
LP
1307 u->machine = NULL;
1308
f459b602
MAP
1309 return sd_bus_message_read(
1310 message,
1311 "(ssssssouso)",
1312 &u->id,
1313 &u->description,
1314 &u->load_state,
1315 &u->active_state,
1316 &u->sub_state,
1317 &u->following,
1318 &u->unit_path,
1319 &u->job_id,
1320 &u->job_type,
1321 &u->job_path);
1322}
ebcf1f97
LP
1323
1324int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1325 assert(m);
1326
1327 if (r < 0) {
1328 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1329 sd_bus_reply_method_errno(m, r, error);
1330
1331 } else if (sd_bus_error_is_set(error)) {
1332 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1333 sd_bus_reply_method_error(m, error);
ebcf1f97
LP
1334 } else
1335 return r;
1336
1337 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1338 bus_message_type_to_string(m->header->type),
1339 strna(m->sender),
1340 strna(m->path),
1341 strna(m->interface),
1342 strna(m->member),
1343 strna(m->root_container.signature),
1344 bus_error_message(error, r));
1345
1346 return 1;
1347}
df31a6c0
LP
1348
1349int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1350 const char *eq, *field;
1351 int r;
1352
1353 assert(m);
1354 assert(assignment);
1355
1356 eq = strchr(assignment, '=');
1357 if (!eq) {
1358 log_error("Not an assignment: %s", assignment);
1359 return -EINVAL;
1360 }
1361
1362 field = strndupa(assignment, eq - assignment);
1363 eq ++;
1364
b2f8b02e
LP
1365 if (streq(field, "CPUQuota")) {
1366
1367 if (isempty(eq)) {
1368
1369 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1370 if (r < 0)
1371 return bus_log_create_error(r);
1372
3a43da28 1373 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
b2f8b02e
LP
1374
1375 } else if (endswith(eq, "%")) {
1376 double percent;
1377
1378 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1379 log_error("CPU quota '%s' invalid.", eq);
1380 return -EINVAL;
1381 }
1382
1383 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1384 if (r < 0)
1385 return bus_log_create_error(r);
1386
1387 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1388 } else {
9a054909 1389 log_error("CPU quota needs to be in percent.");
b2f8b02e
LP
1390 return -EINVAL;
1391 }
1392
b2f8b02e
LP
1393 if (r < 0)
1394 return bus_log_create_error(r);
1395
1396 return 0;
1397 }
1398
df31a6c0
LP
1399 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1400 if (r < 0)
1401 return bus_log_create_error(r);
1402
e567439e
LP
1403 if (STR_IN_SET(field,
1404 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
261420ba 1405 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) {
df31a6c0
LP
1406
1407 r = parse_boolean(eq);
1408 if (r < 0) {
1409 log_error("Failed to parse boolean assignment %s.", assignment);
1410 return -EINVAL;
1411 }
1412
1413 r = sd_bus_message_append(m, "v", "b", r);
1414
1415 } else if (streq(field, "MemoryLimit")) {
1416 off_t bytes;
1417
1418 r = parse_size(eq, 1024, &bytes);
1419 if (r < 0) {
1420 log_error("Failed to parse bytes specification %s", assignment);
1421 return -EINVAL;
1422 }
1423
1424 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1425
1426 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1427 uint64_t u;
1428
1429 r = safe_atou64(eq, &u);
1430 if (r < 0) {
1431 log_error("Failed to parse %s value %s.", field, eq);
1432 return -EINVAL;
1433 }
1434
1435 r = sd_bus_message_append(m, "v", "t", u);
1436
e567439e 1437 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
df31a6c0
LP
1438 r = sd_bus_message_append(m, "v", "s", eq);
1439
1440 else if (streq(field, "DeviceAllow")) {
1441
1442 if (isempty(eq))
1443 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1444 else {
1445 const char *path, *rwm, *e;
1446
1447 e = strchr(eq, ' ');
1448 if (e) {
1449 path = strndupa(eq, e - eq);
1450 rwm = e+1;
1451 } else {
1452 path = eq;
1453 rwm = "";
1454 }
1455
1456 if (!path_startswith(path, "/dev")) {
1457 log_error("%s is not a device file in /dev.", path);
1458 return -EINVAL;
1459 }
1460
1461 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1462 }
1463
1464 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1465
1466 if (isempty(eq))
1467 r = sd_bus_message_append(m, "v", "a(st)", 0);
1468 else {
1469 const char *path, *bandwidth, *e;
1470 off_t bytes;
1471
1472 e = strchr(eq, ' ');
1473 if (e) {
1474 path = strndupa(eq, e - eq);
1475 bandwidth = e+1;
1476 } else {
1477 log_error("Failed to parse %s value %s.", field, eq);
1478 return -EINVAL;
1479 }
1480
1481 if (!path_startswith(path, "/dev")) {
1482 log_error("%s is not a device file in /dev.", path);
1483 return -EINVAL;
1484 }
1485
1486 r = parse_size(bandwidth, 1000, &bytes);
1487 if (r < 0) {
1488 log_error("Failed to parse byte value %s.", bandwidth);
1489 return -EINVAL;
1490 }
1491
1492 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1493 }
1494
1495 } else if (streq(field, "BlockIODeviceWeight")) {
1496
1497 if (isempty(eq))
1498 r = sd_bus_message_append(m, "v", "a(st)", 0);
1499 else {
1500 const char *path, *weight, *e;
1501 uint64_t u;
1502
1503 e = strchr(eq, ' ');
1504 if (e) {
1505 path = strndupa(eq, e - eq);
1506 weight = e+1;
1507 } else {
1508 log_error("Failed to parse %s value %s.", field, eq);
1509 return -EINVAL;
1510 }
1511
1512 if (!path_startswith(path, "/dev")) {
1513 log_error("%s is not a device file in /dev.", path);
1514 return -EINVAL;
1515 }
1516
1517 r = safe_atou64(weight, &u);
1518 if (r < 0) {
1519 log_error("Failed to parse %s value %s.", field, weight);
1520 return -EINVAL;
1521 }
1522 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1523 }
1524
d584f638
LP
1525 } else if (rlimit_from_string(field) >= 0) {
1526 uint64_t rl;
1527
1528 if (streq(eq, "infinity"))
1529 rl = (uint64_t) -1;
1530 else {
1531 r = safe_atou64(eq, &rl);
1532 if (r < 0) {
1533 log_error("Invalid resource limit: %s", eq);
1534 return -EINVAL;
1535 }
1536 }
1537
1538 r = sd_bus_message_append(m, "v", "t", rl);
1539
e567439e
LP
1540 } else if (streq(field, "Nice")) {
1541 int32_t i;
1542
1543 r = safe_atoi32(eq, &i);
1544 if (r < 0) {
1545 log_error("Failed to parse %s value %s.", field, eq);
1546 return -EINVAL;
1547 }
1548
1549 r = sd_bus_message_append(m, "v", "i", i);
1550
1551 } else if (streq(field, "Environment")) {
1552
1553 r = sd_bus_message_append(m, "v", "as", 1, eq);
1554
1555 } else if (streq(field, "KillSignal")) {
1556 int sig;
1557
1558 sig = signal_from_string_try_harder(eq);
1559 if (sig < 0) {
1560 log_error("Failed to parse %s value %s.", field, eq);
1561 return -EINVAL;
1562 }
1563
1564 r = sd_bus_message_append(m, "v", "i", sig);
1565
4c213d6c
WC
1566 } else if (streq(field, "AccuracySec")) {
1567 usec_t u;
1568
1569 r = parse_sec(eq, &u);
1570 if (r < 0) {
1571 log_error("Failed to parse %s value %s", field, eq);
1572 return -EINVAL;
1573 }
1574
1575 r = sd_bus_message_append(m, "v", "t", u);
1576
df31a6c0
LP
1577 } else {
1578 log_error("Unknown assignment %s.", assignment);
1579 return -EINVAL;
1580 }
1581
1582 if (r < 0)
1583 return bus_log_create_error(r);
1584
1585 return 0;
1586}
ebd011d9
LP
1587
1588typedef struct BusWaitForJobs {
1589 sd_bus *bus;
1590 Set *jobs;
1591
1592 char *name;
1593 char *result;
1594
1595 sd_bus_slot *slot_job_removed;
1596 sd_bus_slot *slot_disconnected;
1597} BusWaitForJobs;
1598
1599static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1600 assert(bus);
1601 assert(m);
1602
1603 log_error("Warning! D-Bus connection terminated.");
1604 sd_bus_close(bus);
1605
1606 return 0;
1607}
1608
1609static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1610 const char *path, *unit, *result;
1611 BusWaitForJobs *d = userdata;
1612 uint32_t id;
1613 char *found;
1614 int r;
1615
1616 assert(bus);
1617 assert(m);
1618 assert(d);
1619
1620 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1621 if (r < 0) {
1622 bus_log_parse_error(r);
1623 return 0;
1624 }
1625
1626 found = set_remove(d->jobs, (char*) path);
1627 if (!found)
1628 return 0;
1629
1630 free(found);
1631
1632 if (!isempty(result))
1633 d->result = strdup(result);
1634
1635 if (!isempty(unit))
1636 d->name = strdup(unit);
1637
1638 return 0;
1639}
1640
1641void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1642 if (!d)
1643 return;
1644
1645 set_free_free(d->jobs);
1646
1647 sd_bus_slot_unref(d->slot_disconnected);
1648 sd_bus_slot_unref(d->slot_job_removed);
1649
1650 sd_bus_unref(d->bus);
1651
1652 free(d->name);
1653 free(d->result);
1654
1655 free(d);
1656}
1657
1658int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1659 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1660 int r;
1661
1662 assert(bus);
1663 assert(ret);
1664
1665 d = new0(BusWaitForJobs, 1);
1666 if (!d)
1667 return -ENOMEM;
1668
1669 d->bus = sd_bus_ref(bus);
1670
b798e7ba
LP
1671 /* When we are a bus client we match by sender. Direct
1672 * connections OTOH have no initialized sender field, and
1673 * hence we ignore the sender then */
ebd011d9
LP
1674 r = sd_bus_add_match(
1675 bus,
1676 &d->slot_job_removed,
b798e7ba 1677 bus->bus_client ?
ebd011d9
LP
1678 "type='signal',"
1679 "sender='org.freedesktop.systemd1',"
1680 "interface='org.freedesktop.systemd1.Manager',"
1681 "member='JobRemoved',"
b798e7ba
LP
1682 "path='/org/freedesktop/systemd1'" :
1683 "type='signal',"
1684 "interface='org.freedesktop.systemd1.Manager',"
1685 "member='JobRemoved',"
ebd011d9
LP
1686 "path='/org/freedesktop/systemd1'",
1687 match_job_removed, d);
1688 if (r < 0)
1689 return r;
1690
1691 r = sd_bus_add_match(
1692 bus,
1693 &d->slot_disconnected,
1694 "type='signal',"
1695 "sender='org.freedesktop.DBus.Local',"
1696 "interface='org.freedesktop.DBus.Local',"
1697 "member='Disconnected'",
1698 match_disconnected, d);
1699 if (r < 0)
1700 return r;
1701
1702 *ret = d;
1703 d = NULL;
1704
1705 return 0;
1706}
1707
1708static int bus_process_wait(sd_bus *bus) {
1709 int r;
1710
1711 for (;;) {
1712 r = sd_bus_process(bus, NULL);
1713 if (r < 0)
1714 return r;
1715 if (r > 0)
1716 return 0;
1717
1718 r = sd_bus_wait(bus, (uint64_t) -1);
1719 if (r < 0)
1720 return r;
1721 }
1722}
1723
1724static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1725 int r = 0;
1726
1727 assert(d->result);
1728
1729 if (!quiet) {
1730 if (streq(d->result, "canceled"))
1731 log_error("Job for %s canceled.", strna(d->name));
1732 else if (streq(d->result, "timeout"))
1733 log_error("Job for %s timed out.", strna(d->name));
1734 else if (streq(d->result, "dependency"))
1735 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1736 else if (streq(d->result, "invalid"))
1737 log_error("Job for %s invalid.", strna(d->name));
1738 else if (streq(d->result, "assert"))
1739 log_error("Assertion failed on job for %s.", strna(d->name));
1740 else if (streq(d->result, "unsupported"))
1741 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1742 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
1743 if (d->name) {
1744 bool quotes;
1745
1746 quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
1747
1748 log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
1749 d->name,
1750 quotes ? "'" : "", d->name, quotes ? "'" : "");
1751 } else
1752 log_error("Job failed. See \"journalctl -xe\" for details.");
1753 }
1754 }
1755
1756 if (streq(d->result, "canceled"))
1757 r = -ECANCELED;
1758 else if (streq(d->result, "timeout"))
1759 r = -ETIME;
1760 else if (streq(d->result, "dependency"))
1761 r = -EIO;
1762 else if (streq(d->result, "invalid"))
1763 r = -ENOEXEC;
1764 else if (streq(d->result, "assert"))
1765 r = -EPROTO;
1766 else if (streq(d->result, "unsupported"))
15411c0c 1767 r = -EOPNOTSUPP;
ebd011d9
LP
1768 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1769 r = -EIO;
1770
1771 return r;
1772}
1773
1774int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1775 int r = 0;
1776
1777 assert(d);
1778
1779 while (!set_isempty(d->jobs)) {
1780 int q;
1781
1782 q = bus_process_wait(d->bus);
1783 if (q < 0)
1784 return log_error_errno(q, "Failed to wait for response: %m");
1785
1786 if (d->result) {
1787 q = check_wait_response(d, quiet);
1788 /* Return the first error as it is most likely to be
1789 * meaningful. */
1790 if (q < 0 && r == 0)
1791 r = q;
1792
1793 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1794 }
1795
1796 free(d->name);
1797 d->name = NULL;
1798
1799 free(d->result);
1800 d->result = NULL;
1801 }
1802
1803 return r;
1804}
1805
1806int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1807 int r;
1808
1809 assert(d);
1810
1811 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1812 if (r < 0)
1813 return r;
1814
1815 return set_put_strdup(d->jobs, path);
1816}
d8f52ed2
LP
1817
1818int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
1819 const char *type, *path, *source;
1820 int r;
1821
1822 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1823 if (r < 0)
1824 return bus_log_parse_error(r);
1825
1826 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1827 if (!quiet) {
1828 if (streq(type, "symlink"))
1829 log_info("Created symlink from %s to %s.", path, source);
1830 else
1831 log_info("Removed symlink %s.", path);
1832 }
1833 }
1834 if (r < 0)
1835 return bus_log_parse_error(r);
1836
1837 r = sd_bus_message_exit_container(m);
1838 if (r < 0)
1839 return bus_log_parse_error(r);
1840
1841 return 0;
1842}