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/>.
28 #include <sys/ioctl.h>
29 #include <sys/resource.h>
30 #include <sys/socket.h>
33 #include "sd-bus-protocol.h"
35 #include "sd-daemon.h"
39 #include "alloc-util.h"
40 #include "bus-internal.h"
41 #include "bus-label.h"
42 #include "bus-message.h"
44 #include "cgroup-util.h"
48 #include "extract-word.h"
56 #include "parse-util.h"
57 #include "path-util.h"
58 #include "proc-cmdline.h"
59 #include "process-util.h"
60 #include "rlimit-util.h"
62 #include "signal-util.h"
63 #include "stdio-util.h"
64 #include "string-util.h"
66 #include "syslog-util.h"
67 #include "time-util.h"
68 #include "unit-name.h"
69 #include "user-util.h"
73 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
74 sd_event
*e
= userdata
;
79 sd_bus_close(sd_bus_message_get_bus(m
));
85 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
86 _cleanup_free_
char *match
= NULL
;
94 /* We unregister the name here and then wait for the
95 * NameOwnerChanged signal for this event to arrive before we
96 * quit. We do this in order to make sure that any queued
97 * requests are still processed before we really exit. */
99 r
= sd_bus_get_unique_name(bus
, &unique
);
104 "sender='org.freedesktop.DBus',"
106 "interface='org.freedesktop.DBus',"
107 "member='NameOwnerChanged',"
108 "path='/org/freedesktop/DBus',"
111 "arg2=''", name
, unique
);
115 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
119 r
= sd_bus_release_name(bus
, name
);
126 int bus_event_loop_with_idle(
131 check_idle_t check_idle
,
133 bool exiting
= false;
143 r
= sd_event_get_state(e
);
146 if (r
== SD_EVENT_FINISHED
)
150 idle
= check_idle(userdata
);
154 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
158 if (r
== 0 && !exiting
&& idle
) {
160 r
= sd_bus_try_close(bus
);
164 /* Fallback for dbus1 connections: we
165 * unregister the name and wait for the
166 * response to come through for it */
167 if (r
== -EOPNOTSUPP
) {
169 /* Inform the service manager that we
170 * are going down, so that it will
171 * queue all further start requests,
172 * instead of assuming we are already
174 sd_notify(false, "STOPPING=1");
176 r
= bus_async_unregister_and_exit(e
, bus
, name
);
192 r
= sd_event_get_exit_code(e
, &code
);
199 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
200 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*rep
= NULL
;
201 int r
, has_owner
= 0;
206 r
= sd_bus_call_method(c
,
207 "org.freedesktop.DBus",
208 "/org/freedesktop/dbus",
209 "org.freedesktop.DBus",
218 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
220 return sd_bus_error_set_errno(error
, r
);
225 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
226 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
232 if (good_user
== UID_INVALID
)
235 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
239 /* Don't trust augmented credentials for authorization */
240 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
242 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
246 return sender_uid
== good_user
;
250 sd_bus_message
*call
,
253 const char **details
,
263 /* Tests non-interactively! */
265 r
= check_good_user(call
, good_user
);
269 r
= sd_bus_query_sender_privilege(call
, capability
);
276 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*request
= NULL
;
277 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
278 int authorized
= false, challenge
= false;
279 const char *sender
, **k
, **v
;
281 sender
= sd_bus_message_get_sender(call
);
285 r
= sd_bus_message_new_method_call(
288 "org.freedesktop.PolicyKit1",
289 "/org/freedesktop/PolicyKit1/Authority",
290 "org.freedesktop.PolicyKit1.Authority",
291 "CheckAuthorization");
295 r
= sd_bus_message_append(
298 "system-bus-name", 1, "name", "s", sender
,
303 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
307 STRV_FOREACH_PAIR(k
, v
, details
) {
308 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
313 r
= sd_bus_message_close_container(request
);
317 r
= sd_bus_message_append(request
, "us", 0, NULL
);
321 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
323 /* Treat no PK available as access denied */
324 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
325 sd_bus_error_free(e
);
332 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
336 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
344 *_challenge
= challenge
;
355 typedef struct AsyncPolkitQuery
{
356 sd_bus_message
*request
, *reply
;
357 sd_bus_message_handler_t callback
;
363 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
368 sd_bus_slot_unref(q
->slot
);
370 if (q
->registry
&& q
->request
)
371 hashmap_remove(q
->registry
, q
->request
);
373 sd_bus_message_unref(q
->request
);
374 sd_bus_message_unref(q
->reply
);
379 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
380 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
381 AsyncPolkitQuery
*q
= userdata
;
387 q
->slot
= sd_bus_slot_unref(q
->slot
);
388 q
->reply
= sd_bus_message_ref(reply
);
390 r
= sd_bus_message_rewind(q
->request
, true);
392 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
396 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
397 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
400 async_polkit_query_free(q
);
407 int bus_verify_polkit_async(
408 sd_bus_message
*call
,
411 const char **details
,
415 sd_bus_error
*error
) {
418 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pk
= NULL
;
420 const char *sender
, **k
, **v
;
421 sd_bus_message_handler_t callback
;
431 r
= check_good_user(call
, good_user
);
436 q
= hashmap_get(*registry
, call
);
438 int authorized
, challenge
;
440 /* This is the second invocation of this function, and
441 * there's already a response from polkit, let's
445 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
446 const sd_bus_error
*e
;
448 /* Copy error from polkit reply */
449 e
= sd_bus_message_get_error(q
->reply
);
450 sd_bus_error_copy(error
, e
);
452 /* Treat no PK available as access denied */
453 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
456 return -sd_bus_error_get_errno(e
);
459 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
461 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
470 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
476 r
= sd_bus_query_sender_privilege(call
, capability
);
483 if (sd_bus_get_current_message(call
->bus
) != call
)
486 callback
= sd_bus_get_current_handler(call
->bus
);
490 userdata
= sd_bus_get_current_userdata(call
->bus
);
492 sender
= sd_bus_message_get_sender(call
);
496 c
= sd_bus_message_get_allow_interactive_authorization(call
);
502 r
= hashmap_ensure_allocated(registry
, NULL
);
506 r
= sd_bus_message_new_method_call(
509 "org.freedesktop.PolicyKit1",
510 "/org/freedesktop/PolicyKit1/Authority",
511 "org.freedesktop.PolicyKit1.Authority",
512 "CheckAuthorization");
516 r
= sd_bus_message_append(
519 "system-bus-name", 1, "name", "s", sender
,
524 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
528 STRV_FOREACH_PAIR(k
, v
, details
) {
529 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
534 r
= sd_bus_message_close_container(pk
);
538 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
542 q
= new0(AsyncPolkitQuery
, 1);
546 q
->request
= sd_bus_message_ref(call
);
547 q
->callback
= callback
;
548 q
->userdata
= userdata
;
550 r
= hashmap_put(*registry
, call
, q
);
552 async_polkit_query_free(q
);
556 q
->registry
= *registry
;
558 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
560 async_polkit_query_free(q
);
570 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
574 while ((q
= hashmap_steal_first(registry
)))
575 async_polkit_query_free(q
);
577 hashmap_free(registry
);
581 int bus_check_peercred(sd_bus
*c
) {
588 fd
= sd_bus_get_fd(c
);
592 l
= sizeof(struct ucred
);
593 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
596 if (l
!= sizeof(struct ucred
))
599 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
605 int bus_connect_system_systemd(sd_bus
**_bus
) {
606 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
612 return sd_bus_default_system(_bus
);
614 /* If we are root and kdbus is not available, then let's talk
615 * directly to the system instance, instead of going via the
618 r
= sd_bus_new(&bus
);
622 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
626 bus
->bus_client
= true;
628 r
= sd_bus_start(bus
);
635 bus
= sd_bus_unref(bus
);
637 r
= sd_bus_new(&bus
);
641 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
645 r
= sd_bus_start(bus
);
647 return sd_bus_default_system(_bus
);
649 r
= bus_check_peercred(bus
);
659 int bus_connect_user_systemd(sd_bus
**_bus
) {
660 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
661 _cleanup_free_
char *ee
= NULL
;
665 /* Try via kdbus first, and then directly */
669 r
= sd_bus_new(&bus
);
673 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
676 bus
->bus_client
= true;
678 r
= sd_bus_start(bus
);
685 bus
= sd_bus_unref(bus
);
687 e
= secure_getenv("XDG_RUNTIME_DIR");
689 return sd_bus_default_user(_bus
);
691 ee
= bus_address_escape(e
);
695 r
= sd_bus_new(&bus
);
699 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
703 r
= sd_bus_start(bus
);
705 return sd_bus_default_user(_bus
);
707 r
= bus_check_peercred(bus
);
717 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
719 const char *contents
;
725 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
731 case SD_BUS_TYPE_STRING
: {
734 r
= sd_bus_message_read_basic(property
, type
, &s
);
738 if (all
|| !isempty(s
)) {
739 _cleanup_free_
char *escaped
= NULL
;
741 escaped
= xescape(s
, "\n");
745 printf("%s=%s\n", name
, escaped
);
751 case SD_BUS_TYPE_BOOLEAN
: {
754 r
= sd_bus_message_read_basic(property
, type
, &b
);
758 printf("%s=%s\n", name
, yes_no(b
));
763 case SD_BUS_TYPE_UINT64
: {
766 r
= sd_bus_message_read_basic(property
, type
, &u
);
770 /* Yes, heuristics! But we can change this check
771 * should it turn out to not be sufficient */
773 if (endswith(name
, "Timestamp")) {
774 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
776 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
778 printf("%s=%s\n", name
, strempty(t
));
780 } else if (strstr(name
, "USec")) {
781 char timespan
[FORMAT_TIMESPAN_MAX
];
783 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
785 printf("%s=%llu\n", name
, (unsigned long long) u
);
790 case SD_BUS_TYPE_INT64
: {
793 r
= sd_bus_message_read_basic(property
, type
, &i
);
797 printf("%s=%lld\n", name
, (long long) i
);
802 case SD_BUS_TYPE_UINT32
: {
805 r
= sd_bus_message_read_basic(property
, type
, &u
);
809 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
810 printf("%s=%04o\n", name
, u
);
812 printf("%s=%u\n", name
, (unsigned) u
);
817 case SD_BUS_TYPE_INT32
: {
820 r
= sd_bus_message_read_basic(property
, type
, &i
);
824 printf("%s=%i\n", name
, (int) i
);
828 case SD_BUS_TYPE_DOUBLE
: {
831 r
= sd_bus_message_read_basic(property
, type
, &d
);
835 printf("%s=%g\n", name
, d
);
839 case SD_BUS_TYPE_ARRAY
:
840 if (streq(contents
, "s")) {
844 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
848 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
849 _cleanup_free_
char *escaped
= NULL
;
854 escaped
= xescape(str
, "\n ");
858 printf("%s%s", first
? "" : " ", escaped
);
870 r
= sd_bus_message_exit_container(property
);
876 } else if (streq(contents
, "y")) {
880 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
889 for (i
= 0; i
< n
; i
++)
890 printf("%02x", u
[i
]);
897 } else if (streq(contents
, "u")) {
901 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
910 for (i
= 0; i
< n
; i
++)
911 printf("%08x", u
[i
]);
925 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
926 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
927 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
933 r
= sd_bus_call_method(bus
,
936 "org.freedesktop.DBus.Properties",
944 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
948 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
950 const char *contents
;
952 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
956 if (!filter
|| strv_find(filter
, name
)) {
957 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
961 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
965 r
= bus_print_property(name
, reply
, all
);
970 printf("%s=[unprintable]\n", name
);
971 /* skip what we didn't read */
972 r
= sd_bus_message_skip(reply
, contents
);
977 r
= sd_bus_message_exit_container(reply
);
981 r
= sd_bus_message_skip(reply
, "v");
986 r
= sd_bus_message_exit_container(reply
);
993 r
= sd_bus_message_exit_container(reply
);
1000 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1001 sd_id128_t
*p
= userdata
;
1006 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
1013 memcpy((*p
).bytes
, v
, n
);
1020 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1024 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1029 case SD_BUS_TYPE_STRING
: {
1031 char **p
= userdata
;
1033 r
= sd_bus_message_read_basic(m
, type
, &s
);
1040 r
= free_and_strdup(p
, s
);
1044 case SD_BUS_TYPE_ARRAY
: {
1045 _cleanup_strv_free_
char **l
= NULL
;
1046 char ***p
= userdata
;
1048 r
= bus_message_read_strv_extend(m
, &l
);
1059 case SD_BUS_TYPE_BOOLEAN
: {
1063 r
= sd_bus_message_read_basic(m
, type
, &b
);
1072 case SD_BUS_TYPE_UINT32
: {
1074 uint32_t *p
= userdata
;
1076 r
= sd_bus_message_read_basic(m
, type
, &u
);
1085 case SD_BUS_TYPE_UINT64
: {
1087 uint64_t *p
= userdata
;
1089 r
= sd_bus_message_read_basic(m
, type
, &t
);
1105 int bus_message_map_all_properties(
1107 const struct bus_properties_map
*map
,
1110 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1116 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1120 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1121 const struct bus_properties_map
*prop
;
1123 const char *contents
;
1127 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1131 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1132 if (streq(map
[i
].member
, member
)) {
1138 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1142 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1146 v
= (uint8_t *)userdata
+ prop
->offset
;
1148 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1150 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1154 r
= sd_bus_message_exit_container(m
);
1158 r
= sd_bus_message_skip(m
, "v");
1163 r
= sd_bus_message_exit_container(m
);
1170 return sd_bus_message_exit_container(m
);
1173 int bus_message_map_properties_changed(
1175 const struct bus_properties_map
*map
,
1179 int r
, invalidated
, i
;
1184 r
= bus_message_map_all_properties(m
, map
, userdata
);
1188 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1193 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1194 for (i
= 0; map
[i
].member
; i
++)
1195 if (streq(map
[i
].member
, member
)) {
1202 r
= sd_bus_message_exit_container(m
);
1209 int bus_map_all_properties(
1211 const char *destination
,
1213 const struct bus_properties_map
*map
,
1216 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1217 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1221 assert(destination
);
1225 r
= sd_bus_call_method(
1229 "org.freedesktop.DBus.Properties",
1237 return bus_message_map_all_properties(m
, map
, userdata
);
1240 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1243 assert(transport
>= 0);
1244 assert(transport
< _BUS_TRANSPORT_MAX
);
1247 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1248 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1250 switch (transport
) {
1252 case BUS_TRANSPORT_LOCAL
:
1254 r
= sd_bus_default_user(bus
);
1256 r
= sd_bus_default_system(bus
);
1260 case BUS_TRANSPORT_REMOTE
:
1261 r
= sd_bus_open_system_remote(bus
, host
);
1264 case BUS_TRANSPORT_MACHINE
:
1265 r
= sd_bus_open_system_machine(bus
, host
);
1269 assert_not_reached("Hmm, unknown transport type.");
1275 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1278 assert(transport
>= 0);
1279 assert(transport
< _BUS_TRANSPORT_MAX
);
1282 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1283 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1285 switch (transport
) {
1287 case BUS_TRANSPORT_LOCAL
:
1289 r
= bus_connect_user_systemd(bus
);
1291 r
= bus_connect_system_systemd(bus
);
1295 case BUS_TRANSPORT_REMOTE
:
1296 r
= sd_bus_open_system_remote(bus
, host
);
1299 case BUS_TRANSPORT_MACHINE
:
1300 r
= sd_bus_open_system_machine(bus
, host
);
1304 assert_not_reached("Hmm, unknown transport type.");
1310 int bus_property_get_bool(
1313 const char *interface
,
1314 const char *property
,
1315 sd_bus_message
*reply
,
1317 sd_bus_error
*error
) {
1319 int b
= *(bool*) userdata
;
1321 return sd_bus_message_append_basic(reply
, 'b', &b
);
1324 #if __SIZEOF_SIZE_T__ != 8
1325 int bus_property_get_size(
1328 const char *interface
,
1329 const char *property
,
1330 sd_bus_message
*reply
,
1332 sd_bus_error
*error
) {
1334 uint64_t sz
= *(size_t*) userdata
;
1336 return sd_bus_message_append_basic(reply
, 't', &sz
);
1340 #if __SIZEOF_LONG__ != 8
1341 int bus_property_get_long(
1344 const char *interface
,
1345 const char *property
,
1346 sd_bus_message
*reply
,
1348 sd_bus_error
*error
) {
1350 int64_t l
= *(long*) userdata
;
1352 return sd_bus_message_append_basic(reply
, 'x', &l
);
1355 int bus_property_get_ulong(
1358 const char *interface
,
1359 const char *property
,
1360 sd_bus_message
*reply
,
1362 sd_bus_error
*error
) {
1364 uint64_t ul
= *(unsigned long*) userdata
;
1366 return sd_bus_message_append_basic(reply
, 't', &ul
);
1370 int bus_log_parse_error(int r
) {
1371 return log_error_errno(r
, "Failed to parse bus message: %m");
1374 int bus_log_create_error(int r
) {
1375 return log_error_errno(r
, "Failed to create bus message: %m");
1378 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1384 return sd_bus_message_read(
1399 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1400 const char *eq
, *field
;
1406 eq
= strchr(assignment
, '=');
1408 log_error("Not an assignment: %s", assignment
);
1412 field
= strndupa(assignment
, eq
- assignment
);
1415 if (streq(field
, "CPUQuota")) {
1419 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1421 return bus_log_create_error(r
);
1423 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1425 } else if (endswith(eq
, "%")) {
1428 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1429 log_error("CPU quota '%s' invalid.", eq
);
1433 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1435 return bus_log_create_error(r
);
1437 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1439 log_error("CPU quota needs to be in percent.");
1444 return bus_log_create_error(r
);
1448 } else if (streq(field
, "EnvironmentFile")) {
1450 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1452 return bus_log_create_error(r
);
1454 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1455 eq
[0] == '-' ? eq
+ 1 : eq
,
1458 return bus_log_create_error(r
);
1462 } else if (streq(field
, "RandomizedDelaySec")) {
1465 r
= parse_sec(eq
, &t
);
1467 return log_error_errno(r
, "Failed to parse RandomizedDelaySec= parameter: %s", eq
);
1469 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "RandomizedDelayUSec");
1471 return bus_log_create_error(r
);
1473 r
= sd_bus_message_append(m
, "v", "t", t
);
1475 return bus_log_create_error(r
);
1480 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1482 return bus_log_create_error(r
);
1484 if (STR_IN_SET(field
,
1485 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1486 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1487 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1488 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1489 "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
1491 r
= parse_boolean(eq
);
1493 return log_error_errno(r
, "Failed to parse boolean assignment %s.", assignment
);
1495 r
= sd_bus_message_append(m
, "v", "b", r
);
1497 } else if (streq(field
, "MemoryLimit")) {
1500 if (isempty(eq
) || streq(eq
, "infinity"))
1501 bytes
= (uint64_t) -1;
1503 r
= parse_size(eq
, 1024, &bytes
);
1505 log_error("Failed to parse bytes specification %s", assignment
);
1510 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1512 } else if (streq(field
, "TasksMax")) {
1515 if (isempty(eq
) || streq(eq
, "infinity"))
1518 r
= safe_atou64(eq
, &n
);
1520 log_error("Failed to parse maximum tasks specification %s", assignment
);
1525 r
= sd_bus_message_append(m
, "v", "t", n
);
1527 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1530 r
= cg_cpu_shares_parse(eq
, &u
);
1532 log_error("Failed to parse %s value %s.", field
, eq
);
1536 r
= sd_bus_message_append(m
, "v", "t", u
);
1538 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1541 r
= cg_cpu_shares_parse(eq
, &u
);
1543 log_error("Failed to parse %s value %s.", field
, eq
);
1547 r
= sd_bus_message_append(m
, "v", "t", u
);
1549 } else if (STR_IN_SET(field
,
1550 "User", "Group", "DevicePolicy", "KillMode",
1551 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1552 "StandardInput", "StandardOutput", "StandardError",
1553 "Description", "Slice", "Type", "WorkingDirectory",
1554 "RootDirectory", "SyslogIdentifier", "ProtectSystem",
1556 r
= sd_bus_message_append(m
, "v", "s", eq
);
1558 else if (streq(field
, "SyslogLevel")) {
1561 level
= log_level_from_string(eq
);
1563 log_error("Failed to parse %s value %s.", field
, eq
);
1567 r
= sd_bus_message_append(m
, "v", "i", level
);
1569 } else if (streq(field
, "SyslogFacility")) {
1572 facility
= log_facility_unshifted_from_string(eq
);
1574 log_error("Failed to parse %s value %s.", field
, eq
);
1578 r
= sd_bus_message_append(m
, "v", "i", facility
);
1580 } else if (streq(field
, "DeviceAllow")) {
1583 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1585 const char *path
, *rwm
, *e
;
1587 e
= strchr(eq
, ' ');
1589 path
= strndupa(eq
, e
- eq
);
1596 if (!path_startswith(path
, "/dev")) {
1597 log_error("%s is not a device file in /dev.", path
);
1601 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1604 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1607 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1609 const char *path
, *bandwidth
, *e
;
1612 e
= strchr(eq
, ' ');
1614 path
= strndupa(eq
, e
- eq
);
1617 log_error("Failed to parse %s value %s.", field
, eq
);
1621 if (!path_startswith(path
, "/dev")) {
1622 log_error("%s is not a device file in /dev.", path
);
1626 r
= parse_size(bandwidth
, 1000, &bytes
);
1628 log_error("Failed to parse byte value %s.", bandwidth
);
1632 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1635 } else if (streq(field
, "BlockIODeviceWeight")) {
1638 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1640 const char *path
, *weight
, *e
;
1643 e
= strchr(eq
, ' ');
1645 path
= strndupa(eq
, e
- eq
);
1648 log_error("Failed to parse %s value %s.", field
, eq
);
1652 if (!path_startswith(path
, "/dev")) {
1653 log_error("%s is not a device file in /dev.", path
);
1657 r
= safe_atou64(weight
, &u
);
1659 log_error("Failed to parse %s value %s.", field
, weight
);
1662 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1665 } else if (rlimit_from_string(field
) >= 0) {
1668 if (streq(eq
, "infinity"))
1671 r
= safe_atou64(eq
, &rl
);
1673 log_error("Invalid resource limit: %s", eq
);
1678 r
= sd_bus_message_append(m
, "v", "t", rl
);
1680 } else if (streq(field
, "Nice")) {
1683 r
= safe_atoi32(eq
, &i
);
1685 log_error("Failed to parse %s value %s.", field
, eq
);
1689 r
= sd_bus_message_append(m
, "v", "i", i
);
1691 } else if (STR_IN_SET(field
, "Environment", "PassEnvironment")) {
1694 r
= sd_bus_message_open_container(m
, 'v', "as");
1696 return bus_log_create_error(r
);
1698 r
= sd_bus_message_open_container(m
, 'a', "s");
1700 return bus_log_create_error(r
);
1705 _cleanup_free_
char *word
= NULL
;
1707 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1709 log_error("Failed to parse Environment value %s", eq
);
1715 if (streq(field
, "Environment")) {
1716 if (!env_assignment_is_valid(word
)) {
1717 log_error("Invalid environment assignment: %s", word
);
1720 } else { /* PassEnvironment */
1721 if (!env_name_is_valid(word
)) {
1722 log_error("Invalid environment variable name: %s", word
);
1727 r
= sd_bus_message_append_basic(m
, 's', word
);
1729 return bus_log_create_error(r
);
1732 r
= sd_bus_message_close_container(m
);
1734 return bus_log_create_error(r
);
1736 r
= sd_bus_message_close_container(m
);
1738 } else if (streq(field
, "KillSignal")) {
1741 sig
= signal_from_string_try_harder(eq
);
1743 log_error("Failed to parse %s value %s.", field
, eq
);
1747 r
= sd_bus_message_append(m
, "v", "i", sig
);
1749 } else if (streq(field
, "AccuracySec")) {
1752 r
= parse_sec(eq
, &u
);
1754 log_error("Failed to parse %s value %s", field
, eq
);
1758 r
= sd_bus_message_append(m
, "v", "t", u
);
1759 } else if (streq(field
, "TimerSlackNSec")) {
1762 r
= parse_nsec(eq
, &n
);
1764 log_error("Failed to parse %s value %s", field
, eq
);
1768 r
= sd_bus_message_append(m
, "v", "t", n
);
1769 } else if (streq(field
, "OOMScoreAdjust")) {
1772 r
= safe_atoi(eq
, &oa
);
1774 log_error("Failed to parse %s value %s", field
, eq
);
1778 if (!oom_score_adjust_is_valid(oa
)) {
1779 log_error("OOM score adjust value out of range");
1783 r
= sd_bus_message_append(m
, "v", "i", oa
);
1784 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1787 r
= sd_bus_message_open_container(m
, 'v', "as");
1789 return bus_log_create_error(r
);
1791 r
= sd_bus_message_open_container(m
, 'a', "s");
1793 return bus_log_create_error(r
);
1798 _cleanup_free_
char *word
= NULL
;
1801 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1803 log_error("Failed to parse %s value %s", field
, eq
);
1809 if (!utf8_is_valid(word
)) {
1810 log_error("Failed to parse %s value %s", field
, eq
);
1814 offset
= word
[0] == '-';
1815 if (!path_is_absolute(word
+ offset
)) {
1816 log_error("Failed to parse %s value %s", field
, eq
);
1820 path_kill_slashes(word
+ offset
);
1822 r
= sd_bus_message_append_basic(m
, 's', word
);
1824 return bus_log_create_error(r
);
1827 r
= sd_bus_message_close_container(m
);
1829 return bus_log_create_error(r
);
1831 r
= sd_bus_message_close_container(m
);
1833 } else if (streq(field
, "RuntimeDirectory")) {
1836 r
= sd_bus_message_open_container(m
, 'v', "as");
1838 return bus_log_create_error(r
);
1840 r
= sd_bus_message_open_container(m
, 'a', "s");
1842 return bus_log_create_error(r
);
1847 _cleanup_free_
char *word
= NULL
;
1849 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1851 return log_error_errno(r
, "Failed to parse %s value %s", field
, eq
);
1856 r
= sd_bus_message_append_basic(m
, 's', word
);
1858 return bus_log_create_error(r
);
1861 r
= sd_bus_message_close_container(m
);
1863 return bus_log_create_error(r
);
1865 r
= sd_bus_message_close_container(m
);
1868 log_error("Unknown assignment %s.", assignment
);
1873 return bus_log_create_error(r
);
1878 typedef struct BusWaitForJobs
{
1885 sd_bus_slot
*slot_job_removed
;
1886 sd_bus_slot
*slot_disconnected
;
1889 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1892 log_error("Warning! D-Bus connection terminated.");
1893 sd_bus_close(sd_bus_message_get_bus(m
));
1898 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1899 const char *path
, *unit
, *result
;
1900 BusWaitForJobs
*d
= userdata
;
1908 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1910 bus_log_parse_error(r
);
1914 found
= set_remove(d
->jobs
, (char*) path
);
1920 if (!isempty(result
))
1921 d
->result
= strdup(result
);
1924 d
->name
= strdup(unit
);
1929 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1933 set_free_free(d
->jobs
);
1935 sd_bus_slot_unref(d
->slot_disconnected
);
1936 sd_bus_slot_unref(d
->slot_job_removed
);
1938 sd_bus_unref(d
->bus
);
1946 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1947 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1953 d
= new0(BusWaitForJobs
, 1);
1957 d
->bus
= sd_bus_ref(bus
);
1959 /* When we are a bus client we match by sender. Direct
1960 * connections OTOH have no initialized sender field, and
1961 * hence we ignore the sender then */
1962 r
= sd_bus_add_match(
1964 &d
->slot_job_removed
,
1967 "sender='org.freedesktop.systemd1',"
1968 "interface='org.freedesktop.systemd1.Manager',"
1969 "member='JobRemoved',"
1970 "path='/org/freedesktop/systemd1'" :
1972 "interface='org.freedesktop.systemd1.Manager',"
1973 "member='JobRemoved',"
1974 "path='/org/freedesktop/systemd1'",
1975 match_job_removed
, d
);
1979 r
= sd_bus_add_match(
1981 &d
->slot_disconnected
,
1983 "sender='org.freedesktop.DBus.Local',"
1984 "interface='org.freedesktop.DBus.Local',"
1985 "member='Disconnected'",
1986 match_disconnected
, d
);
1996 static int bus_process_wait(sd_bus
*bus
) {
2000 r
= sd_bus_process(bus
, NULL
);
2006 r
= sd_bus_wait(bus
, (uint64_t) -1);
2012 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
2013 _cleanup_free_
char *dbus_path
= NULL
;
2019 dbus_path
= unit_dbus_path_from_name(d
->name
);
2023 return sd_bus_get_property_string(d
->bus
,
2024 "org.freedesktop.systemd1",
2026 "org.freedesktop.systemd1.Service",
2032 static const struct {
2033 const char *result
, *explanation
;
2034 } explanations
[] = {
2035 { "resources", "a configured resource limit was exceeded" },
2036 { "timeout", "a timeout was exceeded" },
2037 { "exit-code", "the control process exited with error code" },
2038 { "signal", "a fatal signal was delivered to the control process" },
2039 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
2040 { "watchdog", "the service failed to send watchdog ping" },
2041 { "start-limit", "start of the service was attempted too often" }
2044 static void log_job_error_with_service_result(const char* service
, const char *result
) {
2045 _cleanup_free_
char *service_shell_quoted
= NULL
;
2049 service_shell_quoted
= shell_maybe_quote(service
);
2051 if (!isempty(result
)) {
2054 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
2055 if (streq(result
, explanations
[i
].result
))
2058 if (i
< ELEMENTSOF(explanations
)) {
2059 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
2061 explanations
[i
].explanation
,
2062 strna(service_shell_quoted
));
2068 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
2070 strna(service_shell_quoted
));
2073 /* For some results maybe additional explanation is required */
2074 if (streq_ptr(result
, "start-limit"))
2075 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
2076 strna(service_shell_quoted
));
2079 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
2085 if (streq(d
->result
, "canceled"))
2086 log_error("Job for %s canceled.", strna(d
->name
));
2087 else if (streq(d
->result
, "timeout"))
2088 log_error("Job for %s timed out.", strna(d
->name
));
2089 else if (streq(d
->result
, "dependency"))
2090 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2091 else if (streq(d
->result
, "invalid"))
2092 log_error("Job for %s invalid.", strna(d
->name
));
2093 else if (streq(d
->result
, "assert"))
2094 log_error("Assertion failed on job for %s.", strna(d
->name
));
2095 else if (streq(d
->result
, "unsupported"))
2096 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2097 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2100 _cleanup_free_
char *result
= NULL
;
2102 q
= bus_job_get_service_result(d
, &result
);
2104 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2106 log_job_error_with_service_result(d
->name
, result
);
2108 log_error("Job failed. See \"journalctl -xe\" for details.");
2112 if (streq(d
->result
, "canceled"))
2114 else if (streq(d
->result
, "timeout"))
2116 else if (streq(d
->result
, "dependency"))
2118 else if (streq(d
->result
, "invalid"))
2120 else if (streq(d
->result
, "assert"))
2122 else if (streq(d
->result
, "unsupported"))
2124 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2130 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2135 while (!set_isempty(d
->jobs
)) {
2138 q
= bus_process_wait(d
->bus
);
2140 return log_error_errno(q
, "Failed to wait for response: %m");
2143 q
= check_wait_response(d
, quiet
);
2144 /* Return the first error as it is most likely to be
2146 if (q
< 0 && r
== 0)
2149 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2152 d
->name
= mfree(d
->name
);
2153 d
->result
= mfree(d
->result
);
2159 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2164 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2168 return set_put_strdup(d
->jobs
, path
);
2171 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2174 r
= bus_wait_for_jobs_add(d
, path
);
2178 return bus_wait_for_jobs(d
, quiet
);
2181 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2182 const char *type
, *path
, *source
;
2185 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2187 return bus_log_parse_error(r
);
2189 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2191 if (streq(type
, "symlink"))
2192 log_info("Created symlink from %s to %s.", path
, source
);
2194 log_info("Removed symlink %s.", path
);
2197 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2202 return bus_log_parse_error(r
);
2204 r
= sd_bus_message_exit_container(m
);
2206 return bus_log_parse_error(r
);
2212 * bus_path_encode_unique() - encode unique object path
2213 * @b: bus connection or NULL
2214 * @prefix: object path prefix
2215 * @sender_id: unique-name of client, or NULL
2216 * @external_id: external ID to be chosen by client, or NULL
2217 * @ret_path: storage for encoded object path pointer
2219 * Whenever we provide a bus API that allows clients to create and manage
2220 * server-side objects, we need to provide a unique name for these objects. If
2221 * we let the server choose the name, we suffer from a race condition: If a
2222 * client creates an object asynchronously, it cannot destroy that object until
2223 * it received the method reply. It cannot know the name of the new object,
2224 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2226 * Therefore, many APIs allow the client to choose the unique name for newly
2227 * created objects. There're two problems to solve, though:
2228 * 1) Object names are usually defined via dbus object paths, which are
2229 * usually globally namespaced. Therefore, multiple clients must be able
2230 * to choose unique object names without interference.
2231 * 2) If multiple libraries share the same bus connection, they must be
2232 * able to choose unique object names without interference.
2233 * The first problem is solved easily by prefixing a name with the
2234 * unique-bus-name of a connection. The server side must enforce this and
2235 * reject any other name. The second problem is solved by providing unique
2236 * suffixes from within sd-bus.
2238 * This helper allows clients to create unique object-paths. It uses the
2239 * template '/prefix/sender_id/external_id' and returns the new path in
2240 * @ret_path (must be freed by the caller).
2241 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2242 * NULL, this function allocates a unique suffix via @b (by requesting a new
2243 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2246 * Returns: 0 on success, negative error code on failure.
2248 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2249 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2250 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2253 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2254 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2255 assert_return(ret_path
, -EINVAL
);
2258 r
= sd_bus_get_unique_name(b
, &sender_id
);
2264 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2265 external_id
= external_buf
;
2268 sender_label
= bus_label_escape(sender_id
);
2272 external_label
= bus_label_escape(external_id
);
2273 if (!external_label
)
2276 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2285 * bus_path_decode_unique() - decode unique object path
2286 * @path: object path to decode
2287 * @prefix: object path prefix
2288 * @ret_sender: output parameter for sender-id label
2289 * @ret_external: output parameter for external-id label
2291 * This does the reverse of bus_path_encode_unique() (see its description for
2292 * details). Both trailing labels, sender-id and external-id, are unescaped and
2293 * returned in the given output parameters (the caller must free them).
2295 * Note that this function returns 0 if the path does not match the template
2296 * (see bus_path_encode_unique()), 1 if it matched.
2298 * Returns: Negative error code on failure, 0 if the given object path does not
2299 * match the template (return parameters are set to NULL), 1 if it was
2300 * parsed successfully (return parameters contain allocated labels).
2302 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2304 char *sender
, *external
;
2306 assert(object_path_is_valid(path
));
2307 assert(object_path_is_valid(prefix
));
2309 assert(ret_external
);
2311 p
= object_path_startswith(path
, prefix
);
2314 *ret_external
= NULL
;
2321 *ret_external
= NULL
;
2325 sender
= bus_label_unescape_n(p
, q
- p
);
2326 external
= bus_label_unescape(q
+ 1);
2327 if (!sender
|| !external
) {
2333 *ret_sender
= sender
;
2334 *ret_external
= external
;
2338 bool is_kdbus_wanted(void) {
2339 _cleanup_free_
char *value
= NULL
;
2341 const bool configured
= true;
2343 const bool configured
= false;
2348 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2351 r
= get_proc_cmdline_key("kdbus=", &value
);
2355 return parse_boolean(value
) == 1;
2358 bool is_kdbus_available(void) {
2359 _cleanup_close_
int fd
= -1;
2360 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2362 if (!is_kdbus_wanted())
2365 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2369 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2372 int bus_property_get_rlimit(
2375 const char *interface
,
2376 const char *property
,
2377 sd_bus_message
*reply
,
2379 sd_bus_error
*error
) {
2389 rl
= *(struct rlimit
**) userdata
;
2393 struct rlimit buf
= {};
2396 z
= rlimit_from_string(strstr(property
, "Limit"));
2403 /* rlim_t might have different sizes, let's map
2404 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2406 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2408 return sd_bus_message_append(reply
, "t", u
);