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