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
, const char *extra_args
) {
2045 _cleanup_free_
char *service_shell_quoted
= NULL
, *systemctl_extra_args
= NULL
;
2049 service_shell_quoted
= shell_maybe_quote(service
);
2051 systemctl_extra_args
= strjoin("systemctl ", extra_args
, " ", NULL
);
2052 if (!systemctl_extra_args
) {
2057 systemctl_extra_args
= strstrip(systemctl_extra_args
);
2059 if (!isempty(result
)) {
2062 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
2063 if (streq(result
, explanations
[i
].result
))
2066 if (i
< ELEMENTSOF(explanations
)) {
2067 log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
2069 explanations
[i
].explanation
,
2070 systemctl_extra_args
,
2071 strna(service_shell_quoted
));
2077 log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
2079 systemctl_extra_args
,
2080 strna(service_shell_quoted
));
2083 /* For some results maybe additional explanation is required */
2084 if (streq_ptr(result
, "start-limit"))
2085 log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.",
2086 systemctl_extra_args
,
2087 strna(service_shell_quoted
));
2090 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char *extra_args
) {
2096 if (streq(d
->result
, "canceled"))
2097 log_error("Job for %s canceled.", strna(d
->name
));
2098 else if (streq(d
->result
, "timeout"))
2099 log_error("Job for %s timed out.", strna(d
->name
));
2100 else if (streq(d
->result
, "dependency"))
2101 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2102 else if (streq(d
->result
, "invalid"))
2103 log_error("Job for %s invalid.", strna(d
->name
));
2104 else if (streq(d
->result
, "assert"))
2105 log_error("Assertion failed on job for %s.", strna(d
->name
));
2106 else if (streq(d
->result
, "unsupported"))
2107 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2108 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2111 _cleanup_free_
char *result
= NULL
;
2113 q
= bus_job_get_service_result(d
, &result
);
2115 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2117 log_job_error_with_service_result(d
->name
, result
, extra_args
);
2119 log_error("Job failed. See \"journalctl -xe\" for details.");
2123 if (streq(d
->result
, "canceled"))
2125 else if (streq(d
->result
, "timeout"))
2127 else if (streq(d
->result
, "dependency"))
2129 else if (streq(d
->result
, "invalid"))
2131 else if (streq(d
->result
, "assert"))
2133 else if (streq(d
->result
, "unsupported"))
2135 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2141 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char *extra_args
) {
2146 while (!set_isempty(d
->jobs
)) {
2149 q
= bus_process_wait(d
->bus
);
2151 return log_error_errno(q
, "Failed to wait for response: %m");
2154 q
= check_wait_response(d
, quiet
, extra_args
);
2155 /* Return the first error as it is most likely to be
2157 if (q
< 0 && r
== 0)
2160 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2163 d
->name
= mfree(d
->name
);
2164 d
->result
= mfree(d
->result
);
2170 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2175 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2179 return set_put_strdup(d
->jobs
, path
);
2182 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2185 r
= bus_wait_for_jobs_add(d
, path
);
2189 return bus_wait_for_jobs(d
, quiet
, NULL
);
2192 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2193 const char *type
, *path
, *source
;
2196 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2198 return bus_log_parse_error(r
);
2200 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2202 if (streq(type
, "symlink"))
2203 log_info("Created symlink from %s to %s.", path
, source
);
2205 log_info("Removed symlink %s.", path
);
2208 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2213 return bus_log_parse_error(r
);
2215 r
= sd_bus_message_exit_container(m
);
2217 return bus_log_parse_error(r
);
2223 * bus_path_encode_unique() - encode unique object path
2224 * @b: bus connection or NULL
2225 * @prefix: object path prefix
2226 * @sender_id: unique-name of client, or NULL
2227 * @external_id: external ID to be chosen by client, or NULL
2228 * @ret_path: storage for encoded object path pointer
2230 * Whenever we provide a bus API that allows clients to create and manage
2231 * server-side objects, we need to provide a unique name for these objects. If
2232 * we let the server choose the name, we suffer from a race condition: If a
2233 * client creates an object asynchronously, it cannot destroy that object until
2234 * it received the method reply. It cannot know the name of the new object,
2235 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2237 * Therefore, many APIs allow the client to choose the unique name for newly
2238 * created objects. There're two problems to solve, though:
2239 * 1) Object names are usually defined via dbus object paths, which are
2240 * usually globally namespaced. Therefore, multiple clients must be able
2241 * to choose unique object names without interference.
2242 * 2) If multiple libraries share the same bus connection, they must be
2243 * able to choose unique object names without interference.
2244 * The first problem is solved easily by prefixing a name with the
2245 * unique-bus-name of a connection. The server side must enforce this and
2246 * reject any other name. The second problem is solved by providing unique
2247 * suffixes from within sd-bus.
2249 * This helper allows clients to create unique object-paths. It uses the
2250 * template '/prefix/sender_id/external_id' and returns the new path in
2251 * @ret_path (must be freed by the caller).
2252 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2253 * NULL, this function allocates a unique suffix via @b (by requesting a new
2254 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2257 * Returns: 0 on success, negative error code on failure.
2259 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2260 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2261 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2264 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2265 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2266 assert_return(ret_path
, -EINVAL
);
2269 r
= sd_bus_get_unique_name(b
, &sender_id
);
2275 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2276 external_id
= external_buf
;
2279 sender_label
= bus_label_escape(sender_id
);
2283 external_label
= bus_label_escape(external_id
);
2284 if (!external_label
)
2287 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2296 * bus_path_decode_unique() - decode unique object path
2297 * @path: object path to decode
2298 * @prefix: object path prefix
2299 * @ret_sender: output parameter for sender-id label
2300 * @ret_external: output parameter for external-id label
2302 * This does the reverse of bus_path_encode_unique() (see its description for
2303 * details). Both trailing labels, sender-id and external-id, are unescaped and
2304 * returned in the given output parameters (the caller must free them).
2306 * Note that this function returns 0 if the path does not match the template
2307 * (see bus_path_encode_unique()), 1 if it matched.
2309 * Returns: Negative error code on failure, 0 if the given object path does not
2310 * match the template (return parameters are set to NULL), 1 if it was
2311 * parsed successfully (return parameters contain allocated labels).
2313 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2315 char *sender
, *external
;
2317 assert(object_path_is_valid(path
));
2318 assert(object_path_is_valid(prefix
));
2320 assert(ret_external
);
2322 p
= object_path_startswith(path
, prefix
);
2325 *ret_external
= NULL
;
2332 *ret_external
= NULL
;
2336 sender
= bus_label_unescape_n(p
, q
- p
);
2337 external
= bus_label_unescape(q
+ 1);
2338 if (!sender
|| !external
) {
2344 *ret_sender
= sender
;
2345 *ret_external
= external
;
2349 bool is_kdbus_wanted(void) {
2350 _cleanup_free_
char *value
= NULL
;
2352 const bool configured
= true;
2354 const bool configured
= false;
2359 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2362 r
= get_proc_cmdline_key("kdbus=", &value
);
2366 return parse_boolean(value
) == 1;
2369 bool is_kdbus_available(void) {
2370 _cleanup_close_
int fd
= -1;
2371 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2373 if (!is_kdbus_wanted())
2376 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2380 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2383 int bus_property_get_rlimit(
2386 const char *interface
,
2387 const char *property
,
2388 sd_bus_message
*reply
,
2390 sd_bus_error
*error
) {
2395 const char *is_soft
;
2401 is_soft
= endswith(property
, "Soft");
2402 rl
= *(struct rlimit
**) userdata
;
2404 x
= is_soft
? rl
->rlim_cur
: rl
->rlim_max
;
2406 struct rlimit buf
= {};
2410 s
= is_soft
? strndupa(property
, is_soft
- property
) : property
;
2412 z
= rlimit_from_string(strstr(s
, "Limit"));
2416 x
= is_soft
? buf
.rlim_cur
: buf
.rlim_max
;
2419 /* rlim_t might have different sizes, let's map
2420 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2422 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2424 return sd_bus_message_append(reply
, "t", u
);