1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
25 #include "sd-daemon.h"
28 #include "bus-error.h"
29 #include "bus-internal.h"
30 #include "bus-label.h"
31 #include "bus-message.h"
33 #include "cgroup-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "rlimit-util.h"
44 #include "signal-util.h"
45 #include "string-util.h"
47 #include "unit-name.h"
51 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
52 sd_event
*e
= userdata
;
57 sd_bus_close(sd_bus_message_get_bus(m
));
63 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
64 _cleanup_free_
char *match
= NULL
;
72 /* We unregister the name here and then wait for the
73 * NameOwnerChanged signal for this event to arrive before we
74 * quit. We do this in order to make sure that any queued
75 * requests are still processed before we really exit. */
77 r
= sd_bus_get_unique_name(bus
, &unique
);
82 "sender='org.freedesktop.DBus',"
84 "interface='org.freedesktop.DBus',"
85 "member='NameOwnerChanged',"
86 "path='/org/freedesktop/DBus',"
89 "arg2=''", name
, unique
);
93 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
97 r
= sd_bus_release_name(bus
, name
);
104 int bus_event_loop_with_idle(
109 check_idle_t check_idle
,
111 bool exiting
= false;
121 r
= sd_event_get_state(e
);
124 if (r
== SD_EVENT_FINISHED
)
128 idle
= check_idle(userdata
);
132 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
136 if (r
== 0 && !exiting
&& idle
) {
138 r
= sd_bus_try_close(bus
);
142 /* Fallback for dbus1 connections: we
143 * unregister the name and wait for the
144 * response to come through for it */
145 if (r
== -EOPNOTSUPP
) {
147 /* Inform the service manager that we
148 * are going down, so that it will
149 * queue all further start requests,
150 * instead of assuming we are already
152 sd_notify(false, "STOPPING=1");
154 r
= bus_async_unregister_and_exit(e
, bus
, name
);
170 r
= sd_event_get_exit_code(e
, &code
);
177 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
178 _cleanup_bus_message_unref_ sd_bus_message
*rep
= NULL
;
179 int r
, has_owner
= 0;
184 r
= sd_bus_call_method(c
,
185 "org.freedesktop.DBus",
186 "/org/freedesktop/dbus",
187 "org.freedesktop.DBus",
196 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
198 return sd_bus_error_set_errno(error
, r
);
203 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
204 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
210 if (good_user
== UID_INVALID
)
213 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
217 /* Don't trust augmented credentials for authorization */
218 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
220 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
224 return sender_uid
== good_user
;
228 sd_bus_message
*call
,
231 const char **details
,
241 /* Tests non-interactively! */
243 r
= check_good_user(call
, good_user
);
247 r
= sd_bus_query_sender_privilege(call
, capability
);
254 _cleanup_bus_message_unref_ sd_bus_message
*request
= NULL
;
255 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
256 int authorized
= false, challenge
= false;
257 const char *sender
, **k
, **v
;
259 sender
= sd_bus_message_get_sender(call
);
263 r
= sd_bus_message_new_method_call(
266 "org.freedesktop.PolicyKit1",
267 "/org/freedesktop/PolicyKit1/Authority",
268 "org.freedesktop.PolicyKit1.Authority",
269 "CheckAuthorization");
273 r
= sd_bus_message_append(
276 "system-bus-name", 1, "name", "s", sender
,
281 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
285 STRV_FOREACH_PAIR(k
, v
, details
) {
286 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
291 r
= sd_bus_message_close_container(request
);
295 r
= sd_bus_message_append(request
, "us", 0, NULL
);
299 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
301 /* Treat no PK available as access denied */
302 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
303 sd_bus_error_free(e
);
310 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
314 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
322 *_challenge
= challenge
;
333 typedef struct AsyncPolkitQuery
{
334 sd_bus_message
*request
, *reply
;
335 sd_bus_message_handler_t callback
;
341 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
346 sd_bus_slot_unref(q
->slot
);
348 if (q
->registry
&& q
->request
)
349 hashmap_remove(q
->registry
, q
->request
);
351 sd_bus_message_unref(q
->request
);
352 sd_bus_message_unref(q
->reply
);
357 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
358 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
359 AsyncPolkitQuery
*q
= userdata
;
365 q
->slot
= sd_bus_slot_unref(q
->slot
);
366 q
->reply
= sd_bus_message_ref(reply
);
368 r
= sd_bus_message_rewind(q
->request
, true);
370 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
374 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
375 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
378 async_polkit_query_free(q
);
385 int bus_verify_polkit_async(
386 sd_bus_message
*call
,
389 const char **details
,
393 sd_bus_error
*error
) {
396 _cleanup_bus_message_unref_ sd_bus_message
*pk
= NULL
;
398 const char *sender
, **k
, **v
;
399 sd_bus_message_handler_t callback
;
409 r
= check_good_user(call
, good_user
);
414 q
= hashmap_get(*registry
, call
);
416 int authorized
, challenge
;
418 /* This is the second invocation of this function, and
419 * there's already a response from polkit, let's
423 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
424 const sd_bus_error
*e
;
426 /* Copy error from polkit reply */
427 e
= sd_bus_message_get_error(q
->reply
);
428 sd_bus_error_copy(error
, e
);
430 /* Treat no PK available as access denied */
431 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
434 return -sd_bus_error_get_errno(e
);
437 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
439 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
448 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
454 r
= sd_bus_query_sender_privilege(call
, capability
);
461 if (sd_bus_get_current_message(call
->bus
) != call
)
464 callback
= sd_bus_get_current_handler(call
->bus
);
468 userdata
= sd_bus_get_current_userdata(call
->bus
);
470 sender
= sd_bus_message_get_sender(call
);
474 c
= sd_bus_message_get_allow_interactive_authorization(call
);
480 r
= hashmap_ensure_allocated(registry
, NULL
);
484 r
= sd_bus_message_new_method_call(
487 "org.freedesktop.PolicyKit1",
488 "/org/freedesktop/PolicyKit1/Authority",
489 "org.freedesktop.PolicyKit1.Authority",
490 "CheckAuthorization");
494 r
= sd_bus_message_append(
497 "system-bus-name", 1, "name", "s", sender
,
502 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
506 STRV_FOREACH_PAIR(k
, v
, details
) {
507 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
512 r
= sd_bus_message_close_container(pk
);
516 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
520 q
= new0(AsyncPolkitQuery
, 1);
524 q
->request
= sd_bus_message_ref(call
);
525 q
->callback
= callback
;
526 q
->userdata
= userdata
;
528 r
= hashmap_put(*registry
, call
, q
);
530 async_polkit_query_free(q
);
534 q
->registry
= *registry
;
536 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
538 async_polkit_query_free(q
);
548 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
552 while ((q
= hashmap_steal_first(registry
)))
553 async_polkit_query_free(q
);
555 hashmap_free(registry
);
559 int bus_check_peercred(sd_bus
*c
) {
566 fd
= sd_bus_get_fd(c
);
570 l
= sizeof(struct ucred
);
571 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
574 if (l
!= sizeof(struct ucred
))
577 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
583 int bus_connect_system_systemd(sd_bus
**_bus
) {
584 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
590 return sd_bus_default_system(_bus
);
592 /* If we are root and kdbus is not available, then let's talk
593 * directly to the system instance, instead of going via the
596 r
= sd_bus_new(&bus
);
600 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
604 bus
->bus_client
= true;
606 r
= sd_bus_start(bus
);
613 bus
= sd_bus_unref(bus
);
615 r
= sd_bus_new(&bus
);
619 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
623 r
= sd_bus_start(bus
);
625 return sd_bus_default_system(_bus
);
627 r
= bus_check_peercred(bus
);
637 int bus_connect_user_systemd(sd_bus
**_bus
) {
638 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
639 _cleanup_free_
char *ee
= NULL
;
643 /* Try via kdbus first, and then directly */
647 r
= sd_bus_new(&bus
);
651 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
654 bus
->bus_client
= true;
656 r
= sd_bus_start(bus
);
663 bus
= sd_bus_unref(bus
);
665 e
= secure_getenv("XDG_RUNTIME_DIR");
667 return sd_bus_default_user(_bus
);
669 ee
= bus_address_escape(e
);
673 r
= sd_bus_new(&bus
);
677 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
681 r
= sd_bus_start(bus
);
683 return sd_bus_default_user(_bus
);
685 r
= bus_check_peercred(bus
);
695 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
697 const char *contents
;
703 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
709 case SD_BUS_TYPE_STRING
: {
712 r
= sd_bus_message_read_basic(property
, type
, &s
);
716 if (all
|| !isempty(s
)) {
717 _cleanup_free_
char *escaped
= NULL
;
719 escaped
= xescape(s
, "\n");
723 printf("%s=%s\n", name
, escaped
);
729 case SD_BUS_TYPE_BOOLEAN
: {
732 r
= sd_bus_message_read_basic(property
, type
, &b
);
736 printf("%s=%s\n", name
, yes_no(b
));
741 case SD_BUS_TYPE_UINT64
: {
744 r
= sd_bus_message_read_basic(property
, type
, &u
);
748 /* Yes, heuristics! But we can change this check
749 * should it turn out to not be sufficient */
751 if (endswith(name
, "Timestamp")) {
752 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
754 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
756 printf("%s=%s\n", name
, strempty(t
));
758 } else if (strstr(name
, "USec")) {
759 char timespan
[FORMAT_TIMESPAN_MAX
];
761 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
763 printf("%s=%llu\n", name
, (unsigned long long) u
);
768 case SD_BUS_TYPE_INT64
: {
771 r
= sd_bus_message_read_basic(property
, type
, &i
);
775 printf("%s=%lld\n", name
, (long long) i
);
780 case SD_BUS_TYPE_UINT32
: {
783 r
= sd_bus_message_read_basic(property
, type
, &u
);
787 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
788 printf("%s=%04o\n", name
, u
);
790 printf("%s=%u\n", name
, (unsigned) u
);
795 case SD_BUS_TYPE_INT32
: {
798 r
= sd_bus_message_read_basic(property
, type
, &i
);
802 printf("%s=%i\n", name
, (int) i
);
806 case SD_BUS_TYPE_DOUBLE
: {
809 r
= sd_bus_message_read_basic(property
, type
, &d
);
813 printf("%s=%g\n", name
, d
);
817 case SD_BUS_TYPE_ARRAY
:
818 if (streq(contents
, "s")) {
822 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
826 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
827 _cleanup_free_
char *escaped
= NULL
;
832 escaped
= xescape(str
, "\n ");
836 printf("%s%s", first
? "" : " ", escaped
);
848 r
= sd_bus_message_exit_container(property
);
854 } else if (streq(contents
, "y")) {
858 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
867 for (i
= 0; i
< n
; i
++)
868 printf("%02x", u
[i
]);
875 } else if (streq(contents
, "u")) {
879 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
888 for (i
= 0; i
< n
; i
++)
889 printf("%08x", u
[i
]);
903 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
904 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
905 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
911 r
= sd_bus_call_method(bus
,
914 "org.freedesktop.DBus.Properties",
922 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
926 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
928 const char *contents
;
930 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
934 if (!filter
|| strv_find(filter
, name
)) {
935 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
939 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
943 r
= bus_print_property(name
, reply
, all
);
948 printf("%s=[unprintable]\n", name
);
949 /* skip what we didn't read */
950 r
= sd_bus_message_skip(reply
, contents
);
955 r
= sd_bus_message_exit_container(reply
);
959 r
= sd_bus_message_skip(reply
, "v");
964 r
= sd_bus_message_exit_container(reply
);
971 r
= sd_bus_message_exit_container(reply
);
978 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
979 sd_id128_t
*p
= userdata
;
984 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
991 memcpy((*p
).bytes
, v
, n
);
998 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1002 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1007 case SD_BUS_TYPE_STRING
: {
1009 char **p
= userdata
;
1011 r
= sd_bus_message_read_basic(m
, type
, &s
);
1018 r
= free_and_strdup(p
, s
);
1022 case SD_BUS_TYPE_ARRAY
: {
1023 _cleanup_strv_free_
char **l
= NULL
;
1024 char ***p
= userdata
;
1026 r
= bus_message_read_strv_extend(m
, &l
);
1037 case SD_BUS_TYPE_BOOLEAN
: {
1041 r
= sd_bus_message_read_basic(m
, type
, &b
);
1050 case SD_BUS_TYPE_UINT32
: {
1052 uint32_t *p
= userdata
;
1054 r
= sd_bus_message_read_basic(m
, type
, &u
);
1063 case SD_BUS_TYPE_UINT64
: {
1065 uint64_t *p
= userdata
;
1067 r
= sd_bus_message_read_basic(m
, type
, &t
);
1083 int bus_message_map_all_properties(
1085 const struct bus_properties_map
*map
,
1088 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1094 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1098 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1099 const struct bus_properties_map
*prop
;
1101 const char *contents
;
1105 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1109 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1110 if (streq(map
[i
].member
, member
)) {
1116 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1120 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1124 v
= (uint8_t *)userdata
+ prop
->offset
;
1126 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1128 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1132 r
= sd_bus_message_exit_container(m
);
1136 r
= sd_bus_message_skip(m
, "v");
1141 r
= sd_bus_message_exit_container(m
);
1148 return sd_bus_message_exit_container(m
);
1151 int bus_message_map_properties_changed(
1153 const struct bus_properties_map
*map
,
1157 int r
, invalidated
, i
;
1162 r
= bus_message_map_all_properties(m
, map
, userdata
);
1166 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1171 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1172 for (i
= 0; map
[i
].member
; i
++)
1173 if (streq(map
[i
].member
, member
)) {
1180 r
= sd_bus_message_exit_container(m
);
1187 int bus_map_all_properties(
1189 const char *destination
,
1191 const struct bus_properties_map
*map
,
1194 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1195 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1199 assert(destination
);
1203 r
= sd_bus_call_method(
1207 "org.freedesktop.DBus.Properties",
1215 return bus_message_map_all_properties(m
, map
, userdata
);
1218 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1221 assert(transport
>= 0);
1222 assert(transport
< _BUS_TRANSPORT_MAX
);
1225 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1226 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1228 switch (transport
) {
1230 case BUS_TRANSPORT_LOCAL
:
1232 r
= sd_bus_default_user(bus
);
1234 r
= sd_bus_default_system(bus
);
1238 case BUS_TRANSPORT_REMOTE
:
1239 r
= sd_bus_open_system_remote(bus
, host
);
1242 case BUS_TRANSPORT_MACHINE
:
1243 r
= sd_bus_open_system_machine(bus
, host
);
1247 assert_not_reached("Hmm, unknown transport type.");
1253 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1256 assert(transport
>= 0);
1257 assert(transport
< _BUS_TRANSPORT_MAX
);
1260 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1261 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1263 switch (transport
) {
1265 case BUS_TRANSPORT_LOCAL
:
1267 r
= bus_connect_user_systemd(bus
);
1269 r
= bus_connect_system_systemd(bus
);
1273 case BUS_TRANSPORT_REMOTE
:
1274 r
= sd_bus_open_system_remote(bus
, host
);
1277 case BUS_TRANSPORT_MACHINE
:
1278 r
= sd_bus_open_system_machine(bus
, host
);
1282 assert_not_reached("Hmm, unknown transport type.");
1288 int bus_property_get_bool(
1291 const char *interface
,
1292 const char *property
,
1293 sd_bus_message
*reply
,
1295 sd_bus_error
*error
) {
1297 int b
= *(bool*) userdata
;
1299 return sd_bus_message_append_basic(reply
, 'b', &b
);
1302 #if __SIZEOF_SIZE_T__ != 8
1303 int bus_property_get_size(
1306 const char *interface
,
1307 const char *property
,
1308 sd_bus_message
*reply
,
1310 sd_bus_error
*error
) {
1312 uint64_t sz
= *(size_t*) userdata
;
1314 return sd_bus_message_append_basic(reply
, 't', &sz
);
1318 #if __SIZEOF_LONG__ != 8
1319 int bus_property_get_long(
1322 const char *interface
,
1323 const char *property
,
1324 sd_bus_message
*reply
,
1326 sd_bus_error
*error
) {
1328 int64_t l
= *(long*) userdata
;
1330 return sd_bus_message_append_basic(reply
, 'x', &l
);
1333 int bus_property_get_ulong(
1336 const char *interface
,
1337 const char *property
,
1338 sd_bus_message
*reply
,
1340 sd_bus_error
*error
) {
1342 uint64_t ul
= *(unsigned long*) userdata
;
1344 return sd_bus_message_append_basic(reply
, 't', &ul
);
1348 int bus_log_parse_error(int r
) {
1349 return log_error_errno(r
, "Failed to parse bus message: %m");
1352 int bus_log_create_error(int r
) {
1353 return log_error_errno(r
, "Failed to create bus message: %m");
1356 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1362 return sd_bus_message_read(
1377 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1378 const char *eq
, *field
;
1384 eq
= strchr(assignment
, '=');
1386 log_error("Not an assignment: %s", assignment
);
1390 field
= strndupa(assignment
, eq
- assignment
);
1393 if (streq(field
, "CPUQuota")) {
1397 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1399 return bus_log_create_error(r
);
1401 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1403 } else if (endswith(eq
, "%")) {
1406 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1407 log_error("CPU quota '%s' invalid.", eq
);
1411 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1413 return bus_log_create_error(r
);
1415 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1417 log_error("CPU quota needs to be in percent.");
1422 return bus_log_create_error(r
);
1425 } else if (streq(field
, "EnvironmentFile")) {
1426 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1430 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1431 eq
[0] == '-' ? eq
+ 1 : eq
,
1438 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1440 return bus_log_create_error(r
);
1442 if (STR_IN_SET(field
,
1443 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1444 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1445 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1446 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1447 "SyslogLevelPrefix")) {
1449 r
= parse_boolean(eq
);
1451 log_error("Failed to parse boolean assignment %s.", assignment
);
1455 r
= sd_bus_message_append(m
, "v", "b", r
);
1457 } else if (streq(field
, "MemoryLimit")) {
1460 if (isempty(eq
) || streq(eq
, "infinity"))
1461 bytes
= (uint64_t) -1;
1463 r
= parse_size(eq
, 1024, &bytes
);
1465 log_error("Failed to parse bytes specification %s", assignment
);
1470 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1472 } else if (streq(field
, "TasksMax")) {
1475 if (isempty(eq
) || streq(eq
, "infinity"))
1478 r
= safe_atou64(eq
, &n
);
1480 log_error("Failed to parse maximum tasks specification %s", assignment
);
1485 r
= sd_bus_message_append(m
, "v", "t", n
);
1487 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1490 r
= cg_cpu_shares_parse(eq
, &u
);
1492 log_error("Failed to parse %s value %s.", field
, eq
);
1496 r
= sd_bus_message_append(m
, "v", "t", u
);
1498 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1501 r
= cg_cpu_shares_parse(eq
, &u
);
1503 log_error("Failed to parse %s value %s.", field
, eq
);
1507 r
= sd_bus_message_append(m
, "v", "t", u
);
1509 } else if (STR_IN_SET(field
,
1510 "User", "Group", "DevicePolicy", "KillMode",
1511 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1512 "StandardInput", "StandardOutput", "StandardError",
1513 "Description", "Slice", "Type", "WorkingDirectory",
1514 "RootDirectory", "SyslogIdentifier", "ProtectSystem",
1516 r
= sd_bus_message_append(m
, "v", "s", eq
);
1518 else if (streq(field
, "SyslogLevel")) {
1521 level
= log_level_from_string(eq
);
1523 log_error("Failed to parse %s value %s.", field
, eq
);
1527 r
= sd_bus_message_append(m
, "v", "i", level
);
1529 } else if (streq(field
, "SyslogFacility")) {
1532 facility
= log_facility_unshifted_from_string(eq
);
1534 log_error("Failed to parse %s value %s.", field
, eq
);
1538 r
= sd_bus_message_append(m
, "v", "i", facility
);
1540 } else if (streq(field
, "DeviceAllow")) {
1543 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1545 const char *path
, *rwm
, *e
;
1547 e
= strchr(eq
, ' ');
1549 path
= strndupa(eq
, e
- eq
);
1556 if (!path_startswith(path
, "/dev")) {
1557 log_error("%s is not a device file in /dev.", path
);
1561 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1564 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1567 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1569 const char *path
, *bandwidth
, *e
;
1572 e
= strchr(eq
, ' ');
1574 path
= strndupa(eq
, e
- eq
);
1577 log_error("Failed to parse %s value %s.", field
, eq
);
1581 if (!path_startswith(path
, "/dev")) {
1582 log_error("%s is not a device file in /dev.", path
);
1586 r
= parse_size(bandwidth
, 1000, &bytes
);
1588 log_error("Failed to parse byte value %s.", bandwidth
);
1592 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1595 } else if (streq(field
, "BlockIODeviceWeight")) {
1598 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1600 const char *path
, *weight
, *e
;
1603 e
= strchr(eq
, ' ');
1605 path
= strndupa(eq
, e
- eq
);
1608 log_error("Failed to parse %s value %s.", field
, eq
);
1612 if (!path_startswith(path
, "/dev")) {
1613 log_error("%s is not a device file in /dev.", path
);
1617 r
= safe_atou64(weight
, &u
);
1619 log_error("Failed to parse %s value %s.", field
, weight
);
1622 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1625 } else if (rlimit_from_string(field
) >= 0) {
1628 if (streq(eq
, "infinity"))
1631 r
= safe_atou64(eq
, &rl
);
1633 log_error("Invalid resource limit: %s", eq
);
1638 r
= sd_bus_message_append(m
, "v", "t", rl
);
1640 } else if (streq(field
, "Nice")) {
1643 r
= safe_atoi32(eq
, &i
);
1645 log_error("Failed to parse %s value %s.", field
, eq
);
1649 r
= sd_bus_message_append(m
, "v", "i", i
);
1651 } else if (streq(field
, "Environment")) {
1654 r
= sd_bus_message_open_container(m
, 'v', "as");
1656 return bus_log_create_error(r
);
1658 r
= sd_bus_message_open_container(m
, 'a', "s");
1660 return bus_log_create_error(r
);
1665 _cleanup_free_
char *word
= NULL
;
1667 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1669 log_error("Failed to parse Environment value %s", eq
);
1675 if (!env_assignment_is_valid(word
)) {
1676 log_error("Invalid environment assignment: %s", eq
);
1680 r
= sd_bus_message_append_basic(m
, 's', word
);
1682 return bus_log_create_error(r
);
1685 r
= sd_bus_message_close_container(m
);
1687 return bus_log_create_error(r
);
1689 r
= sd_bus_message_close_container(m
);
1691 } else if (streq(field
, "KillSignal")) {
1694 sig
= signal_from_string_try_harder(eq
);
1696 log_error("Failed to parse %s value %s.", field
, eq
);
1700 r
= sd_bus_message_append(m
, "v", "i", sig
);
1702 } else if (streq(field
, "AccuracySec")) {
1705 r
= parse_sec(eq
, &u
);
1707 log_error("Failed to parse %s value %s", field
, eq
);
1711 r
= sd_bus_message_append(m
, "v", "t", u
);
1712 } else if (streq(field
, "TimerSlackNSec")) {
1715 r
= parse_nsec(eq
, &n
);
1717 log_error("Failed to parse %s value %s", field
, eq
);
1721 r
= sd_bus_message_append(m
, "v", "t", n
);
1722 } else if (streq(field
, "OOMScoreAdjust")) {
1725 r
= safe_atoi(eq
, &oa
);
1727 log_error("Failed to parse %s value %s", field
, eq
);
1731 if (!oom_score_adjust_is_valid(oa
)) {
1732 log_error("OOM score adjust value out of range");
1736 r
= sd_bus_message_append(m
, "v", "i", oa
);
1737 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1740 r
= sd_bus_message_open_container(m
, 'v', "as");
1742 return bus_log_create_error(r
);
1744 r
= sd_bus_message_open_container(m
, 'a', "s");
1746 return bus_log_create_error(r
);
1751 _cleanup_free_
char *word
= NULL
;
1754 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1756 log_error("Failed to parse %s value %s", field
, eq
);
1762 if (!utf8_is_valid(word
)) {
1763 log_error("Failed to parse %s value %s", field
, eq
);
1767 offset
= word
[0] == '-';
1768 if (!path_is_absolute(word
+ offset
)) {
1769 log_error("Failed to parse %s value %s", field
, eq
);
1773 path_kill_slashes(word
+ offset
);
1775 r
= sd_bus_message_append_basic(m
, 's', word
);
1777 return bus_log_create_error(r
);
1780 r
= sd_bus_message_close_container(m
);
1782 return bus_log_create_error(r
);
1784 r
= sd_bus_message_close_container(m
);
1787 log_error("Unknown assignment %s.", assignment
);
1792 return bus_log_create_error(r
);
1797 typedef struct BusWaitForJobs
{
1804 sd_bus_slot
*slot_job_removed
;
1805 sd_bus_slot
*slot_disconnected
;
1808 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1811 log_error("Warning! D-Bus connection terminated.");
1812 sd_bus_close(sd_bus_message_get_bus(m
));
1817 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1818 const char *path
, *unit
, *result
;
1819 BusWaitForJobs
*d
= userdata
;
1827 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1829 bus_log_parse_error(r
);
1833 found
= set_remove(d
->jobs
, (char*) path
);
1839 if (!isempty(result
))
1840 d
->result
= strdup(result
);
1843 d
->name
= strdup(unit
);
1848 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1852 set_free_free(d
->jobs
);
1854 sd_bus_slot_unref(d
->slot_disconnected
);
1855 sd_bus_slot_unref(d
->slot_job_removed
);
1857 sd_bus_unref(d
->bus
);
1865 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1866 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1872 d
= new0(BusWaitForJobs
, 1);
1876 d
->bus
= sd_bus_ref(bus
);
1878 /* When we are a bus client we match by sender. Direct
1879 * connections OTOH have no initialized sender field, and
1880 * hence we ignore the sender then */
1881 r
= sd_bus_add_match(
1883 &d
->slot_job_removed
,
1886 "sender='org.freedesktop.systemd1',"
1887 "interface='org.freedesktop.systemd1.Manager',"
1888 "member='JobRemoved',"
1889 "path='/org/freedesktop/systemd1'" :
1891 "interface='org.freedesktop.systemd1.Manager',"
1892 "member='JobRemoved',"
1893 "path='/org/freedesktop/systemd1'",
1894 match_job_removed
, d
);
1898 r
= sd_bus_add_match(
1900 &d
->slot_disconnected
,
1902 "sender='org.freedesktop.DBus.Local',"
1903 "interface='org.freedesktop.DBus.Local',"
1904 "member='Disconnected'",
1905 match_disconnected
, d
);
1915 static int bus_process_wait(sd_bus
*bus
) {
1919 r
= sd_bus_process(bus
, NULL
);
1925 r
= sd_bus_wait(bus
, (uint64_t) -1);
1931 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1932 _cleanup_free_
char *dbus_path
= NULL
;
1938 dbus_path
= unit_dbus_path_from_name(d
->name
);
1942 return sd_bus_get_property_string(d
->bus
,
1943 "org.freedesktop.systemd1",
1945 "org.freedesktop.systemd1.Service",
1951 static const struct {
1952 const char *result
, *explanation
;
1953 } explanations
[] = {
1954 { "resources", "a configured resource limit was exceeded" },
1955 { "timeout", "a timeout was exceeded" },
1956 { "exit-code", "the control process exited with error code" },
1957 { "signal", "a fatal signal was delivered to the control process" },
1958 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1959 { "watchdog", "the service failed to send watchdog ping" },
1960 { "start-limit", "start of the service was attempted too often" }
1963 static void log_job_error_with_service_result(const char* service
, const char *result
) {
1964 _cleanup_free_
char *service_shell_quoted
= NULL
;
1968 service_shell_quoted
= shell_maybe_quote(service
);
1970 if (!isempty(result
)) {
1973 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1974 if (streq(result
, explanations
[i
].result
))
1977 if (i
< ELEMENTSOF(explanations
)) {
1978 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1980 explanations
[i
].explanation
,
1981 strna(service_shell_quoted
));
1987 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1989 strna(service_shell_quoted
));
1992 /* For some results maybe additional explanation is required */
1993 if (streq_ptr(result
, "start-limit"))
1994 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
1995 strna(service_shell_quoted
));
1998 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
2004 if (streq(d
->result
, "canceled"))
2005 log_error("Job for %s canceled.", strna(d
->name
));
2006 else if (streq(d
->result
, "timeout"))
2007 log_error("Job for %s timed out.", strna(d
->name
));
2008 else if (streq(d
->result
, "dependency"))
2009 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2010 else if (streq(d
->result
, "invalid"))
2011 log_error("Job for %s invalid.", strna(d
->name
));
2012 else if (streq(d
->result
, "assert"))
2013 log_error("Assertion failed on job for %s.", strna(d
->name
));
2014 else if (streq(d
->result
, "unsupported"))
2015 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2016 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2019 _cleanup_free_
char *result
= NULL
;
2021 q
= bus_job_get_service_result(d
, &result
);
2023 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2025 log_job_error_with_service_result(d
->name
, result
);
2027 log_error("Job failed. See \"journalctl -xe\" for details.");
2031 if (streq(d
->result
, "canceled"))
2033 else if (streq(d
->result
, "timeout"))
2035 else if (streq(d
->result
, "dependency"))
2037 else if (streq(d
->result
, "invalid"))
2039 else if (streq(d
->result
, "assert"))
2041 else if (streq(d
->result
, "unsupported"))
2043 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2049 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2054 while (!set_isempty(d
->jobs
)) {
2057 q
= bus_process_wait(d
->bus
);
2059 return log_error_errno(q
, "Failed to wait for response: %m");
2062 q
= check_wait_response(d
, quiet
);
2063 /* Return the first error as it is most likely to be
2065 if (q
< 0 && r
== 0)
2068 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2071 d
->name
= mfree(d
->name
);
2072 d
->result
= mfree(d
->result
);
2078 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2083 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2087 return set_put_strdup(d
->jobs
, path
);
2090 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2093 r
= bus_wait_for_jobs_add(d
, path
);
2097 return bus_wait_for_jobs(d
, quiet
);
2100 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2101 const char *type
, *path
, *source
;
2104 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2106 return bus_log_parse_error(r
);
2108 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2110 if (streq(type
, "symlink"))
2111 log_info("Created symlink from %s to %s.", path
, source
);
2113 log_info("Removed symlink %s.", path
);
2116 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2121 return bus_log_parse_error(r
);
2123 r
= sd_bus_message_exit_container(m
);
2125 return bus_log_parse_error(r
);
2131 * bus_path_encode_unique() - encode unique object path
2132 * @b: bus connection or NULL
2133 * @prefix: object path prefix
2134 * @sender_id: unique-name of client, or NULL
2135 * @external_id: external ID to be chosen by client, or NULL
2136 * @ret_path: storage for encoded object path pointer
2138 * Whenever we provide a bus API that allows clients to create and manage
2139 * server-side objects, we need to provide a unique name for these objects. If
2140 * we let the server choose the name, we suffer from a race condition: If a
2141 * client creates an object asynchronously, it cannot destroy that object until
2142 * it received the method reply. It cannot know the name of the new object,
2143 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2145 * Therefore, many APIs allow the client to choose the unique name for newly
2146 * created objects. There're two problems to solve, though:
2147 * 1) Object names are usually defined via dbus object paths, which are
2148 * usually globally namespaced. Therefore, multiple clients must be able
2149 * to choose unique object names without interference.
2150 * 2) If multiple libraries share the same bus connection, they must be
2151 * able to choose unique object names without interference.
2152 * The first problem is solved easily by prefixing a name with the
2153 * unique-bus-name of a connection. The server side must enforce this and
2154 * reject any other name. The second problem is solved by providing unique
2155 * suffixes from within sd-bus.
2157 * This helper allows clients to create unique object-paths. It uses the
2158 * template '/prefix/sender_id/external_id' and returns the new path in
2159 * @ret_path (must be freed by the caller).
2160 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2161 * NULL, this function allocates a unique suffix via @b (by requesting a new
2162 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2165 * Returns: 0 on success, negative error code on failure.
2167 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2168 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2169 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2172 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2173 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2174 assert_return(ret_path
, -EINVAL
);
2177 r
= sd_bus_get_unique_name(b
, &sender_id
);
2183 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2184 external_id
= external_buf
;
2187 sender_label
= bus_label_escape(sender_id
);
2191 external_label
= bus_label_escape(external_id
);
2192 if (!external_label
)
2195 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2204 * bus_path_decode_unique() - decode unique object path
2205 * @path: object path to decode
2206 * @prefix: object path prefix
2207 * @ret_sender: output parameter for sender-id label
2208 * @ret_external: output parameter for external-id label
2210 * This does the reverse of bus_path_encode_unique() (see its description for
2211 * details). Both trailing labels, sender-id and external-id, are unescaped and
2212 * returned in the given output parameters (the caller must free them).
2214 * Note that this function returns 0 if the path does not match the template
2215 * (see bus_path_encode_unique()), 1 if it matched.
2217 * Returns: Negative error code on failure, 0 if the given object path does not
2218 * match the template (return parameters are set to NULL), 1 if it was
2219 * parsed successfully (return parameters contain allocated labels).
2221 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2223 char *sender
, *external
;
2225 assert(object_path_is_valid(path
));
2226 assert(object_path_is_valid(prefix
));
2228 assert(ret_external
);
2230 p
= object_path_startswith(path
, prefix
);
2233 *ret_external
= NULL
;
2240 *ret_external
= NULL
;
2244 sender
= bus_label_unescape_n(p
, q
- p
);
2245 external
= bus_label_unescape(q
+ 1);
2246 if (!sender
|| !external
) {
2252 *ret_sender
= sender
;
2253 *ret_external
= external
;
2257 bool is_kdbus_wanted(void) {
2258 _cleanup_free_
char *value
= NULL
;
2260 const bool configured
= true;
2262 const bool configured
= false;
2267 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2270 r
= get_proc_cmdline_key("kdbus=", &value
);
2274 return parse_boolean(value
) == 1;
2277 bool is_kdbus_available(void) {
2278 _cleanup_close_
int fd
= -1;
2279 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2281 if (!is_kdbus_wanted())
2284 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2288 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2291 int bus_property_get_rlimit(
2294 const char *interface
,
2295 const char *property
,
2296 sd_bus_message
*reply
,
2298 sd_bus_error
*error
) {
2308 rl
= *(struct rlimit
**) userdata
;
2312 struct rlimit buf
= {};
2315 z
= rlimit_from_string(strstr(property
, "Limit"));
2322 /* rlim_t might have different sizes, let's map
2323 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2325 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2327 return sd_bus_message_append(reply
, "t", u
);