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>
24 #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"
37 #include "path-util.h"
39 #include "signal-util.h"
41 #include "unit-name.h"
47 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
48 sd_event
*e
= userdata
;
53 sd_bus_close(sd_bus_message_get_bus(m
));
59 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
60 _cleanup_free_
char *match
= NULL
;
68 /* We unregister the name here and then wait for the
69 * NameOwnerChanged signal for this event to arrive before we
70 * quit. We do this in order to make sure that any queued
71 * requests are still processed before we really exit. */
73 r
= sd_bus_get_unique_name(bus
, &unique
);
78 "sender='org.freedesktop.DBus',"
80 "interface='org.freedesktop.DBus',"
81 "member='NameOwnerChanged',"
82 "path='/org/freedesktop/DBus',"
85 "arg2=''", name
, unique
);
89 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
93 r
= sd_bus_release_name(bus
, name
);
100 int bus_event_loop_with_idle(
105 check_idle_t check_idle
,
107 bool exiting
= false;
117 r
= sd_event_get_state(e
);
120 if (r
== SD_EVENT_FINISHED
)
124 idle
= check_idle(userdata
);
128 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
132 if (r
== 0 && !exiting
&& idle
) {
134 r
= sd_bus_try_close(bus
);
138 /* Fallback for dbus1 connections: we
139 * unregister the name and wait for the
140 * response to come through for it */
141 if (r
== -EOPNOTSUPP
) {
143 /* Inform the service manager that we
144 * are going down, so that it will
145 * queue all further start requests,
146 * instead of assuming we are already
148 sd_notify(false, "STOPPING=1");
150 r
= bus_async_unregister_and_exit(e
, bus
, name
);
166 r
= sd_event_get_exit_code(e
, &code
);
173 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
174 _cleanup_bus_message_unref_ sd_bus_message
*rep
= NULL
;
175 int r
, has_owner
= 0;
180 r
= sd_bus_call_method(c
,
181 "org.freedesktop.DBus",
182 "/org/freedesktop/dbus",
183 "org.freedesktop.DBus",
192 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
194 return sd_bus_error_set_errno(error
, r
);
199 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
200 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
206 if (good_user
== UID_INVALID
)
209 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
213 /* Don't trust augmented credentials for authorization */
214 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
216 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
220 return sender_uid
== good_user
;
224 sd_bus_message
*call
,
227 const char **details
,
237 /* Tests non-interactively! */
239 r
= check_good_user(call
, good_user
);
243 r
= sd_bus_query_sender_privilege(call
, capability
);
250 _cleanup_bus_message_unref_ sd_bus_message
*request
= NULL
;
251 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
252 int authorized
= false, challenge
= false;
253 const char *sender
, **k
, **v
;
255 sender
= sd_bus_message_get_sender(call
);
259 r
= sd_bus_message_new_method_call(
262 "org.freedesktop.PolicyKit1",
263 "/org/freedesktop/PolicyKit1/Authority",
264 "org.freedesktop.PolicyKit1.Authority",
265 "CheckAuthorization");
269 r
= sd_bus_message_append(
272 "system-bus-name", 1, "name", "s", sender
,
277 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
281 STRV_FOREACH_PAIR(k
, v
, details
) {
282 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
287 r
= sd_bus_message_close_container(request
);
291 r
= sd_bus_message_append(request
, "us", 0, NULL
);
295 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
297 /* Treat no PK available as access denied */
298 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
299 sd_bus_error_free(e
);
306 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
310 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
318 *_challenge
= challenge
;
329 typedef struct AsyncPolkitQuery
{
330 sd_bus_message
*request
, *reply
;
331 sd_bus_message_handler_t callback
;
337 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
342 sd_bus_slot_unref(q
->slot
);
344 if (q
->registry
&& q
->request
)
345 hashmap_remove(q
->registry
, q
->request
);
347 sd_bus_message_unref(q
->request
);
348 sd_bus_message_unref(q
->reply
);
353 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
354 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
355 AsyncPolkitQuery
*q
= userdata
;
361 q
->slot
= sd_bus_slot_unref(q
->slot
);
362 q
->reply
= sd_bus_message_ref(reply
);
364 r
= sd_bus_message_rewind(q
->request
, true);
366 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
370 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
371 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
374 async_polkit_query_free(q
);
381 int bus_verify_polkit_async(
382 sd_bus_message
*call
,
385 const char **details
,
389 sd_bus_error
*error
) {
392 _cleanup_bus_message_unref_ sd_bus_message
*pk
= NULL
;
394 const char *sender
, **k
, **v
;
395 sd_bus_message_handler_t callback
;
405 r
= check_good_user(call
, good_user
);
410 q
= hashmap_get(*registry
, call
);
412 int authorized
, challenge
;
414 /* This is the second invocation of this function, and
415 * there's already a response from polkit, let's
419 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
420 const sd_bus_error
*e
;
422 /* Copy error from polkit reply */
423 e
= sd_bus_message_get_error(q
->reply
);
424 sd_bus_error_copy(error
, e
);
426 /* Treat no PK available as access denied */
427 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
430 return -sd_bus_error_get_errno(e
);
433 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
435 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
444 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
450 r
= sd_bus_query_sender_privilege(call
, capability
);
457 if (sd_bus_get_current_message(call
->bus
) != call
)
460 callback
= sd_bus_get_current_handler(call
->bus
);
464 userdata
= sd_bus_get_current_userdata(call
->bus
);
466 sender
= sd_bus_message_get_sender(call
);
470 c
= sd_bus_message_get_allow_interactive_authorization(call
);
476 r
= hashmap_ensure_allocated(registry
, NULL
);
480 r
= sd_bus_message_new_method_call(
483 "org.freedesktop.PolicyKit1",
484 "/org/freedesktop/PolicyKit1/Authority",
485 "org.freedesktop.PolicyKit1.Authority",
486 "CheckAuthorization");
490 r
= sd_bus_message_append(
493 "system-bus-name", 1, "name", "s", sender
,
498 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
502 STRV_FOREACH_PAIR(k
, v
, details
) {
503 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
508 r
= sd_bus_message_close_container(pk
);
512 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
516 q
= new0(AsyncPolkitQuery
, 1);
520 q
->request
= sd_bus_message_ref(call
);
521 q
->callback
= callback
;
522 q
->userdata
= userdata
;
524 r
= hashmap_put(*registry
, call
, q
);
526 async_polkit_query_free(q
);
530 q
->registry
= *registry
;
532 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
534 async_polkit_query_free(q
);
544 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
548 while ((q
= hashmap_steal_first(registry
)))
549 async_polkit_query_free(q
);
551 hashmap_free(registry
);
555 int bus_check_peercred(sd_bus
*c
) {
562 fd
= sd_bus_get_fd(c
);
566 l
= sizeof(struct ucred
);
567 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
570 if (l
!= sizeof(struct ucred
))
573 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
579 int bus_connect_system_systemd(sd_bus
**_bus
) {
580 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
586 return sd_bus_default_system(_bus
);
588 /* If we are root and kdbus is not available, then let's talk
589 * directly to the system instance, instead of going via the
592 r
= sd_bus_new(&bus
);
596 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
600 bus
->bus_client
= true;
602 r
= sd_bus_start(bus
);
609 bus
= sd_bus_unref(bus
);
611 r
= sd_bus_new(&bus
);
615 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
619 r
= sd_bus_start(bus
);
621 return sd_bus_default_system(_bus
);
623 r
= bus_check_peercred(bus
);
633 int bus_connect_user_systemd(sd_bus
**_bus
) {
634 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
635 _cleanup_free_
char *ee
= NULL
;
639 /* Try via kdbus first, and then directly */
643 r
= sd_bus_new(&bus
);
647 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
650 bus
->bus_client
= true;
652 r
= sd_bus_start(bus
);
659 bus
= sd_bus_unref(bus
);
661 e
= secure_getenv("XDG_RUNTIME_DIR");
663 return sd_bus_default_user(_bus
);
665 ee
= bus_address_escape(e
);
669 r
= sd_bus_new(&bus
);
673 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
677 r
= sd_bus_start(bus
);
679 return sd_bus_default_user(_bus
);
681 r
= bus_check_peercred(bus
);
691 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
693 const char *contents
;
699 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
705 case SD_BUS_TYPE_STRING
: {
708 r
= sd_bus_message_read_basic(property
, type
, &s
);
712 if (all
|| !isempty(s
)) {
713 _cleanup_free_
char *escaped
= NULL
;
715 escaped
= xescape(s
, "\n");
719 printf("%s=%s\n", name
, escaped
);
725 case SD_BUS_TYPE_BOOLEAN
: {
728 r
= sd_bus_message_read_basic(property
, type
, &b
);
732 printf("%s=%s\n", name
, yes_no(b
));
737 case SD_BUS_TYPE_UINT64
: {
740 r
= sd_bus_message_read_basic(property
, type
, &u
);
744 /* Yes, heuristics! But we can change this check
745 * should it turn out to not be sufficient */
747 if (endswith(name
, "Timestamp")) {
748 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
750 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
752 printf("%s=%s\n", name
, strempty(t
));
754 } else if (strstr(name
, "USec")) {
755 char timespan
[FORMAT_TIMESPAN_MAX
];
757 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
759 printf("%s=%llu\n", name
, (unsigned long long) u
);
764 case SD_BUS_TYPE_INT64
: {
767 r
= sd_bus_message_read_basic(property
, type
, &i
);
771 printf("%s=%lld\n", name
, (long long) i
);
776 case SD_BUS_TYPE_UINT32
: {
779 r
= sd_bus_message_read_basic(property
, type
, &u
);
783 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
784 printf("%s=%04o\n", name
, u
);
786 printf("%s=%u\n", name
, (unsigned) u
);
791 case SD_BUS_TYPE_INT32
: {
794 r
= sd_bus_message_read_basic(property
, type
, &i
);
798 printf("%s=%i\n", name
, (int) i
);
802 case SD_BUS_TYPE_DOUBLE
: {
805 r
= sd_bus_message_read_basic(property
, type
, &d
);
809 printf("%s=%g\n", name
, d
);
813 case SD_BUS_TYPE_ARRAY
:
814 if (streq(contents
, "s")) {
818 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
822 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
823 _cleanup_free_
char *escaped
= NULL
;
828 escaped
= xescape(str
, "\n ");
832 printf("%s%s", first
? "" : " ", escaped
);
844 r
= sd_bus_message_exit_container(property
);
850 } else if (streq(contents
, "y")) {
854 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
863 for (i
= 0; i
< n
; i
++)
864 printf("%02x", u
[i
]);
871 } else if (streq(contents
, "u")) {
875 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
884 for (i
= 0; i
< n
; i
++)
885 printf("%08x", u
[i
]);
899 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
900 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
901 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
907 r
= sd_bus_call_method(bus
,
910 "org.freedesktop.DBus.Properties",
918 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
922 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
924 const char *contents
;
926 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
930 if (!filter
|| strv_find(filter
, name
)) {
931 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
935 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
939 r
= bus_print_property(name
, reply
, all
);
944 printf("%s=[unprintable]\n", name
);
945 /* skip what we didn't read */
946 r
= sd_bus_message_skip(reply
, contents
);
951 r
= sd_bus_message_exit_container(reply
);
955 r
= sd_bus_message_skip(reply
, "v");
960 r
= sd_bus_message_exit_container(reply
);
967 r
= sd_bus_message_exit_container(reply
);
974 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
975 sd_id128_t
*p
= userdata
;
980 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
987 memcpy((*p
).bytes
, v
, n
);
994 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
998 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1003 case SD_BUS_TYPE_STRING
: {
1005 char **p
= userdata
;
1007 r
= sd_bus_message_read_basic(m
, type
, &s
);
1014 r
= free_and_strdup(p
, s
);
1018 case SD_BUS_TYPE_ARRAY
: {
1019 _cleanup_strv_free_
char **l
= NULL
;
1020 char ***p
= userdata
;
1022 r
= bus_message_read_strv_extend(m
, &l
);
1033 case SD_BUS_TYPE_BOOLEAN
: {
1037 r
= sd_bus_message_read_basic(m
, type
, &b
);
1046 case SD_BUS_TYPE_UINT32
: {
1048 uint32_t *p
= userdata
;
1050 r
= sd_bus_message_read_basic(m
, type
, &u
);
1059 case SD_BUS_TYPE_UINT64
: {
1061 uint64_t *p
= userdata
;
1063 r
= sd_bus_message_read_basic(m
, type
, &t
);
1079 int bus_message_map_all_properties(
1081 const struct bus_properties_map
*map
,
1084 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1090 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1094 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1095 const struct bus_properties_map
*prop
;
1097 const char *contents
;
1101 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1105 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1106 if (streq(map
[i
].member
, member
)) {
1112 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1116 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1120 v
= (uint8_t *)userdata
+ prop
->offset
;
1122 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1124 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1128 r
= sd_bus_message_exit_container(m
);
1132 r
= sd_bus_message_skip(m
, "v");
1137 r
= sd_bus_message_exit_container(m
);
1144 return sd_bus_message_exit_container(m
);
1147 int bus_message_map_properties_changed(
1149 const struct bus_properties_map
*map
,
1153 int r
, invalidated
, i
;
1158 r
= bus_message_map_all_properties(m
, map
, userdata
);
1162 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1167 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1168 for (i
= 0; map
[i
].member
; i
++)
1169 if (streq(map
[i
].member
, member
)) {
1176 r
= sd_bus_message_exit_container(m
);
1183 int bus_map_all_properties(
1185 const char *destination
,
1187 const struct bus_properties_map
*map
,
1190 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1191 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1195 assert(destination
);
1199 r
= sd_bus_call_method(
1203 "org.freedesktop.DBus.Properties",
1211 return bus_message_map_all_properties(m
, map
, userdata
);
1214 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1217 assert(transport
>= 0);
1218 assert(transport
< _BUS_TRANSPORT_MAX
);
1221 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1222 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1224 switch (transport
) {
1226 case BUS_TRANSPORT_LOCAL
:
1228 r
= sd_bus_default_user(bus
);
1230 r
= sd_bus_default_system(bus
);
1234 case BUS_TRANSPORT_REMOTE
:
1235 r
= sd_bus_open_system_remote(bus
, host
);
1238 case BUS_TRANSPORT_MACHINE
:
1239 r
= sd_bus_open_system_machine(bus
, host
);
1243 assert_not_reached("Hmm, unknown transport type.");
1249 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1252 assert(transport
>= 0);
1253 assert(transport
< _BUS_TRANSPORT_MAX
);
1256 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1257 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1259 switch (transport
) {
1261 case BUS_TRANSPORT_LOCAL
:
1263 r
= bus_connect_user_systemd(bus
);
1265 r
= bus_connect_system_systemd(bus
);
1269 case BUS_TRANSPORT_REMOTE
:
1270 r
= sd_bus_open_system_remote(bus
, host
);
1273 case BUS_TRANSPORT_MACHINE
:
1274 r
= sd_bus_open_system_machine(bus
, host
);
1278 assert_not_reached("Hmm, unknown transport type.");
1284 int bus_property_get_bool(
1287 const char *interface
,
1288 const char *property
,
1289 sd_bus_message
*reply
,
1291 sd_bus_error
*error
) {
1293 int b
= *(bool*) userdata
;
1295 return sd_bus_message_append_basic(reply
, 'b', &b
);
1298 #if __SIZEOF_SIZE_T__ != 8
1299 int bus_property_get_size(
1302 const char *interface
,
1303 const char *property
,
1304 sd_bus_message
*reply
,
1306 sd_bus_error
*error
) {
1308 uint64_t sz
= *(size_t*) userdata
;
1310 return sd_bus_message_append_basic(reply
, 't', &sz
);
1314 #if __SIZEOF_LONG__ != 8
1315 int bus_property_get_long(
1318 const char *interface
,
1319 const char *property
,
1320 sd_bus_message
*reply
,
1322 sd_bus_error
*error
) {
1324 int64_t l
= *(long*) userdata
;
1326 return sd_bus_message_append_basic(reply
, 'x', &l
);
1329 int bus_property_get_ulong(
1332 const char *interface
,
1333 const char *property
,
1334 sd_bus_message
*reply
,
1336 sd_bus_error
*error
) {
1338 uint64_t ul
= *(unsigned long*) userdata
;
1340 return sd_bus_message_append_basic(reply
, 't', &ul
);
1344 int bus_log_parse_error(int r
) {
1345 return log_error_errno(r
, "Failed to parse bus message: %m");
1348 int bus_log_create_error(int r
) {
1349 return log_error_errno(r
, "Failed to create bus message: %m");
1352 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1358 return sd_bus_message_read(
1373 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1374 const char *eq
, *field
;
1380 eq
= strchr(assignment
, '=');
1382 log_error("Not an assignment: %s", assignment
);
1386 field
= strndupa(assignment
, eq
- assignment
);
1389 if (streq(field
, "CPUQuota")) {
1393 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1395 return bus_log_create_error(r
);
1397 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1399 } else if (endswith(eq
, "%")) {
1402 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1403 log_error("CPU quota '%s' invalid.", eq
);
1407 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1409 return bus_log_create_error(r
);
1411 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1413 log_error("CPU quota needs to be in percent.");
1418 return bus_log_create_error(r
);
1421 } else if (streq(field
, "EnvironmentFile")) {
1422 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1426 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1427 eq
[0] == '-' ? eq
+ 1 : eq
,
1434 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1436 return bus_log_create_error(r
);
1438 if (STR_IN_SET(field
,
1439 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1440 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1441 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1442 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1443 "SyslogLevelPrefix")) {
1445 r
= parse_boolean(eq
);
1447 log_error("Failed to parse boolean assignment %s.", assignment
);
1451 r
= sd_bus_message_append(m
, "v", "b", r
);
1453 } else if (streq(field
, "MemoryLimit")) {
1456 if (isempty(eq
) || streq(eq
, "infinity"))
1457 bytes
= (uint64_t) -1;
1459 r
= parse_size(eq
, 1024, &bytes
);
1461 log_error("Failed to parse bytes specification %s", assignment
);
1466 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1468 } else if (streq(field
, "TasksMax")) {
1471 if (isempty(eq
) || streq(eq
, "infinity"))
1474 r
= safe_atou64(eq
, &n
);
1476 log_error("Failed to parse maximum tasks specification %s", assignment
);
1481 r
= sd_bus_message_append(m
, "v", "t", n
);
1483 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1486 r
= cg_cpu_shares_parse(eq
, &u
);
1488 log_error("Failed to parse %s value %s.", field
, eq
);
1492 r
= sd_bus_message_append(m
, "v", "t", u
);
1494 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1497 r
= cg_cpu_shares_parse(eq
, &u
);
1499 log_error("Failed to parse %s value %s.", field
, eq
);
1503 r
= sd_bus_message_append(m
, "v", "t", u
);
1505 } else if (STR_IN_SET(field
,
1506 "User", "Group", "DevicePolicy", "KillMode",
1507 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1508 "StandardInput", "StandardOutput", "StandardError",
1509 "Description", "Slice", "Type", "WorkingDirectory",
1510 "RootDirectory", "SyslogIdentifier", "ProtectSystem"))
1511 r
= sd_bus_message_append(m
, "v", "s", eq
);
1513 else if (streq(field
, "SyslogLevel")) {
1516 level
= log_level_from_string(eq
);
1518 log_error("Failed to parse %s value %s.", field
, eq
);
1522 r
= sd_bus_message_append(m
, "v", "i", level
);
1524 } else if (streq(field
, "SyslogFacility")) {
1527 facility
= log_facility_unshifted_from_string(eq
);
1529 log_error("Failed to parse %s value %s.", field
, eq
);
1533 r
= sd_bus_message_append(m
, "v", "i", facility
);
1535 } else if (streq(field
, "DeviceAllow")) {
1538 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1540 const char *path
, *rwm
, *e
;
1542 e
= strchr(eq
, ' ');
1544 path
= strndupa(eq
, e
- eq
);
1551 if (!path_startswith(path
, "/dev")) {
1552 log_error("%s is not a device file in /dev.", path
);
1556 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1559 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1562 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1564 const char *path
, *bandwidth
, *e
;
1567 e
= strchr(eq
, ' ');
1569 path
= strndupa(eq
, e
- eq
);
1572 log_error("Failed to parse %s value %s.", field
, eq
);
1576 if (!path_startswith(path
, "/dev")) {
1577 log_error("%s is not a device file in /dev.", path
);
1581 r
= parse_size(bandwidth
, 1000, &bytes
);
1583 log_error("Failed to parse byte value %s.", bandwidth
);
1587 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1590 } else if (streq(field
, "BlockIODeviceWeight")) {
1593 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1595 const char *path
, *weight
, *e
;
1598 e
= strchr(eq
, ' ');
1600 path
= strndupa(eq
, e
- eq
);
1603 log_error("Failed to parse %s value %s.", field
, eq
);
1607 if (!path_startswith(path
, "/dev")) {
1608 log_error("%s is not a device file in /dev.", path
);
1612 r
= safe_atou64(weight
, &u
);
1614 log_error("Failed to parse %s value %s.", field
, weight
);
1617 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1620 } else if (rlimit_from_string(field
) >= 0) {
1623 if (streq(eq
, "infinity"))
1626 r
= safe_atou64(eq
, &rl
);
1628 log_error("Invalid resource limit: %s", eq
);
1633 r
= sd_bus_message_append(m
, "v", "t", rl
);
1635 } else if (streq(field
, "Nice")) {
1638 r
= safe_atoi32(eq
, &i
);
1640 log_error("Failed to parse %s value %s.", field
, eq
);
1644 r
= sd_bus_message_append(m
, "v", "i", i
);
1646 } else if (streq(field
, "Environment")) {
1649 r
= sd_bus_message_open_container(m
, 'v', "as");
1651 return bus_log_create_error(r
);
1653 r
= sd_bus_message_open_container(m
, 'a', "s");
1655 return bus_log_create_error(r
);
1660 _cleanup_free_
char *word
= NULL
;
1662 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1664 log_error("Failed to parse Environment value %s", eq
);
1670 if (!env_assignment_is_valid(word
)) {
1671 log_error("Invalid environment assignment: %s", eq
);
1675 r
= sd_bus_message_append_basic(m
, 's', word
);
1677 return bus_log_create_error(r
);
1680 r
= sd_bus_message_close_container(m
);
1682 return bus_log_create_error(r
);
1684 r
= sd_bus_message_close_container(m
);
1686 } else if (streq(field
, "KillSignal")) {
1689 sig
= signal_from_string_try_harder(eq
);
1691 log_error("Failed to parse %s value %s.", field
, eq
);
1695 r
= sd_bus_message_append(m
, "v", "i", sig
);
1697 } else if (streq(field
, "AccuracySec")) {
1700 r
= parse_sec(eq
, &u
);
1702 log_error("Failed to parse %s value %s", field
, eq
);
1706 r
= sd_bus_message_append(m
, "v", "t", u
);
1707 } else if (streq(field
, "TimerSlackNSec")) {
1710 r
= parse_nsec(eq
, &n
);
1712 log_error("Failed to parse %s value %s", field
, eq
);
1716 r
= sd_bus_message_append(m
, "v", "t", n
);
1717 } else if (streq(field
, "OOMScoreAdjust")) {
1720 r
= safe_atoi(eq
, &oa
);
1722 log_error("Failed to parse %s value %s", field
, eq
);
1726 if (!oom_score_adjust_is_valid(oa
)) {
1727 log_error("OOM score adjust value out of range");
1731 r
= sd_bus_message_append(m
, "v", "i", oa
);
1732 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1735 r
= sd_bus_message_open_container(m
, 'v', "as");
1737 return bus_log_create_error(r
);
1739 r
= sd_bus_message_open_container(m
, 'a', "s");
1741 return bus_log_create_error(r
);
1746 _cleanup_free_
char *word
= NULL
;
1749 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1751 log_error("Failed to parse %s value %s", field
, eq
);
1757 if (!utf8_is_valid(word
)) {
1758 log_error("Failed to parse %s value %s", field
, eq
);
1762 offset
= word
[0] == '-';
1763 if (!path_is_absolute(word
+ offset
)) {
1764 log_error("Failed to parse %s value %s", field
, eq
);
1768 path_kill_slashes(word
+ offset
);
1770 r
= sd_bus_message_append_basic(m
, 's', word
);
1772 return bus_log_create_error(r
);
1775 r
= sd_bus_message_close_container(m
);
1777 return bus_log_create_error(r
);
1779 r
= sd_bus_message_close_container(m
);
1782 log_error("Unknown assignment %s.", assignment
);
1787 return bus_log_create_error(r
);
1792 typedef struct BusWaitForJobs
{
1799 sd_bus_slot
*slot_job_removed
;
1800 sd_bus_slot
*slot_disconnected
;
1803 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1806 log_error("Warning! D-Bus connection terminated.");
1807 sd_bus_close(sd_bus_message_get_bus(m
));
1812 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1813 const char *path
, *unit
, *result
;
1814 BusWaitForJobs
*d
= userdata
;
1822 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1824 bus_log_parse_error(r
);
1828 found
= set_remove(d
->jobs
, (char*) path
);
1834 if (!isempty(result
))
1835 d
->result
= strdup(result
);
1838 d
->name
= strdup(unit
);
1843 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1847 set_free_free(d
->jobs
);
1849 sd_bus_slot_unref(d
->slot_disconnected
);
1850 sd_bus_slot_unref(d
->slot_job_removed
);
1852 sd_bus_unref(d
->bus
);
1860 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1861 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1867 d
= new0(BusWaitForJobs
, 1);
1871 d
->bus
= sd_bus_ref(bus
);
1873 /* When we are a bus client we match by sender. Direct
1874 * connections OTOH have no initialized sender field, and
1875 * hence we ignore the sender then */
1876 r
= sd_bus_add_match(
1878 &d
->slot_job_removed
,
1881 "sender='org.freedesktop.systemd1',"
1882 "interface='org.freedesktop.systemd1.Manager',"
1883 "member='JobRemoved',"
1884 "path='/org/freedesktop/systemd1'" :
1886 "interface='org.freedesktop.systemd1.Manager',"
1887 "member='JobRemoved',"
1888 "path='/org/freedesktop/systemd1'",
1889 match_job_removed
, d
);
1893 r
= sd_bus_add_match(
1895 &d
->slot_disconnected
,
1897 "sender='org.freedesktop.DBus.Local',"
1898 "interface='org.freedesktop.DBus.Local',"
1899 "member='Disconnected'",
1900 match_disconnected
, d
);
1910 static int bus_process_wait(sd_bus
*bus
) {
1914 r
= sd_bus_process(bus
, NULL
);
1920 r
= sd_bus_wait(bus
, (uint64_t) -1);
1926 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1927 _cleanup_free_
char *dbus_path
= NULL
;
1933 dbus_path
= unit_dbus_path_from_name(d
->name
);
1937 return sd_bus_get_property_string(d
->bus
,
1938 "org.freedesktop.systemd1",
1940 "org.freedesktop.systemd1.Service",
1946 static const struct {
1947 const char *result
, *explanation
;
1948 } explanations
[] = {
1949 { "resources", "a configured resource limit was exceeded" },
1950 { "timeout", "a timeout was exceeded" },
1951 { "exit-code", "the control process exited with error code" },
1952 { "signal", "a fatal signal was delivered to the control process" },
1953 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1954 { "watchdog", "the service failed to send watchdog ping" },
1955 { "start-limit", "start of the service was attempted too often" }
1958 static void log_job_error_with_service_result(const char* service
, const char *result
) {
1959 _cleanup_free_
char *service_shell_quoted
= NULL
;
1963 service_shell_quoted
= shell_maybe_quote(service
);
1965 if (!isempty(result
)) {
1968 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1969 if (streq(result
, explanations
[i
].result
))
1972 if (i
< ELEMENTSOF(explanations
)) {
1973 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1975 explanations
[i
].explanation
,
1976 strna(service_shell_quoted
));
1982 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1984 strna(service_shell_quoted
));
1987 /* For some results maybe additional explanation is required */
1988 if (streq_ptr(result
, "start-limit"))
1989 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
1990 strna(service_shell_quoted
));
1993 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
1999 if (streq(d
->result
, "canceled"))
2000 log_error("Job for %s canceled.", strna(d
->name
));
2001 else if (streq(d
->result
, "timeout"))
2002 log_error("Job for %s timed out.", strna(d
->name
));
2003 else if (streq(d
->result
, "dependency"))
2004 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2005 else if (streq(d
->result
, "invalid"))
2006 log_error("Job for %s invalid.", strna(d
->name
));
2007 else if (streq(d
->result
, "assert"))
2008 log_error("Assertion failed on job for %s.", strna(d
->name
));
2009 else if (streq(d
->result
, "unsupported"))
2010 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2011 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2014 _cleanup_free_
char *result
= NULL
;
2016 q
= bus_job_get_service_result(d
, &result
);
2018 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2020 log_job_error_with_service_result(d
->name
, result
);
2022 log_error("Job failed. See \"journalctl -xe\" for details.");
2026 if (streq(d
->result
, "canceled"))
2028 else if (streq(d
->result
, "timeout"))
2030 else if (streq(d
->result
, "dependency"))
2032 else if (streq(d
->result
, "invalid"))
2034 else if (streq(d
->result
, "assert"))
2036 else if (streq(d
->result
, "unsupported"))
2038 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2044 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2049 while (!set_isempty(d
->jobs
)) {
2052 q
= bus_process_wait(d
->bus
);
2054 return log_error_errno(q
, "Failed to wait for response: %m");
2057 q
= check_wait_response(d
, quiet
);
2058 /* Return the first error as it is most likely to be
2060 if (q
< 0 && r
== 0)
2063 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2066 d
->name
= mfree(d
->name
);
2067 d
->result
= mfree(d
->result
);
2073 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2078 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2082 return set_put_strdup(d
->jobs
, path
);
2085 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2088 r
= bus_wait_for_jobs_add(d
, path
);
2092 return bus_wait_for_jobs(d
, quiet
);
2095 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2096 const char *type
, *path
, *source
;
2099 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2101 return bus_log_parse_error(r
);
2103 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2105 if (streq(type
, "symlink"))
2106 log_info("Created symlink from %s to %s.", path
, source
);
2108 log_info("Removed symlink %s.", path
);
2111 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2116 return bus_log_parse_error(r
);
2118 r
= sd_bus_message_exit_container(m
);
2120 return bus_log_parse_error(r
);
2126 * bus_path_encode_unique() - encode unique object path
2127 * @b: bus connection or NULL
2128 * @prefix: object path prefix
2129 * @sender_id: unique-name of client, or NULL
2130 * @external_id: external ID to be chosen by client, or NULL
2131 * @ret_path: storage for encoded object path pointer
2133 * Whenever we provide a bus API that allows clients to create and manage
2134 * server-side objects, we need to provide a unique name for these objects. If
2135 * we let the server choose the name, we suffer from a race condition: If a
2136 * client creates an object asynchronously, it cannot destroy that object until
2137 * it received the method reply. It cannot know the name of the new object,
2138 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2140 * Therefore, many APIs allow the client to choose the unique name for newly
2141 * created objects. There're two problems to solve, though:
2142 * 1) Object names are usually defined via dbus object paths, which are
2143 * usually globally namespaced. Therefore, multiple clients must be able
2144 * to choose unique object names without interference.
2145 * 2) If multiple libraries share the same bus connection, they must be
2146 * able to choose unique object names without interference.
2147 * The first problem is solved easily by prefixing a name with the
2148 * unique-bus-name of a connection. The server side must enforce this and
2149 * reject any other name. The second problem is solved by providing unique
2150 * suffixes from within sd-bus.
2152 * This helper allows clients to create unique object-paths. It uses the
2153 * template '/prefix/sender_id/external_id' and returns the new path in
2154 * @ret_path (must be freed by the caller).
2155 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2156 * NULL, this function allocates a unique suffix via @b (by requesting a new
2157 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2160 * Returns: 0 on success, negative error code on failure.
2162 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2163 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2164 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2167 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2168 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2169 assert_return(ret_path
, -EINVAL
);
2172 r
= sd_bus_get_unique_name(b
, &sender_id
);
2178 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2179 external_id
= external_buf
;
2182 sender_label
= bus_label_escape(sender_id
);
2186 external_label
= bus_label_escape(external_id
);
2187 if (!external_label
)
2190 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2199 * bus_path_decode_unique() - decode unique object path
2200 * @path: object path to decode
2201 * @prefix: object path prefix
2202 * @ret_sender: output parameter for sender-id label
2203 * @ret_external: output parameter for external-id label
2205 * This does the reverse of bus_path_encode_unique() (see its description for
2206 * details). Both trailing labels, sender-id and external-id, are unescaped and
2207 * returned in the given output parameters (the caller must free them).
2209 * Note that this function returns 0 if the path does not match the template
2210 * (see bus_path_encode_unique()), 1 if it matched.
2212 * Returns: Negative error code on failure, 0 if the given object path does not
2213 * match the template (return parameters are set to NULL), 1 if it was
2214 * parsed successfully (return parameters contain allocated labels).
2216 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2218 char *sender
, *external
;
2220 assert(object_path_is_valid(path
));
2221 assert(object_path_is_valid(prefix
));
2223 assert(ret_external
);
2225 p
= object_path_startswith(path
, prefix
);
2228 *ret_external
= NULL
;
2235 *ret_external
= NULL
;
2239 sender
= bus_label_unescape_n(p
, q
- p
);
2240 external
= bus_label_unescape(q
+ 1);
2241 if (!sender
|| !external
) {
2247 *ret_sender
= sender
;
2248 *ret_external
= external
;
2252 bool is_kdbus_wanted(void) {
2253 _cleanup_free_
char *value
= NULL
;
2255 const bool configured
= true;
2257 const bool configured
= false;
2262 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2265 r
= get_proc_cmdline_key("kdbus=", &value
);
2269 return parse_boolean(value
) == 1;
2272 bool is_kdbus_available(void) {
2273 _cleanup_close_
int fd
= -1;
2274 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2276 if (!is_kdbus_wanted())
2279 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2283 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2286 int bus_property_get_rlimit(
2289 const char *interface
,
2290 const char *property
,
2291 sd_bus_message
*reply
,
2293 sd_bus_error
*error
) {
2303 rl
= *(struct rlimit
**) userdata
;
2307 struct rlimit buf
= {};
2310 z
= rlimit_from_string(strstr(property
, "Limit"));
2317 /* rlim_t might have different sizes, let's map
2318 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2320 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2322 return sd_bus_message_append(reply
, "t", u
);