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