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"
32 #include "cgroup-util.h"
38 #include "path-util.h"
40 #include "signal-util.h"
41 #include "string-util.h"
43 #include "unit-name.h"
48 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
49 sd_event
*e
= userdata
;
54 sd_bus_close(sd_bus_message_get_bus(m
));
60 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
61 _cleanup_free_
char *match
= NULL
;
69 /* We unregister the name here and then wait for the
70 * NameOwnerChanged signal for this event to arrive before we
71 * quit. We do this in order to make sure that any queued
72 * requests are still processed before we really exit. */
74 r
= sd_bus_get_unique_name(bus
, &unique
);
79 "sender='org.freedesktop.DBus',"
81 "interface='org.freedesktop.DBus',"
82 "member='NameOwnerChanged',"
83 "path='/org/freedesktop/DBus',"
86 "arg2=''", name
, unique
);
90 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
94 r
= sd_bus_release_name(bus
, name
);
101 int bus_event_loop_with_idle(
106 check_idle_t check_idle
,
108 bool exiting
= false;
118 r
= sd_event_get_state(e
);
121 if (r
== SD_EVENT_FINISHED
)
125 idle
= check_idle(userdata
);
129 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
133 if (r
== 0 && !exiting
&& idle
) {
135 r
= sd_bus_try_close(bus
);
139 /* Fallback for dbus1 connections: we
140 * unregister the name and wait for the
141 * response to come through for it */
142 if (r
== -EOPNOTSUPP
) {
144 /* Inform the service manager that we
145 * are going down, so that it will
146 * queue all further start requests,
147 * instead of assuming we are already
149 sd_notify(false, "STOPPING=1");
151 r
= bus_async_unregister_and_exit(e
, bus
, name
);
167 r
= sd_event_get_exit_code(e
, &code
);
174 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
175 _cleanup_bus_message_unref_ sd_bus_message
*rep
= NULL
;
176 int r
, has_owner
= 0;
181 r
= sd_bus_call_method(c
,
182 "org.freedesktop.DBus",
183 "/org/freedesktop/dbus",
184 "org.freedesktop.DBus",
193 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
195 return sd_bus_error_set_errno(error
, r
);
200 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
201 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
207 if (good_user
== UID_INVALID
)
210 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
214 /* Don't trust augmented credentials for authorization */
215 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
217 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
221 return sender_uid
== good_user
;
225 sd_bus_message
*call
,
228 const char **details
,
238 /* Tests non-interactively! */
240 r
= check_good_user(call
, good_user
);
244 r
= sd_bus_query_sender_privilege(call
, capability
);
251 _cleanup_bus_message_unref_ sd_bus_message
*request
= NULL
;
252 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
253 int authorized
= false, challenge
= false;
254 const char *sender
, **k
, **v
;
256 sender
= sd_bus_message_get_sender(call
);
260 r
= sd_bus_message_new_method_call(
263 "org.freedesktop.PolicyKit1",
264 "/org/freedesktop/PolicyKit1/Authority",
265 "org.freedesktop.PolicyKit1.Authority",
266 "CheckAuthorization");
270 r
= sd_bus_message_append(
273 "system-bus-name", 1, "name", "s", sender
,
278 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
282 STRV_FOREACH_PAIR(k
, v
, details
) {
283 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
288 r
= sd_bus_message_close_container(request
);
292 r
= sd_bus_message_append(request
, "us", 0, NULL
);
296 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
298 /* Treat no PK available as access denied */
299 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
300 sd_bus_error_free(e
);
307 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
311 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
319 *_challenge
= challenge
;
330 typedef struct AsyncPolkitQuery
{
331 sd_bus_message
*request
, *reply
;
332 sd_bus_message_handler_t callback
;
338 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
343 sd_bus_slot_unref(q
->slot
);
345 if (q
->registry
&& q
->request
)
346 hashmap_remove(q
->registry
, q
->request
);
348 sd_bus_message_unref(q
->request
);
349 sd_bus_message_unref(q
->reply
);
354 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
355 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
356 AsyncPolkitQuery
*q
= userdata
;
362 q
->slot
= sd_bus_slot_unref(q
->slot
);
363 q
->reply
= sd_bus_message_ref(reply
);
365 r
= sd_bus_message_rewind(q
->request
, true);
367 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
371 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
372 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
375 async_polkit_query_free(q
);
382 int bus_verify_polkit_async(
383 sd_bus_message
*call
,
386 const char **details
,
390 sd_bus_error
*error
) {
393 _cleanup_bus_message_unref_ sd_bus_message
*pk
= NULL
;
395 const char *sender
, **k
, **v
;
396 sd_bus_message_handler_t callback
;
406 r
= check_good_user(call
, good_user
);
411 q
= hashmap_get(*registry
, call
);
413 int authorized
, challenge
;
415 /* This is the second invocation of this function, and
416 * there's already a response from polkit, let's
420 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
421 const sd_bus_error
*e
;
423 /* Copy error from polkit reply */
424 e
= sd_bus_message_get_error(q
->reply
);
425 sd_bus_error_copy(error
, e
);
427 /* Treat no PK available as access denied */
428 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
431 return -sd_bus_error_get_errno(e
);
434 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
436 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
445 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
451 r
= sd_bus_query_sender_privilege(call
, capability
);
458 if (sd_bus_get_current_message(call
->bus
) != call
)
461 callback
= sd_bus_get_current_handler(call
->bus
);
465 userdata
= sd_bus_get_current_userdata(call
->bus
);
467 sender
= sd_bus_message_get_sender(call
);
471 c
= sd_bus_message_get_allow_interactive_authorization(call
);
477 r
= hashmap_ensure_allocated(registry
, NULL
);
481 r
= sd_bus_message_new_method_call(
484 "org.freedesktop.PolicyKit1",
485 "/org/freedesktop/PolicyKit1/Authority",
486 "org.freedesktop.PolicyKit1.Authority",
487 "CheckAuthorization");
491 r
= sd_bus_message_append(
494 "system-bus-name", 1, "name", "s", sender
,
499 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
503 STRV_FOREACH_PAIR(k
, v
, details
) {
504 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
509 r
= sd_bus_message_close_container(pk
);
513 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
517 q
= new0(AsyncPolkitQuery
, 1);
521 q
->request
= sd_bus_message_ref(call
);
522 q
->callback
= callback
;
523 q
->userdata
= userdata
;
525 r
= hashmap_put(*registry
, call
, q
);
527 async_polkit_query_free(q
);
531 q
->registry
= *registry
;
533 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
535 async_polkit_query_free(q
);
545 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
549 while ((q
= hashmap_steal_first(registry
)))
550 async_polkit_query_free(q
);
552 hashmap_free(registry
);
556 int bus_check_peercred(sd_bus
*c
) {
563 fd
= sd_bus_get_fd(c
);
567 l
= sizeof(struct ucred
);
568 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
571 if (l
!= sizeof(struct ucred
))
574 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
580 int bus_connect_system_systemd(sd_bus
**_bus
) {
581 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
587 return sd_bus_default_system(_bus
);
589 /* If we are root and kdbus is not available, then let's talk
590 * directly to the system instance, instead of going via the
593 r
= sd_bus_new(&bus
);
597 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
601 bus
->bus_client
= true;
603 r
= sd_bus_start(bus
);
610 bus
= sd_bus_unref(bus
);
612 r
= sd_bus_new(&bus
);
616 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
620 r
= sd_bus_start(bus
);
622 return sd_bus_default_system(_bus
);
624 r
= bus_check_peercred(bus
);
634 int bus_connect_user_systemd(sd_bus
**_bus
) {
635 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
636 _cleanup_free_
char *ee
= NULL
;
640 /* Try via kdbus first, and then directly */
644 r
= sd_bus_new(&bus
);
648 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
651 bus
->bus_client
= true;
653 r
= sd_bus_start(bus
);
660 bus
= sd_bus_unref(bus
);
662 e
= secure_getenv("XDG_RUNTIME_DIR");
664 return sd_bus_default_user(_bus
);
666 ee
= bus_address_escape(e
);
670 r
= sd_bus_new(&bus
);
674 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
678 r
= sd_bus_start(bus
);
680 return sd_bus_default_user(_bus
);
682 r
= bus_check_peercred(bus
);
692 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
694 const char *contents
;
700 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
706 case SD_BUS_TYPE_STRING
: {
709 r
= sd_bus_message_read_basic(property
, type
, &s
);
713 if (all
|| !isempty(s
)) {
714 _cleanup_free_
char *escaped
= NULL
;
716 escaped
= xescape(s
, "\n");
720 printf("%s=%s\n", name
, escaped
);
726 case SD_BUS_TYPE_BOOLEAN
: {
729 r
= sd_bus_message_read_basic(property
, type
, &b
);
733 printf("%s=%s\n", name
, yes_no(b
));
738 case SD_BUS_TYPE_UINT64
: {
741 r
= sd_bus_message_read_basic(property
, type
, &u
);
745 /* Yes, heuristics! But we can change this check
746 * should it turn out to not be sufficient */
748 if (endswith(name
, "Timestamp")) {
749 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
751 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
753 printf("%s=%s\n", name
, strempty(t
));
755 } else if (strstr(name
, "USec")) {
756 char timespan
[FORMAT_TIMESPAN_MAX
];
758 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
760 printf("%s=%llu\n", name
, (unsigned long long) u
);
765 case SD_BUS_TYPE_INT64
: {
768 r
= sd_bus_message_read_basic(property
, type
, &i
);
772 printf("%s=%lld\n", name
, (long long) i
);
777 case SD_BUS_TYPE_UINT32
: {
780 r
= sd_bus_message_read_basic(property
, type
, &u
);
784 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
785 printf("%s=%04o\n", name
, u
);
787 printf("%s=%u\n", name
, (unsigned) u
);
792 case SD_BUS_TYPE_INT32
: {
795 r
= sd_bus_message_read_basic(property
, type
, &i
);
799 printf("%s=%i\n", name
, (int) i
);
803 case SD_BUS_TYPE_DOUBLE
: {
806 r
= sd_bus_message_read_basic(property
, type
, &d
);
810 printf("%s=%g\n", name
, d
);
814 case SD_BUS_TYPE_ARRAY
:
815 if (streq(contents
, "s")) {
819 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
823 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
824 _cleanup_free_
char *escaped
= NULL
;
829 escaped
= xescape(str
, "\n ");
833 printf("%s%s", first
? "" : " ", escaped
);
845 r
= sd_bus_message_exit_container(property
);
851 } else if (streq(contents
, "y")) {
855 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
864 for (i
= 0; i
< n
; i
++)
865 printf("%02x", u
[i
]);
872 } else if (streq(contents
, "u")) {
876 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
885 for (i
= 0; i
< n
; i
++)
886 printf("%08x", u
[i
]);
900 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
901 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
902 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
908 r
= sd_bus_call_method(bus
,
911 "org.freedesktop.DBus.Properties",
919 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
923 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
925 const char *contents
;
927 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
931 if (!filter
|| strv_find(filter
, name
)) {
932 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
936 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
940 r
= bus_print_property(name
, reply
, all
);
945 printf("%s=[unprintable]\n", name
);
946 /* skip what we didn't read */
947 r
= sd_bus_message_skip(reply
, contents
);
952 r
= sd_bus_message_exit_container(reply
);
956 r
= sd_bus_message_skip(reply
, "v");
961 r
= sd_bus_message_exit_container(reply
);
968 r
= sd_bus_message_exit_container(reply
);
975 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
976 sd_id128_t
*p
= userdata
;
981 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
988 memcpy((*p
).bytes
, v
, n
);
995 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
999 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1004 case SD_BUS_TYPE_STRING
: {
1006 char **p
= userdata
;
1008 r
= sd_bus_message_read_basic(m
, type
, &s
);
1015 r
= free_and_strdup(p
, s
);
1019 case SD_BUS_TYPE_ARRAY
: {
1020 _cleanup_strv_free_
char **l
= NULL
;
1021 char ***p
= userdata
;
1023 r
= bus_message_read_strv_extend(m
, &l
);
1034 case SD_BUS_TYPE_BOOLEAN
: {
1038 r
= sd_bus_message_read_basic(m
, type
, &b
);
1047 case SD_BUS_TYPE_UINT32
: {
1049 uint32_t *p
= userdata
;
1051 r
= sd_bus_message_read_basic(m
, type
, &u
);
1060 case SD_BUS_TYPE_UINT64
: {
1062 uint64_t *p
= userdata
;
1064 r
= sd_bus_message_read_basic(m
, type
, &t
);
1080 int bus_message_map_all_properties(
1082 const struct bus_properties_map
*map
,
1085 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1091 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1095 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1096 const struct bus_properties_map
*prop
;
1098 const char *contents
;
1102 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1106 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1107 if (streq(map
[i
].member
, member
)) {
1113 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1117 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1121 v
= (uint8_t *)userdata
+ prop
->offset
;
1123 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1125 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1129 r
= sd_bus_message_exit_container(m
);
1133 r
= sd_bus_message_skip(m
, "v");
1138 r
= sd_bus_message_exit_container(m
);
1145 return sd_bus_message_exit_container(m
);
1148 int bus_message_map_properties_changed(
1150 const struct bus_properties_map
*map
,
1154 int r
, invalidated
, i
;
1159 r
= bus_message_map_all_properties(m
, map
, userdata
);
1163 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1168 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1169 for (i
= 0; map
[i
].member
; i
++)
1170 if (streq(map
[i
].member
, member
)) {
1177 r
= sd_bus_message_exit_container(m
);
1184 int bus_map_all_properties(
1186 const char *destination
,
1188 const struct bus_properties_map
*map
,
1191 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1192 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1196 assert(destination
);
1200 r
= sd_bus_call_method(
1204 "org.freedesktop.DBus.Properties",
1212 return bus_message_map_all_properties(m
, map
, userdata
);
1215 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1218 assert(transport
>= 0);
1219 assert(transport
< _BUS_TRANSPORT_MAX
);
1222 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1223 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1225 switch (transport
) {
1227 case BUS_TRANSPORT_LOCAL
:
1229 r
= sd_bus_default_user(bus
);
1231 r
= sd_bus_default_system(bus
);
1235 case BUS_TRANSPORT_REMOTE
:
1236 r
= sd_bus_open_system_remote(bus
, host
);
1239 case BUS_TRANSPORT_MACHINE
:
1240 r
= sd_bus_open_system_machine(bus
, host
);
1244 assert_not_reached("Hmm, unknown transport type.");
1250 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1253 assert(transport
>= 0);
1254 assert(transport
< _BUS_TRANSPORT_MAX
);
1257 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1258 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1260 switch (transport
) {
1262 case BUS_TRANSPORT_LOCAL
:
1264 r
= bus_connect_user_systemd(bus
);
1266 r
= bus_connect_system_systemd(bus
);
1270 case BUS_TRANSPORT_REMOTE
:
1271 r
= sd_bus_open_system_remote(bus
, host
);
1274 case BUS_TRANSPORT_MACHINE
:
1275 r
= sd_bus_open_system_machine(bus
, host
);
1279 assert_not_reached("Hmm, unknown transport type.");
1285 int bus_property_get_bool(
1288 const char *interface
,
1289 const char *property
,
1290 sd_bus_message
*reply
,
1292 sd_bus_error
*error
) {
1294 int b
= *(bool*) userdata
;
1296 return sd_bus_message_append_basic(reply
, 'b', &b
);
1299 #if __SIZEOF_SIZE_T__ != 8
1300 int bus_property_get_size(
1303 const char *interface
,
1304 const char *property
,
1305 sd_bus_message
*reply
,
1307 sd_bus_error
*error
) {
1309 uint64_t sz
= *(size_t*) userdata
;
1311 return sd_bus_message_append_basic(reply
, 't', &sz
);
1315 #if __SIZEOF_LONG__ != 8
1316 int bus_property_get_long(
1319 const char *interface
,
1320 const char *property
,
1321 sd_bus_message
*reply
,
1323 sd_bus_error
*error
) {
1325 int64_t l
= *(long*) userdata
;
1327 return sd_bus_message_append_basic(reply
, 'x', &l
);
1330 int bus_property_get_ulong(
1333 const char *interface
,
1334 const char *property
,
1335 sd_bus_message
*reply
,
1337 sd_bus_error
*error
) {
1339 uint64_t ul
= *(unsigned long*) userdata
;
1341 return sd_bus_message_append_basic(reply
, 't', &ul
);
1345 int bus_log_parse_error(int r
) {
1346 return log_error_errno(r
, "Failed to parse bus message: %m");
1349 int bus_log_create_error(int r
) {
1350 return log_error_errno(r
, "Failed to create bus message: %m");
1353 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1359 return sd_bus_message_read(
1374 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1375 const char *eq
, *field
;
1381 eq
= strchr(assignment
, '=');
1383 log_error("Not an assignment: %s", assignment
);
1387 field
= strndupa(assignment
, eq
- assignment
);
1390 if (streq(field
, "CPUQuota")) {
1394 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1396 return bus_log_create_error(r
);
1398 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1400 } else if (endswith(eq
, "%")) {
1403 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1404 log_error("CPU quota '%s' invalid.", eq
);
1408 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1410 return bus_log_create_error(r
);
1412 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1414 log_error("CPU quota needs to be in percent.");
1419 return bus_log_create_error(r
);
1422 } else if (streq(field
, "EnvironmentFile")) {
1423 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1427 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1428 eq
[0] == '-' ? eq
+ 1 : eq
,
1435 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1437 return bus_log_create_error(r
);
1439 if (STR_IN_SET(field
,
1440 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1441 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1442 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1443 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1444 "SyslogLevelPrefix")) {
1446 r
= parse_boolean(eq
);
1448 log_error("Failed to parse boolean assignment %s.", assignment
);
1452 r
= sd_bus_message_append(m
, "v", "b", r
);
1454 } else if (streq(field
, "MemoryLimit")) {
1457 if (isempty(eq
) || streq(eq
, "infinity"))
1458 bytes
= (uint64_t) -1;
1460 r
= parse_size(eq
, 1024, &bytes
);
1462 log_error("Failed to parse bytes specification %s", assignment
);
1467 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1469 } else if (streq(field
, "TasksMax")) {
1472 if (isempty(eq
) || streq(eq
, "infinity"))
1475 r
= safe_atou64(eq
, &n
);
1477 log_error("Failed to parse maximum tasks specification %s", assignment
);
1482 r
= sd_bus_message_append(m
, "v", "t", n
);
1484 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1487 r
= cg_cpu_shares_parse(eq
, &u
);
1489 log_error("Failed to parse %s value %s.", field
, eq
);
1493 r
= sd_bus_message_append(m
, "v", "t", u
);
1495 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1498 r
= cg_cpu_shares_parse(eq
, &u
);
1500 log_error("Failed to parse %s value %s.", field
, eq
);
1504 r
= sd_bus_message_append(m
, "v", "t", u
);
1506 } else if (STR_IN_SET(field
,
1507 "User", "Group", "DevicePolicy", "KillMode",
1508 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1509 "StandardInput", "StandardOutput", "StandardError",
1510 "Description", "Slice", "Type", "WorkingDirectory",
1511 "RootDirectory", "SyslogIdentifier"))
1512 r
= sd_bus_message_append(m
, "v", "s", eq
);
1514 else if (streq(field
, "SyslogLevel")) {
1517 level
= log_level_from_string(eq
);
1519 log_error("Failed to parse %s value %s.", field
, eq
);
1523 r
= sd_bus_message_append(m
, "v", "i", level
);
1525 } else if (streq(field
, "SyslogFacility")) {
1528 facility
= log_facility_unshifted_from_string(eq
);
1530 log_error("Failed to parse %s value %s.", field
, eq
);
1534 r
= sd_bus_message_append(m
, "v", "i", facility
);
1536 } else if (streq(field
, "DeviceAllow")) {
1539 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1541 const char *path
, *rwm
, *e
;
1543 e
= strchr(eq
, ' ');
1545 path
= strndupa(eq
, e
- eq
);
1552 if (!path_startswith(path
, "/dev")) {
1553 log_error("%s is not a device file in /dev.", path
);
1557 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1560 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1563 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1565 const char *path
, *bandwidth
, *e
;
1568 e
= strchr(eq
, ' ');
1570 path
= strndupa(eq
, e
- eq
);
1573 log_error("Failed to parse %s value %s.", field
, eq
);
1577 if (!path_startswith(path
, "/dev")) {
1578 log_error("%s is not a device file in /dev.", path
);
1582 r
= parse_size(bandwidth
, 1000, &bytes
);
1584 log_error("Failed to parse byte value %s.", bandwidth
);
1588 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1591 } else if (streq(field
, "BlockIODeviceWeight")) {
1594 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1596 const char *path
, *weight
, *e
;
1599 e
= strchr(eq
, ' ');
1601 path
= strndupa(eq
, e
- eq
);
1604 log_error("Failed to parse %s value %s.", field
, eq
);
1608 if (!path_startswith(path
, "/dev")) {
1609 log_error("%s is not a device file in /dev.", path
);
1613 r
= safe_atou64(weight
, &u
);
1615 log_error("Failed to parse %s value %s.", field
, weight
);
1618 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1621 } else if (rlimit_from_string(field
) >= 0) {
1624 if (streq(eq
, "infinity"))
1627 r
= safe_atou64(eq
, &rl
);
1629 log_error("Invalid resource limit: %s", eq
);
1634 r
= sd_bus_message_append(m
, "v", "t", rl
);
1636 } else if (streq(field
, "Nice")) {
1639 r
= safe_atoi32(eq
, &i
);
1641 log_error("Failed to parse %s value %s.", field
, eq
);
1645 r
= sd_bus_message_append(m
, "v", "i", i
);
1647 } else if (streq(field
, "Environment")) {
1650 r
= sd_bus_message_open_container(m
, 'v', "as");
1652 return bus_log_create_error(r
);
1654 r
= sd_bus_message_open_container(m
, 'a', "s");
1656 return bus_log_create_error(r
);
1661 _cleanup_free_
char *word
= NULL
;
1663 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1665 log_error("Failed to parse Environment value %s", eq
);
1671 if (!env_assignment_is_valid(word
)) {
1672 log_error("Invalid environment assignment: %s", eq
);
1676 r
= sd_bus_message_append_basic(m
, 's', word
);
1678 return bus_log_create_error(r
);
1681 r
= sd_bus_message_close_container(m
);
1683 return bus_log_create_error(r
);
1685 r
= sd_bus_message_close_container(m
);
1687 } else if (streq(field
, "KillSignal")) {
1690 sig
= signal_from_string_try_harder(eq
);
1692 log_error("Failed to parse %s value %s.", field
, eq
);
1696 r
= sd_bus_message_append(m
, "v", "i", sig
);
1698 } else if (streq(field
, "AccuracySec")) {
1701 r
= parse_sec(eq
, &u
);
1703 log_error("Failed to parse %s value %s", field
, eq
);
1707 r
= sd_bus_message_append(m
, "v", "t", u
);
1708 } else if (streq(field
, "TimerSlackNSec")) {
1711 r
= parse_nsec(eq
, &n
);
1713 log_error("Failed to parse %s value %s", field
, eq
);
1717 r
= sd_bus_message_append(m
, "v", "t", n
);
1718 } else if (streq(field
, "OOMScoreAdjust")) {
1721 r
= safe_atoi(eq
, &oa
);
1723 log_error("Failed to parse %s value %s", field
, eq
);
1727 if (!oom_score_adjust_is_valid(oa
)) {
1728 log_error("OOM score adjust value out of range");
1732 r
= sd_bus_message_append(m
, "v", "i", oa
);
1733 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1736 r
= sd_bus_message_open_container(m
, 'v', "as");
1738 return bus_log_create_error(r
);
1740 r
= sd_bus_message_open_container(m
, 'a', "s");
1742 return bus_log_create_error(r
);
1747 _cleanup_free_
char *word
= NULL
;
1750 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1752 log_error("Failed to parse %s value %s", field
, eq
);
1758 if (!utf8_is_valid(word
)) {
1759 log_error("Failed to parse %s value %s", field
, eq
);
1763 offset
= word
[0] == '-';
1764 if (!path_is_absolute(word
+ offset
)) {
1765 log_error("Failed to parse %s value %s", field
, eq
);
1769 path_kill_slashes(word
+ offset
);
1771 r
= sd_bus_message_append_basic(m
, 's', word
);
1773 return bus_log_create_error(r
);
1776 r
= sd_bus_message_close_container(m
);
1778 return bus_log_create_error(r
);
1780 r
= sd_bus_message_close_container(m
);
1783 log_error("Unknown assignment %s.", assignment
);
1788 return bus_log_create_error(r
);
1793 typedef struct BusWaitForJobs
{
1800 sd_bus_slot
*slot_job_removed
;
1801 sd_bus_slot
*slot_disconnected
;
1804 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1807 log_error("Warning! D-Bus connection terminated.");
1808 sd_bus_close(sd_bus_message_get_bus(m
));
1813 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1814 const char *path
, *unit
, *result
;
1815 BusWaitForJobs
*d
= userdata
;
1823 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1825 bus_log_parse_error(r
);
1829 found
= set_remove(d
->jobs
, (char*) path
);
1835 if (!isempty(result
))
1836 d
->result
= strdup(result
);
1839 d
->name
= strdup(unit
);
1844 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1848 set_free_free(d
->jobs
);
1850 sd_bus_slot_unref(d
->slot_disconnected
);
1851 sd_bus_slot_unref(d
->slot_job_removed
);
1853 sd_bus_unref(d
->bus
);
1861 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1862 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1868 d
= new0(BusWaitForJobs
, 1);
1872 d
->bus
= sd_bus_ref(bus
);
1874 /* When we are a bus client we match by sender. Direct
1875 * connections OTOH have no initialized sender field, and
1876 * hence we ignore the sender then */
1877 r
= sd_bus_add_match(
1879 &d
->slot_job_removed
,
1882 "sender='org.freedesktop.systemd1',"
1883 "interface='org.freedesktop.systemd1.Manager',"
1884 "member='JobRemoved',"
1885 "path='/org/freedesktop/systemd1'" :
1887 "interface='org.freedesktop.systemd1.Manager',"
1888 "member='JobRemoved',"
1889 "path='/org/freedesktop/systemd1'",
1890 match_job_removed
, d
);
1894 r
= sd_bus_add_match(
1896 &d
->slot_disconnected
,
1898 "sender='org.freedesktop.DBus.Local',"
1899 "interface='org.freedesktop.DBus.Local',"
1900 "member='Disconnected'",
1901 match_disconnected
, d
);
1911 static int bus_process_wait(sd_bus
*bus
) {
1915 r
= sd_bus_process(bus
, NULL
);
1921 r
= sd_bus_wait(bus
, (uint64_t) -1);
1927 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1928 _cleanup_free_
char *dbus_path
= NULL
;
1934 dbus_path
= unit_dbus_path_from_name(d
->name
);
1938 return sd_bus_get_property_string(d
->bus
,
1939 "org.freedesktop.systemd1",
1941 "org.freedesktop.systemd1.Service",
1947 static const struct {
1948 const char *result
, *explanation
;
1949 } explanations
[] = {
1950 { "resources", "a configured resource limit was exceeded" },
1951 { "timeout", "a timeout was exceeded" },
1952 { "exit-code", "the control process exited with error code" },
1953 { "signal", "a fatal signal was delivered to the control process" },
1954 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1955 { "watchdog", "the service failed to send watchdog ping" },
1956 { "start-limit", "start of the service was attempted too often" }
1959 static void log_job_error_with_service_result(const char* service
, const char *result
) {
1960 _cleanup_free_
char *service_shell_quoted
= NULL
;
1964 service_shell_quoted
= shell_maybe_quote(service
);
1966 if (!isempty(result
)) {
1969 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1970 if (streq(result
, explanations
[i
].result
))
1973 if (i
< ELEMENTSOF(explanations
)) {
1974 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1976 explanations
[i
].explanation
,
1977 strna(service_shell_quoted
));
1983 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1985 strna(service_shell_quoted
));
1988 /* For some results maybe additional explanation is required */
1989 if (streq_ptr(result
, "start-limit"))
1990 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
1991 strna(service_shell_quoted
));
1994 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
2000 if (streq(d
->result
, "canceled"))
2001 log_error("Job for %s canceled.", strna(d
->name
));
2002 else if (streq(d
->result
, "timeout"))
2003 log_error("Job for %s timed out.", strna(d
->name
));
2004 else if (streq(d
->result
, "dependency"))
2005 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2006 else if (streq(d
->result
, "invalid"))
2007 log_error("Job for %s invalid.", strna(d
->name
));
2008 else if (streq(d
->result
, "assert"))
2009 log_error("Assertion failed on job for %s.", strna(d
->name
));
2010 else if (streq(d
->result
, "unsupported"))
2011 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2012 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2015 _cleanup_free_
char *result
= NULL
;
2017 q
= bus_job_get_service_result(d
, &result
);
2019 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2021 log_job_error_with_service_result(d
->name
, result
);
2023 log_error("Job failed. See \"journalctl -xe\" for details.");
2027 if (streq(d
->result
, "canceled"))
2029 else if (streq(d
->result
, "timeout"))
2031 else if (streq(d
->result
, "dependency"))
2033 else if (streq(d
->result
, "invalid"))
2035 else if (streq(d
->result
, "assert"))
2037 else if (streq(d
->result
, "unsupported"))
2039 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2045 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2050 while (!set_isempty(d
->jobs
)) {
2053 q
= bus_process_wait(d
->bus
);
2055 return log_error_errno(q
, "Failed to wait for response: %m");
2058 q
= check_wait_response(d
, quiet
);
2059 /* Return the first error as it is most likely to be
2061 if (q
< 0 && r
== 0)
2064 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2067 d
->name
= mfree(d
->name
);
2068 d
->result
= mfree(d
->result
);
2074 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2079 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2083 return set_put_strdup(d
->jobs
, path
);
2086 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2089 r
= bus_wait_for_jobs_add(d
, path
);
2093 return bus_wait_for_jobs(d
, quiet
);
2096 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2097 const char *type
, *path
, *source
;
2100 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2102 return bus_log_parse_error(r
);
2104 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2106 if (streq(type
, "symlink"))
2107 log_info("Created symlink from %s to %s.", path
, source
);
2109 log_info("Removed symlink %s.", path
);
2112 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2117 return bus_log_parse_error(r
);
2119 r
= sd_bus_message_exit_container(m
);
2121 return bus_log_parse_error(r
);
2127 * bus_path_encode_unique() - encode unique object path
2128 * @b: bus connection or NULL
2129 * @prefix: object path prefix
2130 * @sender_id: unique-name of client, or NULL
2131 * @external_id: external ID to be chosen by client, or NULL
2132 * @ret_path: storage for encoded object path pointer
2134 * Whenever we provide a bus API that allows clients to create and manage
2135 * server-side objects, we need to provide a unique name for these objects. If
2136 * we let the server choose the name, we suffer from a race condition: If a
2137 * client creates an object asynchronously, it cannot destroy that object until
2138 * it received the method reply. It cannot know the name of the new object,
2139 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2141 * Therefore, many APIs allow the client to choose the unique name for newly
2142 * created objects. There're two problems to solve, though:
2143 * 1) Object names are usually defined via dbus object paths, which are
2144 * usually globally namespaced. Therefore, multiple clients must be able
2145 * to choose unique object names without interference.
2146 * 2) If multiple libraries share the same bus connection, they must be
2147 * able to choose unique object names without interference.
2148 * The first problem is solved easily by prefixing a name with the
2149 * unique-bus-name of a connection. The server side must enforce this and
2150 * reject any other name. The second problem is solved by providing unique
2151 * suffixes from within sd-bus.
2153 * This helper allows clients to create unique object-paths. It uses the
2154 * template '/prefix/sender_id/external_id' and returns the new path in
2155 * @ret_path (must be freed by the caller).
2156 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2157 * NULL, this function allocates a unique suffix via @b (by requesting a new
2158 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2161 * Returns: 0 on success, negative error code on failure.
2163 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2164 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2165 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2168 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2169 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2170 assert_return(ret_path
, -EINVAL
);
2173 r
= sd_bus_get_unique_name(b
, &sender_id
);
2179 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2180 external_id
= external_buf
;
2183 sender_label
= bus_label_escape(sender_id
);
2187 external_label
= bus_label_escape(external_id
);
2188 if (!external_label
)
2191 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2200 * bus_path_decode_unique() - decode unique object path
2201 * @path: object path to decode
2202 * @prefix: object path prefix
2203 * @ret_sender: output parameter for sender-id label
2204 * @ret_external: output parameter for external-id label
2206 * This does the reverse of bus_path_encode_unique() (see its description for
2207 * details). Both trailing labels, sender-id and external-id, are unescaped and
2208 * returned in the given output parameters (the caller must free them).
2210 * Note that this function returns 0 if the path does not match the template
2211 * (see bus_path_encode_unique()), 1 if it matched.
2213 * Returns: Negative error code on failure, 0 if the given object path does not
2214 * match the template (return parameters are set to NULL), 1 if it was
2215 * parsed successfully (return parameters contain allocated labels).
2217 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2219 char *sender
, *external
;
2221 assert(object_path_is_valid(path
));
2222 assert(object_path_is_valid(prefix
));
2224 assert(ret_external
);
2226 p
= object_path_startswith(path
, prefix
);
2229 *ret_external
= NULL
;
2236 *ret_external
= NULL
;
2240 sender
= bus_label_unescape_n(p
, q
- p
);
2241 external
= bus_label_unescape(q
+ 1);
2242 if (!sender
|| !external
) {
2248 *ret_sender
= sender
;
2249 *ret_external
= external
;
2253 bool is_kdbus_wanted(void) {
2254 _cleanup_free_
char *value
= NULL
;
2256 const bool configured
= true;
2258 const bool configured
= false;
2263 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2266 r
= get_proc_cmdline_key("kdbus=", &value
);
2270 return parse_boolean(value
) == 1;
2273 bool is_kdbus_available(void) {
2274 _cleanup_close_
int fd
= -1;
2275 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2277 if (!is_kdbus_wanted())
2280 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2284 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2287 int bus_property_get_rlimit(
2290 const char *interface
,
2291 const char *property
,
2292 sd_bus_message
*reply
,
2294 sd_bus_error
*error
) {
2304 rl
= *(struct rlimit
**) userdata
;
2308 struct rlimit buf
= {};
2311 z
= rlimit_from_string(strstr(property
, "Limit"));
2318 /* rlim_t might have different sizes, let's map
2319 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2321 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2323 return sd_bus_message_append(reply
, "t", u
);