1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #include <sys/socket.h>
25 #include "sd-daemon.h"
28 #include "alloc-util.h"
29 #include "bus-error.h"
30 #include "bus-internal.h"
31 #include "bus-label.h"
32 #include "bus-message.h"
34 #include "cgroup-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "proc-cmdline.h"
44 #include "process-util.h"
45 #include "rlimit-util.h"
47 #include "signal-util.h"
48 #include "stdio-util.h"
49 #include "string-util.h"
51 #include "syslog-util.h"
52 #include "unit-name.h"
53 #include "user-util.h"
57 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
58 sd_event
*e
= userdata
;
63 sd_bus_close(sd_bus_message_get_bus(m
));
69 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
70 _cleanup_free_
char *match
= NULL
;
78 /* We unregister the name here and then wait for the
79 * NameOwnerChanged signal for this event to arrive before we
80 * quit. We do this in order to make sure that any queued
81 * requests are still processed before we really exit. */
83 r
= sd_bus_get_unique_name(bus
, &unique
);
88 "sender='org.freedesktop.DBus',"
90 "interface='org.freedesktop.DBus',"
91 "member='NameOwnerChanged',"
92 "path='/org/freedesktop/DBus',"
95 "arg2=''", name
, unique
);
99 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
103 r
= sd_bus_release_name(bus
, name
);
110 int bus_event_loop_with_idle(
115 check_idle_t check_idle
,
117 bool exiting
= false;
127 r
= sd_event_get_state(e
);
130 if (r
== SD_EVENT_FINISHED
)
134 idle
= check_idle(userdata
);
138 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
142 if (r
== 0 && !exiting
&& idle
) {
144 r
= sd_bus_try_close(bus
);
148 /* Fallback for dbus1 connections: we
149 * unregister the name and wait for the
150 * response to come through for it */
151 if (r
== -EOPNOTSUPP
) {
153 /* Inform the service manager that we
154 * are going down, so that it will
155 * queue all further start requests,
156 * instead of assuming we are already
158 sd_notify(false, "STOPPING=1");
160 r
= bus_async_unregister_and_exit(e
, bus
, name
);
176 r
= sd_event_get_exit_code(e
, &code
);
183 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
184 _cleanup_bus_message_unref_ sd_bus_message
*rep
= NULL
;
185 int r
, has_owner
= 0;
190 r
= sd_bus_call_method(c
,
191 "org.freedesktop.DBus",
192 "/org/freedesktop/dbus",
193 "org.freedesktop.DBus",
202 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
204 return sd_bus_error_set_errno(error
, r
);
209 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
210 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
216 if (good_user
== UID_INVALID
)
219 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
223 /* Don't trust augmented credentials for authorization */
224 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
226 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
230 return sender_uid
== good_user
;
234 sd_bus_message
*call
,
237 const char **details
,
247 /* Tests non-interactively! */
249 r
= check_good_user(call
, good_user
);
253 r
= sd_bus_query_sender_privilege(call
, capability
);
260 _cleanup_bus_message_unref_ sd_bus_message
*request
= NULL
;
261 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
262 int authorized
= false, challenge
= false;
263 const char *sender
, **k
, **v
;
265 sender
= sd_bus_message_get_sender(call
);
269 r
= sd_bus_message_new_method_call(
272 "org.freedesktop.PolicyKit1",
273 "/org/freedesktop/PolicyKit1/Authority",
274 "org.freedesktop.PolicyKit1.Authority",
275 "CheckAuthorization");
279 r
= sd_bus_message_append(
282 "system-bus-name", 1, "name", "s", sender
,
287 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
291 STRV_FOREACH_PAIR(k
, v
, details
) {
292 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
297 r
= sd_bus_message_close_container(request
);
301 r
= sd_bus_message_append(request
, "us", 0, NULL
);
305 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
307 /* Treat no PK available as access denied */
308 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
309 sd_bus_error_free(e
);
316 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
320 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
328 *_challenge
= challenge
;
339 typedef struct AsyncPolkitQuery
{
340 sd_bus_message
*request
, *reply
;
341 sd_bus_message_handler_t callback
;
347 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
352 sd_bus_slot_unref(q
->slot
);
354 if (q
->registry
&& q
->request
)
355 hashmap_remove(q
->registry
, q
->request
);
357 sd_bus_message_unref(q
->request
);
358 sd_bus_message_unref(q
->reply
);
363 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
364 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
365 AsyncPolkitQuery
*q
= userdata
;
371 q
->slot
= sd_bus_slot_unref(q
->slot
);
372 q
->reply
= sd_bus_message_ref(reply
);
374 r
= sd_bus_message_rewind(q
->request
, true);
376 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
380 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
381 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
384 async_polkit_query_free(q
);
391 int bus_verify_polkit_async(
392 sd_bus_message
*call
,
395 const char **details
,
399 sd_bus_error
*error
) {
402 _cleanup_bus_message_unref_ sd_bus_message
*pk
= NULL
;
404 const char *sender
, **k
, **v
;
405 sd_bus_message_handler_t callback
;
415 r
= check_good_user(call
, good_user
);
420 q
= hashmap_get(*registry
, call
);
422 int authorized
, challenge
;
424 /* This is the second invocation of this function, and
425 * there's already a response from polkit, let's
429 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
430 const sd_bus_error
*e
;
432 /* Copy error from polkit reply */
433 e
= sd_bus_message_get_error(q
->reply
);
434 sd_bus_error_copy(error
, e
);
436 /* Treat no PK available as access denied */
437 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
440 return -sd_bus_error_get_errno(e
);
443 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
445 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
454 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
460 r
= sd_bus_query_sender_privilege(call
, capability
);
467 if (sd_bus_get_current_message(call
->bus
) != call
)
470 callback
= sd_bus_get_current_handler(call
->bus
);
474 userdata
= sd_bus_get_current_userdata(call
->bus
);
476 sender
= sd_bus_message_get_sender(call
);
480 c
= sd_bus_message_get_allow_interactive_authorization(call
);
486 r
= hashmap_ensure_allocated(registry
, NULL
);
490 r
= sd_bus_message_new_method_call(
493 "org.freedesktop.PolicyKit1",
494 "/org/freedesktop/PolicyKit1/Authority",
495 "org.freedesktop.PolicyKit1.Authority",
496 "CheckAuthorization");
500 r
= sd_bus_message_append(
503 "system-bus-name", 1, "name", "s", sender
,
508 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
512 STRV_FOREACH_PAIR(k
, v
, details
) {
513 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
518 r
= sd_bus_message_close_container(pk
);
522 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
526 q
= new0(AsyncPolkitQuery
, 1);
530 q
->request
= sd_bus_message_ref(call
);
531 q
->callback
= callback
;
532 q
->userdata
= userdata
;
534 r
= hashmap_put(*registry
, call
, q
);
536 async_polkit_query_free(q
);
540 q
->registry
= *registry
;
542 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
544 async_polkit_query_free(q
);
554 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
558 while ((q
= hashmap_steal_first(registry
)))
559 async_polkit_query_free(q
);
561 hashmap_free(registry
);
565 int bus_check_peercred(sd_bus
*c
) {
572 fd
= sd_bus_get_fd(c
);
576 l
= sizeof(struct ucred
);
577 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
580 if (l
!= sizeof(struct ucred
))
583 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
589 int bus_connect_system_systemd(sd_bus
**_bus
) {
590 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
596 return sd_bus_default_system(_bus
);
598 /* If we are root and kdbus is not available, then let's talk
599 * directly to the system instance, instead of going via the
602 r
= sd_bus_new(&bus
);
606 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
610 bus
->bus_client
= true;
612 r
= sd_bus_start(bus
);
619 bus
= sd_bus_unref(bus
);
621 r
= sd_bus_new(&bus
);
625 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
629 r
= sd_bus_start(bus
);
631 return sd_bus_default_system(_bus
);
633 r
= bus_check_peercred(bus
);
643 int bus_connect_user_systemd(sd_bus
**_bus
) {
644 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
645 _cleanup_free_
char *ee
= NULL
;
649 /* Try via kdbus first, and then directly */
653 r
= sd_bus_new(&bus
);
657 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
660 bus
->bus_client
= true;
662 r
= sd_bus_start(bus
);
669 bus
= sd_bus_unref(bus
);
671 e
= secure_getenv("XDG_RUNTIME_DIR");
673 return sd_bus_default_user(_bus
);
675 ee
= bus_address_escape(e
);
679 r
= sd_bus_new(&bus
);
683 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
687 r
= sd_bus_start(bus
);
689 return sd_bus_default_user(_bus
);
691 r
= bus_check_peercred(bus
);
701 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
703 const char *contents
;
709 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
715 case SD_BUS_TYPE_STRING
: {
718 r
= sd_bus_message_read_basic(property
, type
, &s
);
722 if (all
|| !isempty(s
)) {
723 _cleanup_free_
char *escaped
= NULL
;
725 escaped
= xescape(s
, "\n");
729 printf("%s=%s\n", name
, escaped
);
735 case SD_BUS_TYPE_BOOLEAN
: {
738 r
= sd_bus_message_read_basic(property
, type
, &b
);
742 printf("%s=%s\n", name
, yes_no(b
));
747 case SD_BUS_TYPE_UINT64
: {
750 r
= sd_bus_message_read_basic(property
, type
, &u
);
754 /* Yes, heuristics! But we can change this check
755 * should it turn out to not be sufficient */
757 if (endswith(name
, "Timestamp")) {
758 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
760 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
762 printf("%s=%s\n", name
, strempty(t
));
764 } else if (strstr(name
, "USec")) {
765 char timespan
[FORMAT_TIMESPAN_MAX
];
767 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
769 printf("%s=%llu\n", name
, (unsigned long long) u
);
774 case SD_BUS_TYPE_INT64
: {
777 r
= sd_bus_message_read_basic(property
, type
, &i
);
781 printf("%s=%lld\n", name
, (long long) i
);
786 case SD_BUS_TYPE_UINT32
: {
789 r
= sd_bus_message_read_basic(property
, type
, &u
);
793 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
794 printf("%s=%04o\n", name
, u
);
796 printf("%s=%u\n", name
, (unsigned) u
);
801 case SD_BUS_TYPE_INT32
: {
804 r
= sd_bus_message_read_basic(property
, type
, &i
);
808 printf("%s=%i\n", name
, (int) i
);
812 case SD_BUS_TYPE_DOUBLE
: {
815 r
= sd_bus_message_read_basic(property
, type
, &d
);
819 printf("%s=%g\n", name
, d
);
823 case SD_BUS_TYPE_ARRAY
:
824 if (streq(contents
, "s")) {
828 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
832 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
833 _cleanup_free_
char *escaped
= NULL
;
838 escaped
= xescape(str
, "\n ");
842 printf("%s%s", first
? "" : " ", escaped
);
854 r
= sd_bus_message_exit_container(property
);
860 } else if (streq(contents
, "y")) {
864 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
873 for (i
= 0; i
< n
; i
++)
874 printf("%02x", u
[i
]);
881 } else if (streq(contents
, "u")) {
885 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
894 for (i
= 0; i
< n
; i
++)
895 printf("%08x", u
[i
]);
909 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
910 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
911 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
917 r
= sd_bus_call_method(bus
,
920 "org.freedesktop.DBus.Properties",
928 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
932 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
934 const char *contents
;
936 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
940 if (!filter
|| strv_find(filter
, name
)) {
941 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
945 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
949 r
= bus_print_property(name
, reply
, all
);
954 printf("%s=[unprintable]\n", name
);
955 /* skip what we didn't read */
956 r
= sd_bus_message_skip(reply
, contents
);
961 r
= sd_bus_message_exit_container(reply
);
965 r
= sd_bus_message_skip(reply
, "v");
970 r
= sd_bus_message_exit_container(reply
);
977 r
= sd_bus_message_exit_container(reply
);
984 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
985 sd_id128_t
*p
= userdata
;
990 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
997 memcpy((*p
).bytes
, v
, n
);
1004 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1008 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1013 case SD_BUS_TYPE_STRING
: {
1015 char **p
= userdata
;
1017 r
= sd_bus_message_read_basic(m
, type
, &s
);
1024 r
= free_and_strdup(p
, s
);
1028 case SD_BUS_TYPE_ARRAY
: {
1029 _cleanup_strv_free_
char **l
= NULL
;
1030 char ***p
= userdata
;
1032 r
= bus_message_read_strv_extend(m
, &l
);
1043 case SD_BUS_TYPE_BOOLEAN
: {
1047 r
= sd_bus_message_read_basic(m
, type
, &b
);
1056 case SD_BUS_TYPE_UINT32
: {
1058 uint32_t *p
= userdata
;
1060 r
= sd_bus_message_read_basic(m
, type
, &u
);
1069 case SD_BUS_TYPE_UINT64
: {
1071 uint64_t *p
= userdata
;
1073 r
= sd_bus_message_read_basic(m
, type
, &t
);
1089 int bus_message_map_all_properties(
1091 const struct bus_properties_map
*map
,
1094 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1100 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1104 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1105 const struct bus_properties_map
*prop
;
1107 const char *contents
;
1111 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1115 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1116 if (streq(map
[i
].member
, member
)) {
1122 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1126 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1130 v
= (uint8_t *)userdata
+ prop
->offset
;
1132 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1134 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1138 r
= sd_bus_message_exit_container(m
);
1142 r
= sd_bus_message_skip(m
, "v");
1147 r
= sd_bus_message_exit_container(m
);
1154 return sd_bus_message_exit_container(m
);
1157 int bus_message_map_properties_changed(
1159 const struct bus_properties_map
*map
,
1163 int r
, invalidated
, i
;
1168 r
= bus_message_map_all_properties(m
, map
, userdata
);
1172 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1177 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1178 for (i
= 0; map
[i
].member
; i
++)
1179 if (streq(map
[i
].member
, member
)) {
1186 r
= sd_bus_message_exit_container(m
);
1193 int bus_map_all_properties(
1195 const char *destination
,
1197 const struct bus_properties_map
*map
,
1200 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1201 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1205 assert(destination
);
1209 r
= sd_bus_call_method(
1213 "org.freedesktop.DBus.Properties",
1221 return bus_message_map_all_properties(m
, map
, userdata
);
1224 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1227 assert(transport
>= 0);
1228 assert(transport
< _BUS_TRANSPORT_MAX
);
1231 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1232 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1234 switch (transport
) {
1236 case BUS_TRANSPORT_LOCAL
:
1238 r
= sd_bus_default_user(bus
);
1240 r
= sd_bus_default_system(bus
);
1244 case BUS_TRANSPORT_REMOTE
:
1245 r
= sd_bus_open_system_remote(bus
, host
);
1248 case BUS_TRANSPORT_MACHINE
:
1249 r
= sd_bus_open_system_machine(bus
, host
);
1253 assert_not_reached("Hmm, unknown transport type.");
1259 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1262 assert(transport
>= 0);
1263 assert(transport
< _BUS_TRANSPORT_MAX
);
1266 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1267 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1269 switch (transport
) {
1271 case BUS_TRANSPORT_LOCAL
:
1273 r
= bus_connect_user_systemd(bus
);
1275 r
= bus_connect_system_systemd(bus
);
1279 case BUS_TRANSPORT_REMOTE
:
1280 r
= sd_bus_open_system_remote(bus
, host
);
1283 case BUS_TRANSPORT_MACHINE
:
1284 r
= sd_bus_open_system_machine(bus
, host
);
1288 assert_not_reached("Hmm, unknown transport type.");
1294 int bus_property_get_bool(
1297 const char *interface
,
1298 const char *property
,
1299 sd_bus_message
*reply
,
1301 sd_bus_error
*error
) {
1303 int b
= *(bool*) userdata
;
1305 return sd_bus_message_append_basic(reply
, 'b', &b
);
1308 #if __SIZEOF_SIZE_T__ != 8
1309 int bus_property_get_size(
1312 const char *interface
,
1313 const char *property
,
1314 sd_bus_message
*reply
,
1316 sd_bus_error
*error
) {
1318 uint64_t sz
= *(size_t*) userdata
;
1320 return sd_bus_message_append_basic(reply
, 't', &sz
);
1324 #if __SIZEOF_LONG__ != 8
1325 int bus_property_get_long(
1328 const char *interface
,
1329 const char *property
,
1330 sd_bus_message
*reply
,
1332 sd_bus_error
*error
) {
1334 int64_t l
= *(long*) userdata
;
1336 return sd_bus_message_append_basic(reply
, 'x', &l
);
1339 int bus_property_get_ulong(
1342 const char *interface
,
1343 const char *property
,
1344 sd_bus_message
*reply
,
1346 sd_bus_error
*error
) {
1348 uint64_t ul
= *(unsigned long*) userdata
;
1350 return sd_bus_message_append_basic(reply
, 't', &ul
);
1354 int bus_log_parse_error(int r
) {
1355 return log_error_errno(r
, "Failed to parse bus message: %m");
1358 int bus_log_create_error(int r
) {
1359 return log_error_errno(r
, "Failed to create bus message: %m");
1362 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1368 return sd_bus_message_read(
1383 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1384 const char *eq
, *field
;
1390 eq
= strchr(assignment
, '=');
1392 log_error("Not an assignment: %s", assignment
);
1396 field
= strndupa(assignment
, eq
- assignment
);
1399 if (streq(field
, "CPUQuota")) {
1403 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1405 return bus_log_create_error(r
);
1407 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1409 } else if (endswith(eq
, "%")) {
1412 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1413 log_error("CPU quota '%s' invalid.", eq
);
1417 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1419 return bus_log_create_error(r
);
1421 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1423 log_error("CPU quota needs to be in percent.");
1428 return bus_log_create_error(r
);
1432 } else if (streq(field
, "EnvironmentFile")) {
1434 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1436 return bus_log_create_error(r
);
1438 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1439 eq
[0] == '-' ? eq
+ 1 : eq
,
1442 return bus_log_create_error(r
);
1446 } else if (streq(field
, "RandomizedDelaySec")) {
1449 r
= parse_sec(eq
, &t
);
1451 return log_error_errno(r
, "Failed to parse RandomizedDelaySec= parameter: %s", eq
);
1453 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "RandomizedDelayUSec");
1455 return bus_log_create_error(r
);
1457 r
= sd_bus_message_append(m
, "v", "t", t
);
1459 return bus_log_create_error(r
);
1464 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1466 return bus_log_create_error(r
);
1468 if (STR_IN_SET(field
,
1469 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1470 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1471 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1472 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1473 "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
1475 r
= parse_boolean(eq
);
1477 return log_error_errno(r
, "Failed to parse boolean assignment %s.", assignment
);
1479 r
= sd_bus_message_append(m
, "v", "b", r
);
1481 } else if (streq(field
, "MemoryLimit")) {
1484 if (isempty(eq
) || streq(eq
, "infinity"))
1485 bytes
= (uint64_t) -1;
1487 r
= parse_size(eq
, 1024, &bytes
);
1489 log_error("Failed to parse bytes specification %s", assignment
);
1494 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1496 } else if (streq(field
, "TasksMax")) {
1499 if (isempty(eq
) || streq(eq
, "infinity"))
1502 r
= safe_atou64(eq
, &n
);
1504 log_error("Failed to parse maximum tasks specification %s", assignment
);
1509 r
= sd_bus_message_append(m
, "v", "t", n
);
1511 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1514 r
= cg_cpu_shares_parse(eq
, &u
);
1516 log_error("Failed to parse %s value %s.", field
, eq
);
1520 r
= sd_bus_message_append(m
, "v", "t", u
);
1522 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1525 r
= cg_cpu_shares_parse(eq
, &u
);
1527 log_error("Failed to parse %s value %s.", field
, eq
);
1531 r
= sd_bus_message_append(m
, "v", "t", u
);
1533 } else if (STR_IN_SET(field
,
1534 "User", "Group", "DevicePolicy", "KillMode",
1535 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1536 "StandardInput", "StandardOutput", "StandardError",
1537 "Description", "Slice", "Type", "WorkingDirectory",
1538 "RootDirectory", "SyslogIdentifier", "ProtectSystem",
1540 r
= sd_bus_message_append(m
, "v", "s", eq
);
1542 else if (streq(field
, "SyslogLevel")) {
1545 level
= log_level_from_string(eq
);
1547 log_error("Failed to parse %s value %s.", field
, eq
);
1551 r
= sd_bus_message_append(m
, "v", "i", level
);
1553 } else if (streq(field
, "SyslogFacility")) {
1556 facility
= log_facility_unshifted_from_string(eq
);
1558 log_error("Failed to parse %s value %s.", field
, eq
);
1562 r
= sd_bus_message_append(m
, "v", "i", facility
);
1564 } else if (streq(field
, "DeviceAllow")) {
1567 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1569 const char *path
, *rwm
, *e
;
1571 e
= strchr(eq
, ' ');
1573 path
= strndupa(eq
, e
- eq
);
1580 if (!path_startswith(path
, "/dev")) {
1581 log_error("%s is not a device file in /dev.", path
);
1585 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1588 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1591 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1593 const char *path
, *bandwidth
, *e
;
1596 e
= strchr(eq
, ' ');
1598 path
= strndupa(eq
, e
- eq
);
1601 log_error("Failed to parse %s value %s.", field
, eq
);
1605 if (!path_startswith(path
, "/dev")) {
1606 log_error("%s is not a device file in /dev.", path
);
1610 r
= parse_size(bandwidth
, 1000, &bytes
);
1612 log_error("Failed to parse byte value %s.", bandwidth
);
1616 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1619 } else if (streq(field
, "BlockIODeviceWeight")) {
1622 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1624 const char *path
, *weight
, *e
;
1627 e
= strchr(eq
, ' ');
1629 path
= strndupa(eq
, e
- eq
);
1632 log_error("Failed to parse %s value %s.", field
, eq
);
1636 if (!path_startswith(path
, "/dev")) {
1637 log_error("%s is not a device file in /dev.", path
);
1641 r
= safe_atou64(weight
, &u
);
1643 log_error("Failed to parse %s value %s.", field
, weight
);
1646 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1649 } else if (rlimit_from_string(field
) >= 0) {
1652 if (streq(eq
, "infinity"))
1655 r
= safe_atou64(eq
, &rl
);
1657 log_error("Invalid resource limit: %s", eq
);
1662 r
= sd_bus_message_append(m
, "v", "t", rl
);
1664 } else if (streq(field
, "Nice")) {
1667 r
= safe_atoi32(eq
, &i
);
1669 log_error("Failed to parse %s value %s.", field
, eq
);
1673 r
= sd_bus_message_append(m
, "v", "i", i
);
1675 } else if (STR_IN_SET(field
, "Environment", "PassEnvironment")) {
1678 r
= sd_bus_message_open_container(m
, 'v', "as");
1680 return bus_log_create_error(r
);
1682 r
= sd_bus_message_open_container(m
, 'a', "s");
1684 return bus_log_create_error(r
);
1689 _cleanup_free_
char *word
= NULL
;
1691 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1693 log_error("Failed to parse Environment value %s", eq
);
1699 if (streq(field
, "Environment")) {
1700 if (!env_assignment_is_valid(word
)) {
1701 log_error("Invalid environment assignment: %s", word
);
1704 } else { /* PassEnvironment */
1705 if (!env_name_is_valid(word
)) {
1706 log_error("Invalid environment variable name: %s", word
);
1711 r
= sd_bus_message_append_basic(m
, 's', word
);
1713 return bus_log_create_error(r
);
1716 r
= sd_bus_message_close_container(m
);
1718 return bus_log_create_error(r
);
1720 r
= sd_bus_message_close_container(m
);
1722 } else if (streq(field
, "KillSignal")) {
1725 sig
= signal_from_string_try_harder(eq
);
1727 log_error("Failed to parse %s value %s.", field
, eq
);
1731 r
= sd_bus_message_append(m
, "v", "i", sig
);
1733 } else if (streq(field
, "AccuracySec")) {
1736 r
= parse_sec(eq
, &u
);
1738 log_error("Failed to parse %s value %s", field
, eq
);
1742 r
= sd_bus_message_append(m
, "v", "t", u
);
1743 } else if (streq(field
, "TimerSlackNSec")) {
1746 r
= parse_nsec(eq
, &n
);
1748 log_error("Failed to parse %s value %s", field
, eq
);
1752 r
= sd_bus_message_append(m
, "v", "t", n
);
1753 } else if (streq(field
, "OOMScoreAdjust")) {
1756 r
= safe_atoi(eq
, &oa
);
1758 log_error("Failed to parse %s value %s", field
, eq
);
1762 if (!oom_score_adjust_is_valid(oa
)) {
1763 log_error("OOM score adjust value out of range");
1767 r
= sd_bus_message_append(m
, "v", "i", oa
);
1768 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1771 r
= sd_bus_message_open_container(m
, 'v', "as");
1773 return bus_log_create_error(r
);
1775 r
= sd_bus_message_open_container(m
, 'a', "s");
1777 return bus_log_create_error(r
);
1782 _cleanup_free_
char *word
= NULL
;
1785 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1787 log_error("Failed to parse %s value %s", field
, eq
);
1793 if (!utf8_is_valid(word
)) {
1794 log_error("Failed to parse %s value %s", field
, eq
);
1798 offset
= word
[0] == '-';
1799 if (!path_is_absolute(word
+ offset
)) {
1800 log_error("Failed to parse %s value %s", field
, eq
);
1804 path_kill_slashes(word
+ offset
);
1806 r
= sd_bus_message_append_basic(m
, 's', word
);
1808 return bus_log_create_error(r
);
1811 r
= sd_bus_message_close_container(m
);
1813 return bus_log_create_error(r
);
1815 r
= sd_bus_message_close_container(m
);
1817 } else if (streq(field
, "RuntimeDirectory")) {
1820 r
= sd_bus_message_open_container(m
, 'v', "as");
1822 return bus_log_create_error(r
);
1824 r
= sd_bus_message_open_container(m
, 'a', "s");
1826 return bus_log_create_error(r
);
1831 _cleanup_free_
char *word
= NULL
;
1833 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1835 return log_error_errno(r
, "Failed to parse %s value %s", field
, eq
);
1840 r
= sd_bus_message_append_basic(m
, 's', word
);
1842 return bus_log_create_error(r
);
1845 r
= sd_bus_message_close_container(m
);
1847 return bus_log_create_error(r
);
1849 r
= sd_bus_message_close_container(m
);
1852 log_error("Unknown assignment %s.", assignment
);
1857 return bus_log_create_error(r
);
1862 typedef struct BusWaitForJobs
{
1869 sd_bus_slot
*slot_job_removed
;
1870 sd_bus_slot
*slot_disconnected
;
1873 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1876 log_error("Warning! D-Bus connection terminated.");
1877 sd_bus_close(sd_bus_message_get_bus(m
));
1882 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1883 const char *path
, *unit
, *result
;
1884 BusWaitForJobs
*d
= userdata
;
1892 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1894 bus_log_parse_error(r
);
1898 found
= set_remove(d
->jobs
, (char*) path
);
1904 if (!isempty(result
))
1905 d
->result
= strdup(result
);
1908 d
->name
= strdup(unit
);
1913 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1917 set_free_free(d
->jobs
);
1919 sd_bus_slot_unref(d
->slot_disconnected
);
1920 sd_bus_slot_unref(d
->slot_job_removed
);
1922 sd_bus_unref(d
->bus
);
1930 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1931 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1937 d
= new0(BusWaitForJobs
, 1);
1941 d
->bus
= sd_bus_ref(bus
);
1943 /* When we are a bus client we match by sender. Direct
1944 * connections OTOH have no initialized sender field, and
1945 * hence we ignore the sender then */
1946 r
= sd_bus_add_match(
1948 &d
->slot_job_removed
,
1951 "sender='org.freedesktop.systemd1',"
1952 "interface='org.freedesktop.systemd1.Manager',"
1953 "member='JobRemoved',"
1954 "path='/org/freedesktop/systemd1'" :
1956 "interface='org.freedesktop.systemd1.Manager',"
1957 "member='JobRemoved',"
1958 "path='/org/freedesktop/systemd1'",
1959 match_job_removed
, d
);
1963 r
= sd_bus_add_match(
1965 &d
->slot_disconnected
,
1967 "sender='org.freedesktop.DBus.Local',"
1968 "interface='org.freedesktop.DBus.Local',"
1969 "member='Disconnected'",
1970 match_disconnected
, d
);
1980 static int bus_process_wait(sd_bus
*bus
) {
1984 r
= sd_bus_process(bus
, NULL
);
1990 r
= sd_bus_wait(bus
, (uint64_t) -1);
1996 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1997 _cleanup_free_
char *dbus_path
= NULL
;
2003 dbus_path
= unit_dbus_path_from_name(d
->name
);
2007 return sd_bus_get_property_string(d
->bus
,
2008 "org.freedesktop.systemd1",
2010 "org.freedesktop.systemd1.Service",
2016 static const struct {
2017 const char *result
, *explanation
;
2018 } explanations
[] = {
2019 { "resources", "a configured resource limit was exceeded" },
2020 { "timeout", "a timeout was exceeded" },
2021 { "exit-code", "the control process exited with error code" },
2022 { "signal", "a fatal signal was delivered to the control process" },
2023 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
2024 { "watchdog", "the service failed to send watchdog ping" },
2025 { "start-limit", "start of the service was attempted too often" }
2028 static void log_job_error_with_service_result(const char* service
, const char *result
) {
2029 _cleanup_free_
char *service_shell_quoted
= NULL
;
2033 service_shell_quoted
= shell_maybe_quote(service
);
2035 if (!isempty(result
)) {
2038 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
2039 if (streq(result
, explanations
[i
].result
))
2042 if (i
< ELEMENTSOF(explanations
)) {
2043 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
2045 explanations
[i
].explanation
,
2046 strna(service_shell_quoted
));
2052 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
2054 strna(service_shell_quoted
));
2057 /* For some results maybe additional explanation is required */
2058 if (streq_ptr(result
, "start-limit"))
2059 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
2060 strna(service_shell_quoted
));
2063 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
2069 if (streq(d
->result
, "canceled"))
2070 log_error("Job for %s canceled.", strna(d
->name
));
2071 else if (streq(d
->result
, "timeout"))
2072 log_error("Job for %s timed out.", strna(d
->name
));
2073 else if (streq(d
->result
, "dependency"))
2074 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2075 else if (streq(d
->result
, "invalid"))
2076 log_error("Job for %s invalid.", strna(d
->name
));
2077 else if (streq(d
->result
, "assert"))
2078 log_error("Assertion failed on job for %s.", strna(d
->name
));
2079 else if (streq(d
->result
, "unsupported"))
2080 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2081 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2084 _cleanup_free_
char *result
= NULL
;
2086 q
= bus_job_get_service_result(d
, &result
);
2088 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2090 log_job_error_with_service_result(d
->name
, result
);
2092 log_error("Job failed. See \"journalctl -xe\" for details.");
2096 if (streq(d
->result
, "canceled"))
2098 else if (streq(d
->result
, "timeout"))
2100 else if (streq(d
->result
, "dependency"))
2102 else if (streq(d
->result
, "invalid"))
2104 else if (streq(d
->result
, "assert"))
2106 else if (streq(d
->result
, "unsupported"))
2108 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2114 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2119 while (!set_isempty(d
->jobs
)) {
2122 q
= bus_process_wait(d
->bus
);
2124 return log_error_errno(q
, "Failed to wait for response: %m");
2127 q
= check_wait_response(d
, quiet
);
2128 /* Return the first error as it is most likely to be
2130 if (q
< 0 && r
== 0)
2133 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2136 d
->name
= mfree(d
->name
);
2137 d
->result
= mfree(d
->result
);
2143 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2148 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2152 return set_put_strdup(d
->jobs
, path
);
2155 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2158 r
= bus_wait_for_jobs_add(d
, path
);
2162 return bus_wait_for_jobs(d
, quiet
);
2165 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2166 const char *type
, *path
, *source
;
2169 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2171 return bus_log_parse_error(r
);
2173 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2175 if (streq(type
, "symlink"))
2176 log_info("Created symlink from %s to %s.", path
, source
);
2178 log_info("Removed symlink %s.", path
);
2181 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2186 return bus_log_parse_error(r
);
2188 r
= sd_bus_message_exit_container(m
);
2190 return bus_log_parse_error(r
);
2196 * bus_path_encode_unique() - encode unique object path
2197 * @b: bus connection or NULL
2198 * @prefix: object path prefix
2199 * @sender_id: unique-name of client, or NULL
2200 * @external_id: external ID to be chosen by client, or NULL
2201 * @ret_path: storage for encoded object path pointer
2203 * Whenever we provide a bus API that allows clients to create and manage
2204 * server-side objects, we need to provide a unique name for these objects. If
2205 * we let the server choose the name, we suffer from a race condition: If a
2206 * client creates an object asynchronously, it cannot destroy that object until
2207 * it received the method reply. It cannot know the name of the new object,
2208 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2210 * Therefore, many APIs allow the client to choose the unique name for newly
2211 * created objects. There're two problems to solve, though:
2212 * 1) Object names are usually defined via dbus object paths, which are
2213 * usually globally namespaced. Therefore, multiple clients must be able
2214 * to choose unique object names without interference.
2215 * 2) If multiple libraries share the same bus connection, they must be
2216 * able to choose unique object names without interference.
2217 * The first problem is solved easily by prefixing a name with the
2218 * unique-bus-name of a connection. The server side must enforce this and
2219 * reject any other name. The second problem is solved by providing unique
2220 * suffixes from within sd-bus.
2222 * This helper allows clients to create unique object-paths. It uses the
2223 * template '/prefix/sender_id/external_id' and returns the new path in
2224 * @ret_path (must be freed by the caller).
2225 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2226 * NULL, this function allocates a unique suffix via @b (by requesting a new
2227 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2230 * Returns: 0 on success, negative error code on failure.
2232 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2233 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2234 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2237 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2238 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2239 assert_return(ret_path
, -EINVAL
);
2242 r
= sd_bus_get_unique_name(b
, &sender_id
);
2248 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2249 external_id
= external_buf
;
2252 sender_label
= bus_label_escape(sender_id
);
2256 external_label
= bus_label_escape(external_id
);
2257 if (!external_label
)
2260 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2269 * bus_path_decode_unique() - decode unique object path
2270 * @path: object path to decode
2271 * @prefix: object path prefix
2272 * @ret_sender: output parameter for sender-id label
2273 * @ret_external: output parameter for external-id label
2275 * This does the reverse of bus_path_encode_unique() (see its description for
2276 * details). Both trailing labels, sender-id and external-id, are unescaped and
2277 * returned in the given output parameters (the caller must free them).
2279 * Note that this function returns 0 if the path does not match the template
2280 * (see bus_path_encode_unique()), 1 if it matched.
2282 * Returns: Negative error code on failure, 0 if the given object path does not
2283 * match the template (return parameters are set to NULL), 1 if it was
2284 * parsed successfully (return parameters contain allocated labels).
2286 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2288 char *sender
, *external
;
2290 assert(object_path_is_valid(path
));
2291 assert(object_path_is_valid(prefix
));
2293 assert(ret_external
);
2295 p
= object_path_startswith(path
, prefix
);
2298 *ret_external
= NULL
;
2305 *ret_external
= NULL
;
2309 sender
= bus_label_unescape_n(p
, q
- p
);
2310 external
= bus_label_unescape(q
+ 1);
2311 if (!sender
|| !external
) {
2317 *ret_sender
= sender
;
2318 *ret_external
= external
;
2322 bool is_kdbus_wanted(void) {
2323 _cleanup_free_
char *value
= NULL
;
2325 const bool configured
= true;
2327 const bool configured
= false;
2332 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2335 r
= get_proc_cmdline_key("kdbus=", &value
);
2339 return parse_boolean(value
) == 1;
2342 bool is_kdbus_available(void) {
2343 _cleanup_close_
int fd
= -1;
2344 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2346 if (!is_kdbus_wanted())
2349 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2353 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2356 int bus_property_get_rlimit(
2359 const char *interface
,
2360 const char *property
,
2361 sd_bus_message
*reply
,
2363 sd_bus_error
*error
) {
2373 rl
= *(struct rlimit
**) userdata
;
2377 struct rlimit buf
= {};
2380 z
= rlimit_from_string(strstr(property
, "Limit"));
2387 /* rlim_t might have different sizes, let's map
2388 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2390 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2392 return sd_bus_message_append(reply
, "t", u
);