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