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 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1414 return bus_log_create_error(r
);
1416 field
= strndupa(assignment
, eq
- assignment
);
1419 if (streq(field
, "CPUQuota")) {
1422 r
= sd_bus_message_append(m
, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
1423 else if (endswith(eq
, "%")) {
1426 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1427 log_error("CPU quota '%s' invalid.", eq
);
1431 r
= sd_bus_message_append(m
, "sv", "CPUQuotaPerSecUSec", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1433 log_error("CPU quota needs to be in percent.");
1439 } else if (streq(field
, "EnvironmentFile")) {
1441 r
= sd_bus_message_append(m
, "sv", "EnvironmentFiles", "a(sb)", 1,
1442 eq
[0] == '-' ? eq
+ 1 : eq
,
1446 } else if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
1450 r
= parse_sec(eq
, &t
);
1452 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1455 n
= newa(char, l
+ 2);
1459 /* Change suffix Sec → USec */
1460 strcpy(mempcpy(n
, field
, l
- 3), "USec");
1461 r
= sd_bus_message_append(m
, "sv", n
, "t", t
);
1465 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1467 return bus_log_create_error(r
);
1469 rl
= rlimit_from_string(field
);
1474 r
= rlimit_parse(rl
, eq
, &l
);
1476 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1478 r
= sd_bus_message_append(m
, "v", "t", l
.rlim_max
);
1480 return bus_log_create_error(r
);
1482 r
= sd_bus_message_close_container(m
);
1484 return bus_log_create_error(r
);
1486 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1488 return bus_log_create_error(r
);
1490 sn
= strjoina(field
, "Soft");
1491 r
= sd_bus_message_append(m
, "sv", sn
, "t", l
.rlim_cur
);
1493 } else if (STR_IN_SET(field
,
1494 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1495 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1496 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1497 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1498 "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
1500 r
= parse_boolean(eq
);
1502 return log_error_errno(r
, "Failed to parse boolean assignment %s.", assignment
);
1504 r
= sd_bus_message_append(m
, "v", "b", r
);
1506 } else if (streq(field
, "MemoryLimit")) {
1509 if (isempty(eq
) || streq(eq
, "infinity"))
1510 bytes
= (uint64_t) -1;
1512 r
= parse_size(eq
, 1024, &bytes
);
1514 log_error("Failed to parse bytes specification %s", assignment
);
1519 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1521 } else if (streq(field
, "TasksMax")) {
1524 if (isempty(eq
) || streq(eq
, "infinity"))
1527 r
= safe_atou64(eq
, &n
);
1529 log_error("Failed to parse maximum tasks specification %s", assignment
);
1534 r
= sd_bus_message_append(m
, "v", "t", n
);
1536 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1539 r
= cg_cpu_shares_parse(eq
, &u
);
1541 log_error("Failed to parse %s value %s.", field
, eq
);
1545 r
= sd_bus_message_append(m
, "v", "t", u
);
1547 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1550 r
= cg_cpu_shares_parse(eq
, &u
);
1552 log_error("Failed to parse %s value %s.", field
, eq
);
1556 r
= sd_bus_message_append(m
, "v", "t", u
);
1558 } else if (STR_IN_SET(field
,
1559 "User", "Group", "DevicePolicy", "KillMode",
1560 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1561 "StandardInput", "StandardOutput", "StandardError",
1562 "Description", "Slice", "Type", "WorkingDirectory",
1563 "RootDirectory", "SyslogIdentifier", "ProtectSystem",
1565 r
= sd_bus_message_append(m
, "v", "s", eq
);
1567 else if (streq(field
, "SyslogLevel")) {
1570 level
= log_level_from_string(eq
);
1572 log_error("Failed to parse %s value %s.", field
, eq
);
1576 r
= sd_bus_message_append(m
, "v", "i", level
);
1578 } else if (streq(field
, "SyslogFacility")) {
1581 facility
= log_facility_unshifted_from_string(eq
);
1583 log_error("Failed to parse %s value %s.", field
, eq
);
1587 r
= sd_bus_message_append(m
, "v", "i", facility
);
1589 } else if (streq(field
, "DeviceAllow")) {
1592 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1594 const char *path
, *rwm
, *e
;
1596 e
= strchr(eq
, ' ');
1598 path
= strndupa(eq
, e
- eq
);
1605 if (!path_startswith(path
, "/dev")) {
1606 log_error("%s is not a device file in /dev.", path
);
1610 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1613 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1616 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1618 const char *path
, *bandwidth
, *e
;
1621 e
= strchr(eq
, ' ');
1623 path
= strndupa(eq
, e
- eq
);
1626 log_error("Failed to parse %s value %s.", field
, eq
);
1630 if (!path_startswith(path
, "/dev")) {
1631 log_error("%s is not a device file in /dev.", path
);
1635 r
= parse_size(bandwidth
, 1000, &bytes
);
1637 log_error("Failed to parse byte value %s.", bandwidth
);
1641 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1644 } else if (streq(field
, "BlockIODeviceWeight")) {
1647 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1649 const char *path
, *weight
, *e
;
1652 e
= strchr(eq
, ' ');
1654 path
= strndupa(eq
, e
- eq
);
1657 log_error("Failed to parse %s value %s.", field
, eq
);
1661 if (!path_startswith(path
, "/dev")) {
1662 log_error("%s is not a device file in /dev.", path
);
1666 r
= safe_atou64(weight
, &u
);
1668 log_error("Failed to parse %s value %s.", field
, weight
);
1671 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1674 } else if (streq(field
, "Nice")) {
1677 r
= safe_atoi32(eq
, &i
);
1679 log_error("Failed to parse %s value %s.", field
, eq
);
1683 r
= sd_bus_message_append(m
, "v", "i", i
);
1685 } else if (STR_IN_SET(field
, "Environment", "PassEnvironment")) {
1688 r
= sd_bus_message_open_container(m
, 'v', "as");
1690 return bus_log_create_error(r
);
1692 r
= sd_bus_message_open_container(m
, 'a', "s");
1694 return bus_log_create_error(r
);
1699 _cleanup_free_
char *word
= NULL
;
1701 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1703 log_error("Failed to parse Environment value %s", eq
);
1709 if (streq(field
, "Environment")) {
1710 if (!env_assignment_is_valid(word
)) {
1711 log_error("Invalid environment assignment: %s", word
);
1714 } else { /* PassEnvironment */
1715 if (!env_name_is_valid(word
)) {
1716 log_error("Invalid environment variable name: %s", word
);
1721 r
= sd_bus_message_append_basic(m
, 's', word
);
1723 return bus_log_create_error(r
);
1726 r
= sd_bus_message_close_container(m
);
1728 return bus_log_create_error(r
);
1730 r
= sd_bus_message_close_container(m
);
1732 } else if (streq(field
, "KillSignal")) {
1735 sig
= signal_from_string_try_harder(eq
);
1737 log_error("Failed to parse %s value %s.", field
, eq
);
1741 r
= sd_bus_message_append(m
, "v", "i", sig
);
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
);
1858 return bus_log_create_error(r
);
1860 r
= sd_bus_message_close_container(m
);
1862 return bus_log_create_error(r
);
1867 typedef struct BusWaitForJobs
{
1874 sd_bus_slot
*slot_job_removed
;
1875 sd_bus_slot
*slot_disconnected
;
1878 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1881 log_error("Warning! D-Bus connection terminated.");
1882 sd_bus_close(sd_bus_message_get_bus(m
));
1887 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1888 const char *path
, *unit
, *result
;
1889 BusWaitForJobs
*d
= userdata
;
1897 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1899 bus_log_parse_error(r
);
1903 found
= set_remove(d
->jobs
, (char*) path
);
1909 if (!isempty(result
))
1910 d
->result
= strdup(result
);
1913 d
->name
= strdup(unit
);
1918 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1922 set_free_free(d
->jobs
);
1924 sd_bus_slot_unref(d
->slot_disconnected
);
1925 sd_bus_slot_unref(d
->slot_job_removed
);
1927 sd_bus_unref(d
->bus
);
1935 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1936 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1942 d
= new0(BusWaitForJobs
, 1);
1946 d
->bus
= sd_bus_ref(bus
);
1948 /* When we are a bus client we match by sender. Direct
1949 * connections OTOH have no initialized sender field, and
1950 * hence we ignore the sender then */
1951 r
= sd_bus_add_match(
1953 &d
->slot_job_removed
,
1956 "sender='org.freedesktop.systemd1',"
1957 "interface='org.freedesktop.systemd1.Manager',"
1958 "member='JobRemoved',"
1959 "path='/org/freedesktop/systemd1'" :
1961 "interface='org.freedesktop.systemd1.Manager',"
1962 "member='JobRemoved',"
1963 "path='/org/freedesktop/systemd1'",
1964 match_job_removed
, d
);
1968 r
= sd_bus_add_match(
1970 &d
->slot_disconnected
,
1972 "sender='org.freedesktop.DBus.Local',"
1973 "interface='org.freedesktop.DBus.Local',"
1974 "member='Disconnected'",
1975 match_disconnected
, d
);
1985 static int bus_process_wait(sd_bus
*bus
) {
1989 r
= sd_bus_process(bus
, NULL
);
1995 r
= sd_bus_wait(bus
, (uint64_t) -1);
2001 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
2002 _cleanup_free_
char *dbus_path
= NULL
;
2008 dbus_path
= unit_dbus_path_from_name(d
->name
);
2012 return sd_bus_get_property_string(d
->bus
,
2013 "org.freedesktop.systemd1",
2015 "org.freedesktop.systemd1.Service",
2021 static const struct {
2022 const char *result
, *explanation
;
2023 } explanations
[] = {
2024 { "resources", "a configured resource limit was exceeded" },
2025 { "timeout", "a timeout was exceeded" },
2026 { "exit-code", "the control process exited with error code" },
2027 { "signal", "a fatal signal was delivered to the control process" },
2028 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
2029 { "watchdog", "the service failed to send watchdog ping" },
2030 { "start-limit", "start of the service was attempted too often" }
2033 static void log_job_error_with_service_result(const char* service
, const char *result
, const char *extra_args
) {
2034 _cleanup_free_
char *service_shell_quoted
= NULL
, *systemctl_extra_args
= NULL
;
2038 service_shell_quoted
= shell_maybe_quote(service
);
2040 systemctl_extra_args
= strjoin("systemctl ", extra_args
, " ", NULL
);
2041 if (!systemctl_extra_args
) {
2046 systemctl_extra_args
= strstrip(systemctl_extra_args
);
2048 if (!isempty(result
)) {
2051 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
2052 if (streq(result
, explanations
[i
].result
))
2055 if (i
< ELEMENTSOF(explanations
)) {
2056 log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
2058 explanations
[i
].explanation
,
2059 systemctl_extra_args
,
2060 strna(service_shell_quoted
));
2066 log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
2068 systemctl_extra_args
,
2069 strna(service_shell_quoted
));
2072 /* For some results maybe additional explanation is required */
2073 if (streq_ptr(result
, "start-limit"))
2074 log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.",
2075 systemctl_extra_args
,
2076 strna(service_shell_quoted
));
2079 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char *extra_args
) {
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("%s is not active, cannot reload.", 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
, extra_args
);
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
, const char *extra_args
) {
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
, extra_args
);
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
, NULL
);
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
) {
2384 const char *is_soft
;
2390 is_soft
= endswith(property
, "Soft");
2391 rl
= *(struct rlimit
**) userdata
;
2393 x
= is_soft
? rl
->rlim_cur
: rl
->rlim_max
;
2395 struct rlimit buf
= {};
2399 s
= is_soft
? strndupa(property
, is_soft
- property
) : property
;
2401 z
= rlimit_from_string(strstr(s
, "Limit"));
2405 x
= is_soft
? buf
.rlim_cur
: buf
.rlim_max
;
2408 /* rlim_t might have different sizes, let's map
2409 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2411 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2413 return sd_bus_message_append(reply
, "t", u
);