]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-util.c
man: clarify that only the first .network file with a matching [Match] matters
[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"
d5cad221 33#include "unit-name.h"
40ca29a1 34
ffc06c35
KS
35#include "sd-bus.h"
36#include "bus-error.h"
98a4c30b 37#include "bus-label.h"
ffc06c35 38#include "bus-message.h"
40ca29a1 39#include "bus-util.h"
ebcf1f97 40#include "bus-internal.h"
40ca29a1 41
6203e07a 42static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40ca29a1
LP
43 sd_event *e = userdata;
44
45 assert(bus);
46 assert(m);
47 assert(e);
48
b27adf35 49 sd_bus_close(bus);
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
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
d7161865
DM
725 case SD_BUS_TYPE_INT64: {
726 int64_t i;
727
728 r = sd_bus_message_read_basic(property, type, &i);
729 if (r < 0)
730 return r;
731
732 printf("%s=%lld\n", name, (long long) i);
733
734 return 1;
735 }
736
a1da8583
TG
737 case SD_BUS_TYPE_UINT32: {
738 uint32_t u;
739
9f6eb1cd
KS
740 r = sd_bus_message_read_basic(property, type, &u);
741 if (r < 0)
742 return r;
a1da8583
TG
743
744 if (strstr(name, "UMask") || strstr(name, "Mode"))
745 printf("%s=%04o\n", name, u);
746 else
747 printf("%s=%u\n", name, (unsigned) u);
748
749 return 1;
750 }
751
752 case SD_BUS_TYPE_INT32: {
753 int32_t i;
754
9f6eb1cd
KS
755 r = sd_bus_message_read_basic(property, type, &i);
756 if (r < 0)
757 return r;
a1da8583
TG
758
759 printf("%s=%i\n", name, (int) i);
760 return 1;
761 }
762
763 case SD_BUS_TYPE_DOUBLE: {
764 double d;
765
9f6eb1cd
KS
766 r = sd_bus_message_read_basic(property, type, &d);
767 if (r < 0)
768 return r;
a1da8583
TG
769
770 printf("%s=%g\n", name, d);
771 return 1;
772 }
773
774 case SD_BUS_TYPE_ARRAY:
a1da8583 775 if (streq(contents, "s")) {
261afec5
MAP
776 bool first = true;
777 const char *str;
a1da8583 778
9f6eb1cd
KS
779 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
780 if (r < 0)
781 return r;
782
261afec5 783 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
27e9c5af
LP
784 _cleanup_free_ char *escaped = NULL;
785
261afec5
MAP
786 if (first)
787 printf("%s=", name);
788
27e9c5af
LP
789 escaped = xescape(str, "\n ");
790 if (!escaped)
791 return -ENOMEM;
792
793 printf("%s%s", first ? "" : " ", escaped);
261afec5
MAP
794
795 first = false;
796 }
9f6eb1cd
KS
797 if (r < 0)
798 return r;
a1da8583 799
261afec5 800 if (first && all)
a1da8583 801 printf("%s=", name);
261afec5 802 if (!first || all)
a1da8583 803 puts("");
a1da8583 804
9f6eb1cd
KS
805 r = sd_bus_message_exit_container(property);
806 if (r < 0)
807 return r;
a1da8583
TG
808
809 return 1;
810
811 } else if (streq(contents, "y")) {
812 const uint8_t *u;
813 size_t n;
814
9f6eb1cd
KS
815 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
816 if (r < 0)
817 return r;
818
a1da8583
TG
819 if (all || n > 0) {
820 unsigned int i;
821
822 printf("%s=", name);
823
824 for (i = 0; i < n; i++)
825 printf("%02x", u[i]);
826
827 puts("");
828 }
829
830 return 1;
831
832 } else if (streq(contents, "u")) {
833 uint32_t *u;
834 size_t n;
835
9f6eb1cd
KS
836 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
837 if (r < 0)
838 return r;
839
a1da8583
TG
840 if (all || n > 0) {
841 unsigned int i;
842
843 printf("%s=", name);
844
845 for (i = 0; i < n; i++)
846 printf("%08x", u[i]);
847
848 puts("");
849 }
850
851 return 1;
852 }
853
854 break;
855 }
856
857 return 0;
858}
d21ed1ea 859
27e72d6b 860int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 861 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
862 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
863 int r;
864
9f6eb1cd
KS
865 assert(bus);
866 assert(path);
867
868 r = sd_bus_call_method(bus,
27e72d6b 869 dest,
ffc06c35
KS
870 path,
871 "org.freedesktop.DBus.Properties",
872 "GetAll",
873 &error,
9f6eb1cd 874 &reply,
ffc06c35 875 "s", "");
9f6eb1cd 876 if (r < 0)
ffc06c35 877 return r;
ffc06c35 878
9f6eb1cd 879 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
880 if (r < 0)
881 return r;
882
9f6eb1cd 883 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 884 const char *name;
ffc06c35 885 const char *contents;
ffc06c35 886
9f6eb1cd 887 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
888 if (r < 0)
889 return r;
890
9f6eb1cd
KS
891 if (!filter || strv_find(filter, name)) {
892 r = sd_bus_message_peek_type(reply, NULL, &contents);
893 if (r < 0)
894 return r;
895
896 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
897 if (r < 0)
898 return r;
ffc06c35 899
9f6eb1cd
KS
900 r = bus_print_property(name, reply, all);
901 if (r < 0)
902 return r;
27e72d6b
SP
903 if (r == 0) {
904 if (all)
905 printf("%s=[unprintable]\n", name);
906 /* skip what we didn't read */
907 r = sd_bus_message_skip(reply, contents);
908 if (r < 0)
909 return r;
910 }
9f6eb1cd
KS
911
912 r = sd_bus_message_exit_container(reply);
913 if (r < 0)
914 return r;
915 } else {
916 r = sd_bus_message_skip(reply, "v");
917 if (r < 0)
918 return r;
919 }
920
921 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
922 if (r < 0)
923 return r;
9f6eb1cd
KS
924 }
925 if (r < 0)
926 return r;
ffc06c35 927
9f6eb1cd
KS
928 r = sd_bus_message_exit_container(reply);
929 if (r < 0)
930 return r;
ffc06c35 931
9f6eb1cd
KS
932 return 0;
933}
ffc06c35 934
9f6eb1cd
KS
935int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
936 sd_id128_t *p = userdata;
937 const void *v;
938 size_t n;
939 int r;
ffc06c35 940
9f6eb1cd
KS
941 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
942 if (r < 0)
943 return r;
ffc06c35 944
9f6eb1cd
KS
945 if (n == 0)
946 *p = SD_ID128_NULL;
947 else if (n == 16)
948 memcpy((*p).bytes, v, n);
949 else
950 return -EINVAL;
ffc06c35 951
9f6eb1cd
KS
952 return 0;
953}
ffc06c35 954
9f6eb1cd
KS
955static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
956 char type;
957 int r;
ffc06c35 958
9f6eb1cd
KS
959 r = sd_bus_message_peek_type(m, &type, NULL);
960 if (r < 0)
961 return r;
ffc06c35 962
9f6eb1cd
KS
963 switch (type) {
964 case SD_BUS_TYPE_STRING: {
965 const char *s;
9f6eb1cd 966 char **p = userdata;
ffc06c35 967
9f6eb1cd
KS
968 r = sd_bus_message_read_basic(m, type, &s);
969 if (r < 0)
970 break;
ffc06c35 971
9f6eb1cd
KS
972 if (isempty(s))
973 break;
ffc06c35 974
0704ea57 975 r = free_and_strdup(p, s);
9f6eb1cd
KS
976 break;
977 }
ffc06c35 978
9f6eb1cd
KS
979 case SD_BUS_TYPE_ARRAY: {
980 _cleanup_strv_free_ char **l = NULL;
981 char ***p = userdata;
ffc06c35 982
9f6eb1cd
KS
983 r = bus_message_read_strv_extend(m, &l);
984 if (r < 0)
985 break;
ffc06c35 986
9f6eb1cd
KS
987 strv_free(*p);
988 *p = l;
989 l = NULL;
ffc06c35 990
9f6eb1cd
KS
991 break;
992 }
ffc06c35 993
9f6eb1cd
KS
994 case SD_BUS_TYPE_BOOLEAN: {
995 unsigned b;
996 bool *p = userdata;
ffc06c35 997
9f6eb1cd
KS
998 r = sd_bus_message_read_basic(m, type, &b);
999 if (r < 0)
1000 break;
ffc06c35 1001
9f6eb1cd 1002 *p = b;
ffc06c35 1003
9f6eb1cd
KS
1004 break;
1005 }
ffc06c35 1006
9f6eb1cd
KS
1007 case SD_BUS_TYPE_UINT32: {
1008 uint64_t u;
1009 uint32_t *p = userdata;
1010
1011 r = sd_bus_message_read_basic(m, type, &u);
1012 if (r < 0)
ffc06c35 1013 break;
ffc06c35 1014
9f6eb1cd
KS
1015 *p = u;
1016
1017 break;
1018 }
1019
1020 case SD_BUS_TYPE_UINT64: {
1021 uint64_t t;
1022 uint64_t *p = userdata;
1023
1024 r = sd_bus_message_read_basic(m, type, &t);
1025 if (r < 0)
ffc06c35 1026 break;
ffc06c35 1027
9f6eb1cd
KS
1028 *p = t;
1029
1030 break;
1031 }
1032
1033 default:
1034 break;
1035 }
1036
1037 return r;
1038}
1039
aae2b488
DH
1040int bus_message_map_all_properties(sd_bus *bus,
1041 sd_bus_message *m,
1042 const struct bus_properties_map *map,
1043 void *userdata) {
9f6eb1cd
KS
1044 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1045 int r;
1046
1047 assert(bus);
aae2b488 1048 assert(m);
9f6eb1cd
KS
1049 assert(map);
1050
9f6eb1cd
KS
1051 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1052 if (r < 0)
1053 return r;
1054
1055 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1056 const struct bus_properties_map *prop;
1057 const char *member;
1058 const char *contents;
1059 void *v;
1060 unsigned i;
1061
1062 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
1063 if (r < 0)
1064 return r;
1065
9f6eb1cd
KS
1066 for (i = 0, prop = NULL; map[i].member; i++)
1067 if (streq(map[i].member, member)) {
1068 prop = &map[i];
1069 break;
1070 }
1071
1072 if (prop) {
1073 r = sd_bus_message_peek_type(m, NULL, &contents);
1074 if (r < 0)
1075 return r;
1076
1077 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1078 if (r < 0)
1079 return r;
1080
1081 v = (uint8_t *)userdata + prop->offset;
27e72d6b 1082 if (map[i].set)
9f6eb1cd
KS
1083 r = prop->set(bus, member, m, &error, v);
1084 else
1085 r = map_basic(bus, member, m, &error, v);
2b49a470
TA
1086 if (r < 0)
1087 return r;
9f6eb1cd
KS
1088
1089 r = sd_bus_message_exit_container(m);
1090 if (r < 0)
1091 return r;
1092 } else {
1093 r = sd_bus_message_skip(m, "v");
1094 if (r < 0)
6c1508b8 1095 return r;
9f6eb1cd
KS
1096 }
1097
ffc06c35
KS
1098 r = sd_bus_message_exit_container(m);
1099 if (r < 0)
1100 return r;
1101 }
1102
aae2b488
DH
1103 return sd_bus_message_exit_container(m);
1104}
1105
1106int bus_message_map_properties_changed(sd_bus *bus,
1107 sd_bus_message *m,
1108 const struct bus_properties_map *map,
1109 void *userdata) {
1110 const char *member;
1111 int r, invalidated, i;
1112
1113 assert(bus);
1114 assert(m);
1115 assert(map);
1116
aae2b488
DH
1117 r = bus_message_map_all_properties(bus, m, map, userdata);
1118 if (r < 0)
1119 return r;
1120
1121 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1122 if (r < 0)
1123 return r;
1124
1125 invalidated = 0;
1126 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1127 for (i = 0; map[i].member; i++)
1128 if (streq(map[i].member, member)) {
1129 ++invalidated;
1130 break;
1131 }
1132
1133 r = sd_bus_message_exit_container(m);
1134 if (r < 0)
1135 return r;
1136
1137 return invalidated;
1138}
1139
1140int bus_map_all_properties(sd_bus *bus,
1141 const char *destination,
1142 const char *path,
1143 const struct bus_properties_map *map,
1144 void *userdata) {
1145 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1146 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1147 int r;
1148
1149 assert(bus);
1150 assert(destination);
1151 assert(path);
1152 assert(map);
1153
1154 r = sd_bus_call_method(
1155 bus,
1156 destination,
1157 path,
1158 "org.freedesktop.DBus.Properties",
1159 "GetAll",
1160 &error,
1161 &m,
1162 "s", "");
1163 if (r < 0)
1164 return r;
1165
1166 return bus_message_map_all_properties(bus, m, map, userdata);
ffc06c35
KS
1167}
1168
d21ed1ea
LP
1169int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1170 int r;
1171
1172 assert(transport >= 0);
1173 assert(transport < _BUS_TRANSPORT_MAX);
1174 assert(bus);
1175
1176 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1177 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
d21ed1ea
LP
1178
1179 switch (transport) {
1180
1181 case BUS_TRANSPORT_LOCAL:
1182 if (user)
76b54375 1183 r = sd_bus_default_user(bus);
d21ed1ea 1184 else
76b54375 1185 r = sd_bus_default_system(bus);
d21ed1ea
LP
1186
1187 break;
1188
1189 case BUS_TRANSPORT_REMOTE:
3db729cb 1190 r = sd_bus_open_system_remote(bus, host);
41dd15e4
LP
1191 break;
1192
de33fc62
LP
1193 case BUS_TRANSPORT_MACHINE:
1194 r = sd_bus_open_system_machine(bus, host);
41dd15e4
LP
1195 break;
1196
1197 default:
1198 assert_not_reached("Hmm, unknown transport type.");
1199 }
1200
1201 return r;
1202}
1203
1204int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1205 int r;
1206
1207 assert(transport >= 0);
1208 assert(transport < _BUS_TRANSPORT_MAX);
1209 assert(bus);
1210
1211 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1212 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
41dd15e4
LP
1213
1214 switch (transport) {
1215
1216 case BUS_TRANSPORT_LOCAL:
1217 if (user)
1218 r = bus_open_user_systemd(bus);
1219 else
1220 r = bus_open_system_systemd(bus);
1221
1222 break;
1223
1224 case BUS_TRANSPORT_REMOTE:
3db729cb 1225 r = sd_bus_open_system_remote(bus, host);
d21ed1ea
LP
1226 break;
1227
de33fc62
LP
1228 case BUS_TRANSPORT_MACHINE:
1229 r = sd_bus_open_system_machine(bus, host);
d21ed1ea
LP
1230 break;
1231
1232 default:
1233 assert_not_reached("Hmm, unknown transport type.");
1234 }
1235
1236 return r;
1237}
e6504030
LP
1238
1239int bus_property_get_bool(
1240 sd_bus *bus,
1241 const char *path,
1242 const char *interface,
1243 const char *property,
1244 sd_bus_message *reply,
ebcf1f97
LP
1245 void *userdata,
1246 sd_bus_error *error) {
e6504030
LP
1247
1248 int b = *(bool*) userdata;
1249
1250 return sd_bus_message_append_basic(reply, 'b', &b);
1251}
1252
718db961
LP
1253#if __SIZEOF_SIZE_T__ != 8
1254int bus_property_get_size(
e6504030
LP
1255 sd_bus *bus,
1256 const char *path,
1257 const char *interface,
1258 const char *property,
1259 sd_bus_message *reply,
ebcf1f97
LP
1260 void *userdata,
1261 sd_bus_error *error) {
e6504030 1262
718db961 1263 uint64_t sz = *(size_t*) userdata;
e6504030 1264
718db961 1265 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1266}
718db961
LP
1267#endif
1268
1269#if __SIZEOF_LONG__ != 8
1270int bus_property_get_long(
1271 sd_bus *bus,
1272 const char *path,
1273 const char *interface,
1274 const char *property,
1275 sd_bus_message *reply,
ebcf1f97
LP
1276 void *userdata,
1277 sd_bus_error *error) {
718db961
LP
1278
1279 int64_t l = *(long*) userdata;
1280
1281 return sd_bus_message_append_basic(reply, 'x', &l);
1282}
1283
1284int bus_property_get_ulong(
1285 sd_bus *bus,
1286 const char *path,
1287 const char *interface,
1288 const char *property,
1289 sd_bus_message *reply,
ebcf1f97
LP
1290 void *userdata,
1291 sd_bus_error *error) {
718db961
LP
1292
1293 uint64_t ul = *(unsigned long*) userdata;
1294
1295 return sd_bus_message_append_basic(reply, 't', &ul);
1296}
1297#endif
5b30bef8
LP
1298
1299int bus_log_parse_error(int r) {
23bbb0de 1300 return log_error_errno(r, "Failed to parse bus message: %m");
5b30bef8 1301}
f459b602
MAP
1302
1303int bus_log_create_error(int r) {
23bbb0de 1304 return log_error_errno(r, "Failed to create bus message: %m");
f459b602
MAP
1305}
1306
1307int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1308 assert(message);
1309 assert(u);
1310
1238ee09
LP
1311 u->machine = NULL;
1312
f459b602
MAP
1313 return sd_bus_message_read(
1314 message,
1315 "(ssssssouso)",
1316 &u->id,
1317 &u->description,
1318 &u->load_state,
1319 &u->active_state,
1320 &u->sub_state,
1321 &u->following,
1322 &u->unit_path,
1323 &u->job_id,
1324 &u->job_type,
1325 &u->job_path);
1326}
ebcf1f97
LP
1327
1328int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1329 assert(m);
1330
1331 if (r < 0) {
1332 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1333 sd_bus_reply_method_errno(m, r, error);
1334
1335 } else if (sd_bus_error_is_set(error)) {
1336 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1337 sd_bus_reply_method_error(m, error);
ebcf1f97
LP
1338 } else
1339 return r;
1340
1341 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1342 bus_message_type_to_string(m->header->type),
1343 strna(m->sender),
1344 strna(m->path),
1345 strna(m->interface),
1346 strna(m->member),
1347 strna(m->root_container.signature),
1348 bus_error_message(error, r));
1349
1350 return 1;
1351}
df31a6c0
LP
1352
1353int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1354 const char *eq, *field;
1355 int r;
1356
1357 assert(m);
1358 assert(assignment);
1359
1360 eq = strchr(assignment, '=');
1361 if (!eq) {
1362 log_error("Not an assignment: %s", assignment);
1363 return -EINVAL;
1364 }
1365
1366 field = strndupa(assignment, eq - assignment);
1367 eq ++;
1368
b2f8b02e
LP
1369 if (streq(field, "CPUQuota")) {
1370
1371 if (isempty(eq)) {
1372
1373 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1374 if (r < 0)
1375 return bus_log_create_error(r);
1376
3a43da28 1377 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
b2f8b02e
LP
1378
1379 } else if (endswith(eq, "%")) {
1380 double percent;
1381
1382 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1383 log_error("CPU quota '%s' invalid.", eq);
1384 return -EINVAL;
1385 }
1386
1387 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1388 if (r < 0)
1389 return bus_log_create_error(r);
1390
1391 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1392 } else {
9a054909 1393 log_error("CPU quota needs to be in percent.");
b2f8b02e
LP
1394 return -EINVAL;
1395 }
1396
b2f8b02e
LP
1397 if (r < 0)
1398 return bus_log_create_error(r);
1399
1400 return 0;
1401 }
1402
df31a6c0
LP
1403 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1404 if (r < 0)
1405 return bus_log_create_error(r);
1406
e567439e
LP
1407 if (STR_IN_SET(field,
1408 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
261420ba 1409 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) {
df31a6c0
LP
1410
1411 r = parse_boolean(eq);
1412 if (r < 0) {
1413 log_error("Failed to parse boolean assignment %s.", assignment);
1414 return -EINVAL;
1415 }
1416
1417 r = sd_bus_message_append(m, "v", "b", r);
1418
1419 } else if (streq(field, "MemoryLimit")) {
1420 off_t bytes;
1421
1422 r = parse_size(eq, 1024, &bytes);
1423 if (r < 0) {
1424 log_error("Failed to parse bytes specification %s", assignment);
1425 return -EINVAL;
1426 }
1427
1428 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1429
1430 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1431 uint64_t u;
1432
1433 r = safe_atou64(eq, &u);
1434 if (r < 0) {
1435 log_error("Failed to parse %s value %s.", field, eq);
1436 return -EINVAL;
1437 }
1438
1439 r = sd_bus_message_append(m, "v", "t", u);
1440
e567439e 1441 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
df31a6c0
LP
1442 r = sd_bus_message_append(m, "v", "s", eq);
1443
1444 else if (streq(field, "DeviceAllow")) {
1445
1446 if (isempty(eq))
1447 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1448 else {
1449 const char *path, *rwm, *e;
1450
1451 e = strchr(eq, ' ');
1452 if (e) {
1453 path = strndupa(eq, e - eq);
1454 rwm = e+1;
1455 } else {
1456 path = eq;
1457 rwm = "";
1458 }
1459
1460 if (!path_startswith(path, "/dev")) {
1461 log_error("%s is not a device file in /dev.", path);
1462 return -EINVAL;
1463 }
1464
1465 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1466 }
1467
1468 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1469
1470 if (isempty(eq))
1471 r = sd_bus_message_append(m, "v", "a(st)", 0);
1472 else {
1473 const char *path, *bandwidth, *e;
1474 off_t bytes;
1475
1476 e = strchr(eq, ' ');
1477 if (e) {
1478 path = strndupa(eq, e - eq);
1479 bandwidth = e+1;
1480 } else {
1481 log_error("Failed to parse %s value %s.", field, eq);
1482 return -EINVAL;
1483 }
1484
1485 if (!path_startswith(path, "/dev")) {
1486 log_error("%s is not a device file in /dev.", path);
1487 return -EINVAL;
1488 }
1489
1490 r = parse_size(bandwidth, 1000, &bytes);
1491 if (r < 0) {
1492 log_error("Failed to parse byte value %s.", bandwidth);
1493 return -EINVAL;
1494 }
1495
1496 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1497 }
1498
1499 } else if (streq(field, "BlockIODeviceWeight")) {
1500
1501 if (isempty(eq))
1502 r = sd_bus_message_append(m, "v", "a(st)", 0);
1503 else {
1504 const char *path, *weight, *e;
1505 uint64_t u;
1506
1507 e = strchr(eq, ' ');
1508 if (e) {
1509 path = strndupa(eq, e - eq);
1510 weight = e+1;
1511 } else {
1512 log_error("Failed to parse %s value %s.", field, eq);
1513 return -EINVAL;
1514 }
1515
1516 if (!path_startswith(path, "/dev")) {
1517 log_error("%s is not a device file in /dev.", path);
1518 return -EINVAL;
1519 }
1520
1521 r = safe_atou64(weight, &u);
1522 if (r < 0) {
1523 log_error("Failed to parse %s value %s.", field, weight);
1524 return -EINVAL;
1525 }
1526 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1527 }
1528
d584f638
LP
1529 } else if (rlimit_from_string(field) >= 0) {
1530 uint64_t rl;
1531
1532 if (streq(eq, "infinity"))
1533 rl = (uint64_t) -1;
1534 else {
1535 r = safe_atou64(eq, &rl);
1536 if (r < 0) {
1537 log_error("Invalid resource limit: %s", eq);
1538 return -EINVAL;
1539 }
1540 }
1541
1542 r = sd_bus_message_append(m, "v", "t", rl);
1543
e567439e
LP
1544 } else if (streq(field, "Nice")) {
1545 int32_t i;
1546
1547 r = safe_atoi32(eq, &i);
1548 if (r < 0) {
1549 log_error("Failed to parse %s value %s.", field, eq);
1550 return -EINVAL;
1551 }
1552
1553 r = sd_bus_message_append(m, "v", "i", i);
1554
1555 } else if (streq(field, "Environment")) {
1556
1557 r = sd_bus_message_append(m, "v", "as", 1, eq);
1558
1559 } else if (streq(field, "KillSignal")) {
1560 int sig;
1561
1562 sig = signal_from_string_try_harder(eq);
1563 if (sig < 0) {
1564 log_error("Failed to parse %s value %s.", field, eq);
1565 return -EINVAL;
1566 }
1567
1568 r = sd_bus_message_append(m, "v", "i", sig);
1569
4c213d6c
WC
1570 } else if (streq(field, "AccuracySec")) {
1571 usec_t u;
1572
1573 r = parse_sec(eq, &u);
1574 if (r < 0) {
1575 log_error("Failed to parse %s value %s", field, eq);
1576 return -EINVAL;
1577 }
1578
1579 r = sd_bus_message_append(m, "v", "t", u);
1580
df31a6c0
LP
1581 } else {
1582 log_error("Unknown assignment %s.", assignment);
1583 return -EINVAL;
1584 }
1585
1586 if (r < 0)
1587 return bus_log_create_error(r);
1588
1589 return 0;
1590}
ebd011d9
LP
1591
1592typedef struct BusWaitForJobs {
1593 sd_bus *bus;
1594 Set *jobs;
1595
1596 char *name;
1597 char *result;
1598
1599 sd_bus_slot *slot_job_removed;
1600 sd_bus_slot *slot_disconnected;
1601} BusWaitForJobs;
1602
1603static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1604 assert(bus);
1605 assert(m);
1606
1607 log_error("Warning! D-Bus connection terminated.");
1608 sd_bus_close(bus);
1609
1610 return 0;
1611}
1612
1613static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1614 const char *path, *unit, *result;
1615 BusWaitForJobs *d = userdata;
1616 uint32_t id;
1617 char *found;
1618 int r;
1619
1620 assert(bus);
1621 assert(m);
1622 assert(d);
1623
1624 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1625 if (r < 0) {
1626 bus_log_parse_error(r);
1627 return 0;
1628 }
1629
1630 found = set_remove(d->jobs, (char*) path);
1631 if (!found)
1632 return 0;
1633
1634 free(found);
1635
1636 if (!isempty(result))
1637 d->result = strdup(result);
1638
1639 if (!isempty(unit))
1640 d->name = strdup(unit);
1641
1642 return 0;
1643}
1644
1645void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1646 if (!d)
1647 return;
1648
1649 set_free_free(d->jobs);
1650
1651 sd_bus_slot_unref(d->slot_disconnected);
1652 sd_bus_slot_unref(d->slot_job_removed);
1653
1654 sd_bus_unref(d->bus);
1655
1656 free(d->name);
1657 free(d->result);
1658
1659 free(d);
1660}
1661
1662int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1663 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1664 int r;
1665
1666 assert(bus);
1667 assert(ret);
1668
1669 d = new0(BusWaitForJobs, 1);
1670 if (!d)
1671 return -ENOMEM;
1672
1673 d->bus = sd_bus_ref(bus);
1674
b798e7ba
LP
1675 /* When we are a bus client we match by sender. Direct
1676 * connections OTOH have no initialized sender field, and
1677 * hence we ignore the sender then */
ebd011d9
LP
1678 r = sd_bus_add_match(
1679 bus,
1680 &d->slot_job_removed,
b798e7ba 1681 bus->bus_client ?
ebd011d9
LP
1682 "type='signal',"
1683 "sender='org.freedesktop.systemd1',"
1684 "interface='org.freedesktop.systemd1.Manager',"
1685 "member='JobRemoved',"
b798e7ba
LP
1686 "path='/org/freedesktop/systemd1'" :
1687 "type='signal',"
1688 "interface='org.freedesktop.systemd1.Manager',"
1689 "member='JobRemoved',"
ebd011d9
LP
1690 "path='/org/freedesktop/systemd1'",
1691 match_job_removed, d);
1692 if (r < 0)
1693 return r;
1694
1695 r = sd_bus_add_match(
1696 bus,
1697 &d->slot_disconnected,
1698 "type='signal',"
1699 "sender='org.freedesktop.DBus.Local',"
1700 "interface='org.freedesktop.DBus.Local',"
1701 "member='Disconnected'",
1702 match_disconnected, d);
1703 if (r < 0)
1704 return r;
1705
1706 *ret = d;
1707 d = NULL;
1708
1709 return 0;
1710}
1711
1712static int bus_process_wait(sd_bus *bus) {
1713 int r;
1714
1715 for (;;) {
1716 r = sd_bus_process(bus, NULL);
1717 if (r < 0)
1718 return r;
1719 if (r > 0)
1720 return 0;
1721
1722 r = sd_bus_wait(bus, (uint64_t) -1);
1723 if (r < 0)
1724 return r;
1725 }
1726}
1727
d5cad221
MS
1728static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
1729 _cleanup_free_ char *dbus_path = NULL;
1730
1731 assert(d);
1732 assert(d->name);
1733 assert(result);
1734
1735 dbus_path = unit_dbus_path_from_name(d->name);
1736 if (!dbus_path)
1737 return -ENOMEM;
1738
1739 return sd_bus_get_property_string(d->bus,
1740 "org.freedesktop.systemd1",
1741 dbus_path,
1742 "org.freedesktop.systemd1.Service",
1743 "Result",
1744 NULL,
1745 result);
1746}
1747
1748static const struct {
1749 const char *result, *explanation;
1750} explanations [] = {
a61cc460
ZJS
1751 { "resources", "a configured resource limit was exceeded" },
1752 { "timeout", "a timeout was exceeded" },
1753 { "exit-code", "the control process exited with error code" },
1754 { "signal", "a fatal signal was delivered to the control process" },
1755 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1756 { "watchdog", "the service failed to send watchdog ping" },
1757 { "start-limit", "start of the service was attempted too often" }
d5cad221
MS
1758};
1759
1760static void log_job_error_with_service_result(const char* service, const char *result) {
1761 unsigned i;
1762 _cleanup_free_ char *service_shell_quoted = NULL;
1763
1764 assert(service);
1765 assert(result);
1766
1767 service_shell_quoted = shell_maybe_quote(service);
1768
1769 for (i = 0; i < ELEMENTSOF(explanations); ++i)
1770 if (streq(result, explanations[i].result))
1771 break;
1772
1773 if (i < ELEMENTSOF(explanations))
1774 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1775 service,
1776 explanations[i].explanation,
1777 strna(service_shell_quoted));
1778 else
1779 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1780 service,
1781 strna(service_shell_quoted));
1782
1783 /* For some results maybe additional explanation is required */
1784 if (streq_ptr(result, "start-limit"))
a61cc460 1785 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
d5cad221
MS
1786 strna(service_shell_quoted));
1787}
1788
ebd011d9
LP
1789static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1790 int r = 0;
1791
1792 assert(d->result);
1793
1794 if (!quiet) {
1795 if (streq(d->result, "canceled"))
1796 log_error("Job for %s canceled.", strna(d->name));
1797 else if (streq(d->result, "timeout"))
1798 log_error("Job for %s timed out.", strna(d->name));
1799 else if (streq(d->result, "dependency"))
1800 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1801 else if (streq(d->result, "invalid"))
1802 log_error("Job for %s invalid.", strna(d->name));
1803 else if (streq(d->result, "assert"))
1804 log_error("Assertion failed on job for %s.", strna(d->name));
1805 else if (streq(d->result, "unsupported"))
1806 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1807 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
d5cad221
MS
1808 if (d->name) {
1809 int q;
1810 _cleanup_free_ char *result = NULL;
ebd011d9 1811
d5cad221
MS
1812 q = bus_job_get_service_result(d, &result);
1813 if (q < 0)
1814 log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
ebd011d9 1815
d5cad221
MS
1816 log_job_error_with_service_result(d->name, result);
1817 } else
1818 log_error("Job failed. See \"journalctl -xe\" for details.");
ebd011d9
LP
1819 }
1820 }
1821
1822 if (streq(d->result, "canceled"))
1823 r = -ECANCELED;
1824 else if (streq(d->result, "timeout"))
1825 r = -ETIME;
1826 else if (streq(d->result, "dependency"))
1827 r = -EIO;
1828 else if (streq(d->result, "invalid"))
1829 r = -ENOEXEC;
1830 else if (streq(d->result, "assert"))
1831 r = -EPROTO;
1832 else if (streq(d->result, "unsupported"))
15411c0c 1833 r = -EOPNOTSUPP;
ebd011d9
LP
1834 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1835 r = -EIO;
1836
1837 return r;
1838}
1839
1840int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1841 int r = 0;
1842
1843 assert(d);
1844
1845 while (!set_isempty(d->jobs)) {
1846 int q;
1847
1848 q = bus_process_wait(d->bus);
1849 if (q < 0)
1850 return log_error_errno(q, "Failed to wait for response: %m");
1851
1852 if (d->result) {
1853 q = check_wait_response(d, quiet);
1854 /* Return the first error as it is most likely to be
1855 * meaningful. */
1856 if (q < 0 && r == 0)
1857 r = q;
1858
1859 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1860 }
1861
1862 free(d->name);
1863 d->name = NULL;
1864
1865 free(d->result);
1866 d->result = NULL;
1867 }
1868
1869 return r;
1870}
1871
1872int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1873 int r;
1874
1875 assert(d);
1876
1877 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1878 if (r < 0)
1879 return r;
1880
1881 return set_put_strdup(d->jobs, path);
1882}
d8f52ed2
LP
1883
1884int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
1885 const char *type, *path, *source;
1886 int r;
1887
1888 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1889 if (r < 0)
1890 return bus_log_parse_error(r);
1891
1892 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1893 if (!quiet) {
1894 if (streq(type, "symlink"))
1895 log_info("Created symlink from %s to %s.", path, source);
1896 else
1897 log_info("Removed symlink %s.", path);
1898 }
1899 }
1900 if (r < 0)
1901 return bus_log_parse_error(r);
1902
1903 r = sd_bus_message_exit_container(m);
1904 if (r < 0)
1905 return bus_log_parse_error(r);
1906
1907 return 0;
1908}
98a4c30b
DH
1909
1910/**
1911 * bus_path_encode_unique() - encode unique object path
1912 * @b: bus connection or NULL
1913 * @prefix: object path prefix
1914 * @sender_id: unique-name of client, or NULL
1915 * @external_id: external ID to be chosen by client, or NULL
1916 * @ret_path: storage for encoded object path pointer
1917 *
1918 * Whenever we provide a bus API that allows clients to create and manage
1919 * server-side objects, we need to provide a unique name for these objects. If
1920 * we let the server choose the name, we suffer from a race condition: If a
1921 * client creates an object asynchronously, it cannot destroy that object until
1922 * it received the method reply. It cannot know the name of the new object,
1923 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1924 *
1925 * Therefore, many APIs allow the client to choose the unique name for newly
1926 * created objects. There're two problems to solve, though:
1927 * 1) Object names are usually defined via dbus object paths, which are
1928 * usually globally namespaced. Therefore, multiple clients must be able
1929 * to choose unique object names without interference.
1930 * 2) If multiple libraries share the same bus connection, they must be
1931 * able to choose unique object names without interference.
1932 * The first problem is solved easily by prefixing a name with the
1933 * unique-bus-name of a connection. The server side must enforce this and
1934 * reject any other name. The second problem is solved by providing unique
1935 * suffixes from within sd-bus.
1936 *
1937 * This helper allows clients to create unique object-paths. It uses the
1938 * template '/prefix/sender_id/external_id' and returns the new path in
1939 * @ret_path (must be freed by the caller).
1940 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1941 * NULL, this function allocates a unique suffix via @b (by requesting a new
1942 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1943 * NULL.
1944 *
1945 * Returns: 0 on success, negative error code on failure.
1946 */
1947int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1948 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1949 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1950 int r;
1951
1952 assert_return(b || (sender_id && external_id), -EINVAL);
1953 assert_return(object_path_is_valid(prefix), -EINVAL);
1954 assert_return(ret_path, -EINVAL);
1955
1956 if (!sender_id) {
1957 r = sd_bus_get_unique_name(b, &sender_id);
1958 if (r < 0)
1959 return r;
1960 }
1961
1962 if (!external_id) {
1963 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1964 external_id = external_buf;
1965 }
1966
1967 sender_label = bus_label_escape(sender_id);
1968 if (!sender_label)
1969 return -ENOMEM;
1970
1971 external_label = bus_label_escape(external_id);
1972 if (!external_label)
1973 return -ENOMEM;
1974
1975 p = strjoin(prefix, "/", sender_label, "/", external_label, NULL);
1976 if (!p)
1977 return -ENOMEM;
1978
1979 *ret_path = p;
1980 return 0;
1981}
1982
1983/**
1984 * bus_path_decode_unique() - decode unique object path
1985 * @path: object path to decode
1986 * @prefix: object path prefix
1987 * @ret_sender: output parameter for sender-id label
1988 * @ret_external: output parameter for external-id label
1989 *
1990 * This does the reverse of bus_path_encode_unique() (see its description for
1991 * details). Both trailing labels, sender-id and external-id, are unescaped and
1992 * returned in the given output parameters (the caller must free them).
1993 *
1994 * Note that this function returns 0 if the path does not match the template
1995 * (see bus_path_encode_unique()), 1 if it matched.
1996 *
1997 * Returns: Negative error code on failure, 0 if the given object path does not
1998 * match the template (return parameters are set to NULL), 1 if it was
1999 * parsed successfully (return parameters contain allocated labels).
2000 */
2001int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
2002 const char *p, *q;
2003 char *sender, *external;
2004
2005 assert(object_path_is_valid(path));
2006 assert(object_path_is_valid(prefix));
2007 assert(ret_sender);
2008 assert(ret_external);
2009
2010 p = object_path_startswith(path, prefix);
2011 if (!p) {
2012 *ret_sender = NULL;
2013 *ret_external = NULL;
2014 return 0;
2015 }
2016
2017 q = strchr(p, '/');
2018 if (!q) {
2019 *ret_sender = NULL;
2020 *ret_external = NULL;
2021 return 0;
2022 }
2023
2024 sender = bus_label_unescape_n(p, q - p);
2025 external = bus_label_unescape(q + 1);
2026 if (!sender || !external) {
2027 free(sender);
2028 free(external);
2029 return -ENOMEM;
2030 }
2031
2032 *ret_sender = sender;
2033 *ret_external = external;
2034 return 1;
2035}