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