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