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 "path-util.h"
42 #include "signal-util.h"
43 #include "string-util.h"
45 #include "unit-name.h"
49 static int name_owner_change_callback(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
50 sd_event
*e
= userdata
;
55 sd_bus_close(sd_bus_message_get_bus(m
));
61 int bus_async_unregister_and_exit(sd_event
*e
, sd_bus
*bus
, const char *name
) {
62 _cleanup_free_
char *match
= NULL
;
70 /* We unregister the name here and then wait for the
71 * NameOwnerChanged signal for this event to arrive before we
72 * quit. We do this in order to make sure that any queued
73 * requests are still processed before we really exit. */
75 r
= sd_bus_get_unique_name(bus
, &unique
);
80 "sender='org.freedesktop.DBus',"
82 "interface='org.freedesktop.DBus',"
83 "member='NameOwnerChanged',"
84 "path='/org/freedesktop/DBus',"
87 "arg2=''", name
, unique
);
91 r
= sd_bus_add_match(bus
, NULL
, match
, name_owner_change_callback
, e
);
95 r
= sd_bus_release_name(bus
, name
);
102 int bus_event_loop_with_idle(
107 check_idle_t check_idle
,
109 bool exiting
= false;
119 r
= sd_event_get_state(e
);
122 if (r
== SD_EVENT_FINISHED
)
126 idle
= check_idle(userdata
);
130 r
= sd_event_run(e
, exiting
|| !idle
? (uint64_t) -1 : timeout
);
134 if (r
== 0 && !exiting
&& idle
) {
136 r
= sd_bus_try_close(bus
);
140 /* Fallback for dbus1 connections: we
141 * unregister the name and wait for the
142 * response to come through for it */
143 if (r
== -EOPNOTSUPP
) {
145 /* Inform the service manager that we
146 * are going down, so that it will
147 * queue all further start requests,
148 * instead of assuming we are already
150 sd_notify(false, "STOPPING=1");
152 r
= bus_async_unregister_and_exit(e
, bus
, name
);
168 r
= sd_event_get_exit_code(e
, &code
);
175 int bus_name_has_owner(sd_bus
*c
, const char *name
, sd_bus_error
*error
) {
176 _cleanup_bus_message_unref_ sd_bus_message
*rep
= NULL
;
177 int r
, has_owner
= 0;
182 r
= sd_bus_call_method(c
,
183 "org.freedesktop.DBus",
184 "/org/freedesktop/dbus",
185 "org.freedesktop.DBus",
194 r
= sd_bus_message_read_basic(rep
, 'b', &has_owner
);
196 return sd_bus_error_set_errno(error
, r
);
201 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
202 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
208 if (good_user
== UID_INVALID
)
211 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
215 /* Don't trust augmented credentials for authorization */
216 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
218 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
222 return sender_uid
== good_user
;
226 sd_bus_message
*call
,
229 const char **details
,
239 /* Tests non-interactively! */
241 r
= check_good_user(call
, good_user
);
245 r
= sd_bus_query_sender_privilege(call
, capability
);
252 _cleanup_bus_message_unref_ sd_bus_message
*request
= NULL
;
253 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
254 int authorized
= false, challenge
= false;
255 const char *sender
, **k
, **v
;
257 sender
= sd_bus_message_get_sender(call
);
261 r
= sd_bus_message_new_method_call(
264 "org.freedesktop.PolicyKit1",
265 "/org/freedesktop/PolicyKit1/Authority",
266 "org.freedesktop.PolicyKit1.Authority",
267 "CheckAuthorization");
271 r
= sd_bus_message_append(
274 "system-bus-name", 1, "name", "s", sender
,
279 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
283 STRV_FOREACH_PAIR(k
, v
, details
) {
284 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
289 r
= sd_bus_message_close_container(request
);
293 r
= sd_bus_message_append(request
, "us", 0, NULL
);
297 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
299 /* Treat no PK available as access denied */
300 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
301 sd_bus_error_free(e
);
308 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
312 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
320 *_challenge
= challenge
;
331 typedef struct AsyncPolkitQuery
{
332 sd_bus_message
*request
, *reply
;
333 sd_bus_message_handler_t callback
;
339 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
344 sd_bus_slot_unref(q
->slot
);
346 if (q
->registry
&& q
->request
)
347 hashmap_remove(q
->registry
, q
->request
);
349 sd_bus_message_unref(q
->request
);
350 sd_bus_message_unref(q
->reply
);
355 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
356 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
357 AsyncPolkitQuery
*q
= userdata
;
363 q
->slot
= sd_bus_slot_unref(q
->slot
);
364 q
->reply
= sd_bus_message_ref(reply
);
366 r
= sd_bus_message_rewind(q
->request
, true);
368 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
372 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
373 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
376 async_polkit_query_free(q
);
383 int bus_verify_polkit_async(
384 sd_bus_message
*call
,
387 const char **details
,
391 sd_bus_error
*error
) {
394 _cleanup_bus_message_unref_ sd_bus_message
*pk
= NULL
;
396 const char *sender
, **k
, **v
;
397 sd_bus_message_handler_t callback
;
407 r
= check_good_user(call
, good_user
);
412 q
= hashmap_get(*registry
, call
);
414 int authorized
, challenge
;
416 /* This is the second invocation of this function, and
417 * there's already a response from polkit, let's
421 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
422 const sd_bus_error
*e
;
424 /* Copy error from polkit reply */
425 e
= sd_bus_message_get_error(q
->reply
);
426 sd_bus_error_copy(error
, e
);
428 /* Treat no PK available as access denied */
429 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
))
432 return -sd_bus_error_get_errno(e
);
435 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
437 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
446 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
452 r
= sd_bus_query_sender_privilege(call
, capability
);
459 if (sd_bus_get_current_message(call
->bus
) != call
)
462 callback
= sd_bus_get_current_handler(call
->bus
);
466 userdata
= sd_bus_get_current_userdata(call
->bus
);
468 sender
= sd_bus_message_get_sender(call
);
472 c
= sd_bus_message_get_allow_interactive_authorization(call
);
478 r
= hashmap_ensure_allocated(registry
, NULL
);
482 r
= sd_bus_message_new_method_call(
485 "org.freedesktop.PolicyKit1",
486 "/org/freedesktop/PolicyKit1/Authority",
487 "org.freedesktop.PolicyKit1.Authority",
488 "CheckAuthorization");
492 r
= sd_bus_message_append(
495 "system-bus-name", 1, "name", "s", sender
,
500 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
504 STRV_FOREACH_PAIR(k
, v
, details
) {
505 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
510 r
= sd_bus_message_close_container(pk
);
514 r
= sd_bus_message_append(pk
, "us", !!interactive
, NULL
);
518 q
= new0(AsyncPolkitQuery
, 1);
522 q
->request
= sd_bus_message_ref(call
);
523 q
->callback
= callback
;
524 q
->userdata
= userdata
;
526 r
= hashmap_put(*registry
, call
, q
);
528 async_polkit_query_free(q
);
532 q
->registry
= *registry
;
534 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
536 async_polkit_query_free(q
);
546 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
550 while ((q
= hashmap_steal_first(registry
)))
551 async_polkit_query_free(q
);
553 hashmap_free(registry
);
557 int bus_check_peercred(sd_bus
*c
) {
564 fd
= sd_bus_get_fd(c
);
568 l
= sizeof(struct ucred
);
569 if (getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &ucred
, &l
) < 0)
572 if (l
!= sizeof(struct ucred
))
575 if (ucred
.uid
!= 0 && ucred
.uid
!= geteuid())
581 int bus_connect_system_systemd(sd_bus
**_bus
) {
582 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
588 return sd_bus_default_system(_bus
);
590 /* If we are root and kdbus is not available, then let's talk
591 * directly to the system instance, instead of going via the
594 r
= sd_bus_new(&bus
);
598 r
= sd_bus_set_address(bus
, KERNEL_SYSTEM_BUS_ADDRESS
);
602 bus
->bus_client
= true;
604 r
= sd_bus_start(bus
);
611 bus
= sd_bus_unref(bus
);
613 r
= sd_bus_new(&bus
);
617 r
= sd_bus_set_address(bus
, "unix:path=/run/systemd/private");
621 r
= sd_bus_start(bus
);
623 return sd_bus_default_system(_bus
);
625 r
= bus_check_peercred(bus
);
635 int bus_connect_user_systemd(sd_bus
**_bus
) {
636 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
637 _cleanup_free_
char *ee
= NULL
;
641 /* Try via kdbus first, and then directly */
645 r
= sd_bus_new(&bus
);
649 if (asprintf(&bus
->address
, KERNEL_USER_BUS_ADDRESS_FMT
, getuid()) < 0)
652 bus
->bus_client
= true;
654 r
= sd_bus_start(bus
);
661 bus
= sd_bus_unref(bus
);
663 e
= secure_getenv("XDG_RUNTIME_DIR");
665 return sd_bus_default_user(_bus
);
667 ee
= bus_address_escape(e
);
671 r
= sd_bus_new(&bus
);
675 bus
->address
= strjoin("unix:path=", ee
, "/systemd/private", NULL
);
679 r
= sd_bus_start(bus
);
681 return sd_bus_default_user(_bus
);
683 r
= bus_check_peercred(bus
);
693 int bus_print_property(const char *name
, sd_bus_message
*property
, bool all
) {
695 const char *contents
;
701 r
= sd_bus_message_peek_type(property
, &type
, &contents
);
707 case SD_BUS_TYPE_STRING
: {
710 r
= sd_bus_message_read_basic(property
, type
, &s
);
714 if (all
|| !isempty(s
)) {
715 _cleanup_free_
char *escaped
= NULL
;
717 escaped
= xescape(s
, "\n");
721 printf("%s=%s\n", name
, escaped
);
727 case SD_BUS_TYPE_BOOLEAN
: {
730 r
= sd_bus_message_read_basic(property
, type
, &b
);
734 printf("%s=%s\n", name
, yes_no(b
));
739 case SD_BUS_TYPE_UINT64
: {
742 r
= sd_bus_message_read_basic(property
, type
, &u
);
746 /* Yes, heuristics! But we can change this check
747 * should it turn out to not be sufficient */
749 if (endswith(name
, "Timestamp")) {
750 char timestamp
[FORMAT_TIMESTAMP_MAX
], *t
;
752 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
754 printf("%s=%s\n", name
, strempty(t
));
756 } else if (strstr(name
, "USec")) {
757 char timespan
[FORMAT_TIMESPAN_MAX
];
759 printf("%s=%s\n", name
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
761 printf("%s=%llu\n", name
, (unsigned long long) u
);
766 case SD_BUS_TYPE_INT64
: {
769 r
= sd_bus_message_read_basic(property
, type
, &i
);
773 printf("%s=%lld\n", name
, (long long) i
);
778 case SD_BUS_TYPE_UINT32
: {
781 r
= sd_bus_message_read_basic(property
, type
, &u
);
785 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
786 printf("%s=%04o\n", name
, u
);
788 printf("%s=%u\n", name
, (unsigned) u
);
793 case SD_BUS_TYPE_INT32
: {
796 r
= sd_bus_message_read_basic(property
, type
, &i
);
800 printf("%s=%i\n", name
, (int) i
);
804 case SD_BUS_TYPE_DOUBLE
: {
807 r
= sd_bus_message_read_basic(property
, type
, &d
);
811 printf("%s=%g\n", name
, d
);
815 case SD_BUS_TYPE_ARRAY
:
816 if (streq(contents
, "s")) {
820 r
= sd_bus_message_enter_container(property
, SD_BUS_TYPE_ARRAY
, contents
);
824 while((r
= sd_bus_message_read_basic(property
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
825 _cleanup_free_
char *escaped
= NULL
;
830 escaped
= xescape(str
, "\n ");
834 printf("%s%s", first
? "" : " ", escaped
);
846 r
= sd_bus_message_exit_container(property
);
852 } else if (streq(contents
, "y")) {
856 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
865 for (i
= 0; i
< n
; i
++)
866 printf("%02x", u
[i
]);
873 } else if (streq(contents
, "u")) {
877 r
= sd_bus_message_read_array(property
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
886 for (i
= 0; i
< n
; i
++)
887 printf("%08x", u
[i
]);
901 int bus_print_all_properties(sd_bus
*bus
, const char *dest
, const char *path
, char **filter
, bool all
) {
902 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
903 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
909 r
= sd_bus_call_method(bus
,
912 "org.freedesktop.DBus.Properties",
920 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
924 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
926 const char *contents
;
928 r
= sd_bus_message_read_basic(reply
, SD_BUS_TYPE_STRING
, &name
);
932 if (!filter
|| strv_find(filter
, name
)) {
933 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
937 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
941 r
= bus_print_property(name
, reply
, all
);
946 printf("%s=[unprintable]\n", name
);
947 /* skip what we didn't read */
948 r
= sd_bus_message_skip(reply
, contents
);
953 r
= sd_bus_message_exit_container(reply
);
957 r
= sd_bus_message_skip(reply
, "v");
962 r
= sd_bus_message_exit_container(reply
);
969 r
= sd_bus_message_exit_container(reply
);
976 int bus_map_id128(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
977 sd_id128_t
*p
= userdata
;
982 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, &v
, &n
);
989 memcpy((*p
).bytes
, v
, n
);
996 static int map_basic(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1000 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
1005 case SD_BUS_TYPE_STRING
: {
1007 char **p
= userdata
;
1009 r
= sd_bus_message_read_basic(m
, type
, &s
);
1016 r
= free_and_strdup(p
, s
);
1020 case SD_BUS_TYPE_ARRAY
: {
1021 _cleanup_strv_free_
char **l
= NULL
;
1022 char ***p
= userdata
;
1024 r
= bus_message_read_strv_extend(m
, &l
);
1035 case SD_BUS_TYPE_BOOLEAN
: {
1039 r
= sd_bus_message_read_basic(m
, type
, &b
);
1048 case SD_BUS_TYPE_UINT32
: {
1050 uint32_t *p
= userdata
;
1052 r
= sd_bus_message_read_basic(m
, type
, &u
);
1061 case SD_BUS_TYPE_UINT64
: {
1063 uint64_t *p
= userdata
;
1065 r
= sd_bus_message_read_basic(m
, type
, &t
);
1081 int bus_message_map_all_properties(
1083 const struct bus_properties_map
*map
,
1086 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1092 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
1096 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
1097 const struct bus_properties_map
*prop
;
1099 const char *contents
;
1103 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
);
1107 for (i
= 0, prop
= NULL
; map
[i
].member
; i
++)
1108 if (streq(map
[i
].member
, member
)) {
1114 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
1118 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
1122 v
= (uint8_t *)userdata
+ prop
->offset
;
1124 r
= prop
->set(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1126 r
= map_basic(sd_bus_message_get_bus(m
), member
, m
, &error
, v
);
1130 r
= sd_bus_message_exit_container(m
);
1134 r
= sd_bus_message_skip(m
, "v");
1139 r
= sd_bus_message_exit_container(m
);
1146 return sd_bus_message_exit_container(m
);
1149 int bus_message_map_properties_changed(
1151 const struct bus_properties_map
*map
,
1155 int r
, invalidated
, i
;
1160 r
= bus_message_map_all_properties(m
, map
, userdata
);
1164 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "s");
1169 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &member
)) > 0)
1170 for (i
= 0; map
[i
].member
; i
++)
1171 if (streq(map
[i
].member
, member
)) {
1178 r
= sd_bus_message_exit_container(m
);
1185 int bus_map_all_properties(
1187 const char *destination
,
1189 const struct bus_properties_map
*map
,
1192 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1193 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1197 assert(destination
);
1201 r
= sd_bus_call_method(
1205 "org.freedesktop.DBus.Properties",
1213 return bus_message_map_all_properties(m
, map
, userdata
);
1216 int bus_connect_transport(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1219 assert(transport
>= 0);
1220 assert(transport
< _BUS_TRANSPORT_MAX
);
1223 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1224 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1226 switch (transport
) {
1228 case BUS_TRANSPORT_LOCAL
:
1230 r
= sd_bus_default_user(bus
);
1232 r
= sd_bus_default_system(bus
);
1236 case BUS_TRANSPORT_REMOTE
:
1237 r
= sd_bus_open_system_remote(bus
, host
);
1240 case BUS_TRANSPORT_MACHINE
:
1241 r
= sd_bus_open_system_machine(bus
, host
);
1245 assert_not_reached("Hmm, unknown transport type.");
1251 int bus_connect_transport_systemd(BusTransport transport
, const char *host
, bool user
, sd_bus
**bus
) {
1254 assert(transport
>= 0);
1255 assert(transport
< _BUS_TRANSPORT_MAX
);
1258 assert_return((transport
== BUS_TRANSPORT_LOCAL
) == !host
, -EINVAL
);
1259 assert_return(transport
== BUS_TRANSPORT_LOCAL
|| !user
, -EOPNOTSUPP
);
1261 switch (transport
) {
1263 case BUS_TRANSPORT_LOCAL
:
1265 r
= bus_connect_user_systemd(bus
);
1267 r
= bus_connect_system_systemd(bus
);
1271 case BUS_TRANSPORT_REMOTE
:
1272 r
= sd_bus_open_system_remote(bus
, host
);
1275 case BUS_TRANSPORT_MACHINE
:
1276 r
= sd_bus_open_system_machine(bus
, host
);
1280 assert_not_reached("Hmm, unknown transport type.");
1286 int bus_property_get_bool(
1289 const char *interface
,
1290 const char *property
,
1291 sd_bus_message
*reply
,
1293 sd_bus_error
*error
) {
1295 int b
= *(bool*) userdata
;
1297 return sd_bus_message_append_basic(reply
, 'b', &b
);
1300 #if __SIZEOF_SIZE_T__ != 8
1301 int bus_property_get_size(
1304 const char *interface
,
1305 const char *property
,
1306 sd_bus_message
*reply
,
1308 sd_bus_error
*error
) {
1310 uint64_t sz
= *(size_t*) userdata
;
1312 return sd_bus_message_append_basic(reply
, 't', &sz
);
1316 #if __SIZEOF_LONG__ != 8
1317 int bus_property_get_long(
1320 const char *interface
,
1321 const char *property
,
1322 sd_bus_message
*reply
,
1324 sd_bus_error
*error
) {
1326 int64_t l
= *(long*) userdata
;
1328 return sd_bus_message_append_basic(reply
, 'x', &l
);
1331 int bus_property_get_ulong(
1334 const char *interface
,
1335 const char *property
,
1336 sd_bus_message
*reply
,
1338 sd_bus_error
*error
) {
1340 uint64_t ul
= *(unsigned long*) userdata
;
1342 return sd_bus_message_append_basic(reply
, 't', &ul
);
1346 int bus_log_parse_error(int r
) {
1347 return log_error_errno(r
, "Failed to parse bus message: %m");
1350 int bus_log_create_error(int r
) {
1351 return log_error_errno(r
, "Failed to create bus message: %m");
1354 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
1360 return sd_bus_message_read(
1375 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
1376 const char *eq
, *field
;
1382 eq
= strchr(assignment
, '=');
1384 log_error("Not an assignment: %s", assignment
);
1388 field
= strndupa(assignment
, eq
- assignment
);
1391 if (streq(field
, "CPUQuota")) {
1395 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1397 return bus_log_create_error(r
);
1399 r
= sd_bus_message_append(m
, "v", "t", USEC_INFINITY
);
1401 } else if (endswith(eq
, "%")) {
1404 if (sscanf(eq
, "%lf%%", &percent
) != 1 || percent
<= 0) {
1405 log_error("CPU quota '%s' invalid.", eq
);
1409 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "CPUQuotaPerSecUSec");
1411 return bus_log_create_error(r
);
1413 r
= sd_bus_message_append(m
, "v", "t", (usec_t
) percent
* USEC_PER_SEC
/ 100);
1415 log_error("CPU quota needs to be in percent.");
1420 return bus_log_create_error(r
);
1423 } else if (streq(field
, "EnvironmentFile")) {
1424 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, "EnvironmentFiles");
1428 r
= sd_bus_message_append(m
, "v", "a(sb)", 1,
1429 eq
[0] == '-' ? eq
+ 1 : eq
,
1436 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1438 return bus_log_create_error(r
);
1440 if (STR_IN_SET(field
,
1441 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
1442 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1443 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
1444 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
1445 "SyslogLevelPrefix")) {
1447 r
= parse_boolean(eq
);
1449 log_error("Failed to parse boolean assignment %s.", assignment
);
1453 r
= sd_bus_message_append(m
, "v", "b", r
);
1455 } else if (streq(field
, "MemoryLimit")) {
1458 if (isempty(eq
) || streq(eq
, "infinity"))
1459 bytes
= (uint64_t) -1;
1461 r
= parse_size(eq
, 1024, &bytes
);
1463 log_error("Failed to parse bytes specification %s", assignment
);
1468 r
= sd_bus_message_append(m
, "v", "t", bytes
);
1470 } else if (streq(field
, "TasksMax")) {
1473 if (isempty(eq
) || streq(eq
, "infinity"))
1476 r
= safe_atou64(eq
, &n
);
1478 log_error("Failed to parse maximum tasks specification %s", assignment
);
1483 r
= sd_bus_message_append(m
, "v", "t", n
);
1485 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
1488 r
= cg_cpu_shares_parse(eq
, &u
);
1490 log_error("Failed to parse %s value %s.", field
, eq
);
1494 r
= sd_bus_message_append(m
, "v", "t", u
);
1496 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
1499 r
= cg_cpu_shares_parse(eq
, &u
);
1501 log_error("Failed to parse %s value %s.", field
, eq
);
1505 r
= sd_bus_message_append(m
, "v", "t", u
);
1507 } else if (STR_IN_SET(field
,
1508 "User", "Group", "DevicePolicy", "KillMode",
1509 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1510 "StandardInput", "StandardOutput", "StandardError",
1511 "Description", "Slice", "Type", "WorkingDirectory",
1512 "RootDirectory", "SyslogIdentifier", "ProtectSystem"))
1513 r
= sd_bus_message_append(m
, "v", "s", eq
);
1515 else if (streq(field
, "SyslogLevel")) {
1518 level
= log_level_from_string(eq
);
1520 log_error("Failed to parse %s value %s.", field
, eq
);
1524 r
= sd_bus_message_append(m
, "v", "i", level
);
1526 } else if (streq(field
, "SyslogFacility")) {
1529 facility
= log_facility_unshifted_from_string(eq
);
1531 log_error("Failed to parse %s value %s.", field
, eq
);
1535 r
= sd_bus_message_append(m
, "v", "i", facility
);
1537 } else if (streq(field
, "DeviceAllow")) {
1540 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
1542 const char *path
, *rwm
, *e
;
1544 e
= strchr(eq
, ' ');
1546 path
= strndupa(eq
, e
- eq
);
1553 if (!path_startswith(path
, "/dev")) {
1554 log_error("%s is not a device file in /dev.", path
);
1558 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
1561 } else if (STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1564 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1566 const char *path
, *bandwidth
, *e
;
1569 e
= strchr(eq
, ' ');
1571 path
= strndupa(eq
, e
- eq
);
1574 log_error("Failed to parse %s value %s.", field
, eq
);
1578 if (!path_startswith(path
, "/dev")) {
1579 log_error("%s is not a device file in /dev.", path
);
1583 r
= parse_size(bandwidth
, 1000, &bytes
);
1585 log_error("Failed to parse byte value %s.", bandwidth
);
1589 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
1592 } else if (streq(field
, "BlockIODeviceWeight")) {
1595 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
1597 const char *path
, *weight
, *e
;
1600 e
= strchr(eq
, ' ');
1602 path
= strndupa(eq
, e
- eq
);
1605 log_error("Failed to parse %s value %s.", field
, eq
);
1609 if (!path_startswith(path
, "/dev")) {
1610 log_error("%s is not a device file in /dev.", path
);
1614 r
= safe_atou64(weight
, &u
);
1616 log_error("Failed to parse %s value %s.", field
, weight
);
1619 r
= sd_bus_message_append(m
, "v", "a(st)", path
, u
);
1622 } else if (rlimit_from_string(field
) >= 0) {
1625 if (streq(eq
, "infinity"))
1628 r
= safe_atou64(eq
, &rl
);
1630 log_error("Invalid resource limit: %s", eq
);
1635 r
= sd_bus_message_append(m
, "v", "t", rl
);
1637 } else if (streq(field
, "Nice")) {
1640 r
= safe_atoi32(eq
, &i
);
1642 log_error("Failed to parse %s value %s.", field
, eq
);
1646 r
= sd_bus_message_append(m
, "v", "i", i
);
1648 } else if (streq(field
, "Environment")) {
1651 r
= sd_bus_message_open_container(m
, 'v', "as");
1653 return bus_log_create_error(r
);
1655 r
= sd_bus_message_open_container(m
, 'a', "s");
1657 return bus_log_create_error(r
);
1662 _cleanup_free_
char *word
= NULL
;
1664 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
1666 log_error("Failed to parse Environment value %s", eq
);
1672 if (!env_assignment_is_valid(word
)) {
1673 log_error("Invalid environment assignment: %s", eq
);
1677 r
= sd_bus_message_append_basic(m
, 's', word
);
1679 return bus_log_create_error(r
);
1682 r
= sd_bus_message_close_container(m
);
1684 return bus_log_create_error(r
);
1686 r
= sd_bus_message_close_container(m
);
1688 } else if (streq(field
, "KillSignal")) {
1691 sig
= signal_from_string_try_harder(eq
);
1693 log_error("Failed to parse %s value %s.", field
, eq
);
1697 r
= sd_bus_message_append(m
, "v", "i", sig
);
1699 } else if (streq(field
, "AccuracySec")) {
1702 r
= parse_sec(eq
, &u
);
1704 log_error("Failed to parse %s value %s", field
, eq
);
1708 r
= sd_bus_message_append(m
, "v", "t", u
);
1709 } else if (streq(field
, "TimerSlackNSec")) {
1712 r
= parse_nsec(eq
, &n
);
1714 log_error("Failed to parse %s value %s", field
, eq
);
1718 r
= sd_bus_message_append(m
, "v", "t", n
);
1719 } else if (streq(field
, "OOMScoreAdjust")) {
1722 r
= safe_atoi(eq
, &oa
);
1724 log_error("Failed to parse %s value %s", field
, eq
);
1728 if (!oom_score_adjust_is_valid(oa
)) {
1729 log_error("OOM score adjust value out of range");
1733 r
= sd_bus_message_append(m
, "v", "i", oa
);
1734 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1737 r
= sd_bus_message_open_container(m
, 'v', "as");
1739 return bus_log_create_error(r
);
1741 r
= sd_bus_message_open_container(m
, 'a', "s");
1743 return bus_log_create_error(r
);
1748 _cleanup_free_
char *word
= NULL
;
1751 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1753 log_error("Failed to parse %s value %s", field
, eq
);
1759 if (!utf8_is_valid(word
)) {
1760 log_error("Failed to parse %s value %s", field
, eq
);
1764 offset
= word
[0] == '-';
1765 if (!path_is_absolute(word
+ offset
)) {
1766 log_error("Failed to parse %s value %s", field
, eq
);
1770 path_kill_slashes(word
+ offset
);
1772 r
= sd_bus_message_append_basic(m
, 's', word
);
1774 return bus_log_create_error(r
);
1777 r
= sd_bus_message_close_container(m
);
1779 return bus_log_create_error(r
);
1781 r
= sd_bus_message_close_container(m
);
1784 log_error("Unknown assignment %s.", assignment
);
1789 return bus_log_create_error(r
);
1794 typedef struct BusWaitForJobs
{
1801 sd_bus_slot
*slot_job_removed
;
1802 sd_bus_slot
*slot_disconnected
;
1805 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1808 log_error("Warning! D-Bus connection terminated.");
1809 sd_bus_close(sd_bus_message_get_bus(m
));
1814 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1815 const char *path
, *unit
, *result
;
1816 BusWaitForJobs
*d
= userdata
;
1824 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1826 bus_log_parse_error(r
);
1830 found
= set_remove(d
->jobs
, (char*) path
);
1836 if (!isempty(result
))
1837 d
->result
= strdup(result
);
1840 d
->name
= strdup(unit
);
1845 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1849 set_free_free(d
->jobs
);
1851 sd_bus_slot_unref(d
->slot_disconnected
);
1852 sd_bus_slot_unref(d
->slot_job_removed
);
1854 sd_bus_unref(d
->bus
);
1862 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1863 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1869 d
= new0(BusWaitForJobs
, 1);
1873 d
->bus
= sd_bus_ref(bus
);
1875 /* When we are a bus client we match by sender. Direct
1876 * connections OTOH have no initialized sender field, and
1877 * hence we ignore the sender then */
1878 r
= sd_bus_add_match(
1880 &d
->slot_job_removed
,
1883 "sender='org.freedesktop.systemd1',"
1884 "interface='org.freedesktop.systemd1.Manager',"
1885 "member='JobRemoved',"
1886 "path='/org/freedesktop/systemd1'" :
1888 "interface='org.freedesktop.systemd1.Manager',"
1889 "member='JobRemoved',"
1890 "path='/org/freedesktop/systemd1'",
1891 match_job_removed
, d
);
1895 r
= sd_bus_add_match(
1897 &d
->slot_disconnected
,
1899 "sender='org.freedesktop.DBus.Local',"
1900 "interface='org.freedesktop.DBus.Local',"
1901 "member='Disconnected'",
1902 match_disconnected
, d
);
1912 static int bus_process_wait(sd_bus
*bus
) {
1916 r
= sd_bus_process(bus
, NULL
);
1922 r
= sd_bus_wait(bus
, (uint64_t) -1);
1928 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1929 _cleanup_free_
char *dbus_path
= NULL
;
1935 dbus_path
= unit_dbus_path_from_name(d
->name
);
1939 return sd_bus_get_property_string(d
->bus
,
1940 "org.freedesktop.systemd1",
1942 "org.freedesktop.systemd1.Service",
1948 static const struct {
1949 const char *result
, *explanation
;
1950 } explanations
[] = {
1951 { "resources", "a configured resource limit was exceeded" },
1952 { "timeout", "a timeout was exceeded" },
1953 { "exit-code", "the control process exited with error code" },
1954 { "signal", "a fatal signal was delivered to the control process" },
1955 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1956 { "watchdog", "the service failed to send watchdog ping" },
1957 { "start-limit", "start of the service was attempted too often" }
1960 static void log_job_error_with_service_result(const char* service
, const char *result
) {
1961 _cleanup_free_
char *service_shell_quoted
= NULL
;
1965 service_shell_quoted
= shell_maybe_quote(service
);
1967 if (!isempty(result
)) {
1970 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1971 if (streq(result
, explanations
[i
].result
))
1974 if (i
< ELEMENTSOF(explanations
)) {
1975 log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1977 explanations
[i
].explanation
,
1978 strna(service_shell_quoted
));
1984 log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1986 strna(service_shell_quoted
));
1989 /* For some results maybe additional explanation is required */
1990 if (streq_ptr(result
, "start-limit"))
1991 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
1992 strna(service_shell_quoted
));
1995 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
) {
2001 if (streq(d
->result
, "canceled"))
2002 log_error("Job for %s canceled.", strna(d
->name
));
2003 else if (streq(d
->result
, "timeout"))
2004 log_error("Job for %s timed out.", strna(d
->name
));
2005 else if (streq(d
->result
, "dependency"))
2006 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
2007 else if (streq(d
->result
, "invalid"))
2008 log_error("Job for %s invalid.", strna(d
->name
));
2009 else if (streq(d
->result
, "assert"))
2010 log_error("Assertion failed on job for %s.", strna(d
->name
));
2011 else if (streq(d
->result
, "unsupported"))
2012 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2013 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped")) {
2016 _cleanup_free_
char *result
= NULL
;
2018 q
= bus_job_get_service_result(d
, &result
);
2020 log_debug_errno(q
, "Failed to get Result property of service %s: %m", d
->name
);
2022 log_job_error_with_service_result(d
->name
, result
);
2024 log_error("Job failed. See \"journalctl -xe\" for details.");
2028 if (streq(d
->result
, "canceled"))
2030 else if (streq(d
->result
, "timeout"))
2032 else if (streq(d
->result
, "dependency"))
2034 else if (streq(d
->result
, "invalid"))
2036 else if (streq(d
->result
, "assert"))
2038 else if (streq(d
->result
, "unsupported"))
2040 else if (!streq(d
->result
, "done") && !streq(d
->result
, "skipped"))
2046 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
) {
2051 while (!set_isempty(d
->jobs
)) {
2054 q
= bus_process_wait(d
->bus
);
2056 return log_error_errno(q
, "Failed to wait for response: %m");
2059 q
= check_wait_response(d
, quiet
);
2060 /* Return the first error as it is most likely to be
2062 if (q
< 0 && r
== 0)
2065 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2068 d
->name
= mfree(d
->name
);
2069 d
->result
= mfree(d
->result
);
2075 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2080 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2084 return set_put_strdup(d
->jobs
, path
);
2087 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2090 r
= bus_wait_for_jobs_add(d
, path
);
2094 return bus_wait_for_jobs(d
, quiet
);
2097 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2098 const char *type
, *path
, *source
;
2101 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2103 return bus_log_parse_error(r
);
2105 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2107 if (streq(type
, "symlink"))
2108 log_info("Created symlink from %s to %s.", path
, source
);
2110 log_info("Removed symlink %s.", path
);
2113 r
= unit_file_changes_add(changes
, n_changes
, streq(type
, "symlink") ? UNIT_FILE_SYMLINK
: UNIT_FILE_UNLINK
, path
, source
);
2118 return bus_log_parse_error(r
);
2120 r
= sd_bus_message_exit_container(m
);
2122 return bus_log_parse_error(r
);
2128 * bus_path_encode_unique() - encode unique object path
2129 * @b: bus connection or NULL
2130 * @prefix: object path prefix
2131 * @sender_id: unique-name of client, or NULL
2132 * @external_id: external ID to be chosen by client, or NULL
2133 * @ret_path: storage for encoded object path pointer
2135 * Whenever we provide a bus API that allows clients to create and manage
2136 * server-side objects, we need to provide a unique name for these objects. If
2137 * we let the server choose the name, we suffer from a race condition: If a
2138 * client creates an object asynchronously, it cannot destroy that object until
2139 * it received the method reply. It cannot know the name of the new object,
2140 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
2142 * Therefore, many APIs allow the client to choose the unique name for newly
2143 * created objects. There're two problems to solve, though:
2144 * 1) Object names are usually defined via dbus object paths, which are
2145 * usually globally namespaced. Therefore, multiple clients must be able
2146 * to choose unique object names without interference.
2147 * 2) If multiple libraries share the same bus connection, they must be
2148 * able to choose unique object names without interference.
2149 * The first problem is solved easily by prefixing a name with the
2150 * unique-bus-name of a connection. The server side must enforce this and
2151 * reject any other name. The second problem is solved by providing unique
2152 * suffixes from within sd-bus.
2154 * This helper allows clients to create unique object-paths. It uses the
2155 * template '/prefix/sender_id/external_id' and returns the new path in
2156 * @ret_path (must be freed by the caller).
2157 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
2158 * NULL, this function allocates a unique suffix via @b (by requesting a new
2159 * cookie). If both @sender_id and @external_id are given, @b can be passed as
2162 * Returns: 0 on success, negative error code on failure.
2164 int bus_path_encode_unique(sd_bus
*b
, const char *prefix
, const char *sender_id
, const char *external_id
, char **ret_path
) {
2165 _cleanup_free_
char *sender_label
= NULL
, *external_label
= NULL
;
2166 char external_buf
[DECIMAL_STR_MAX(uint64_t)], *p
;
2169 assert_return(b
|| (sender_id
&& external_id
), -EINVAL
);
2170 assert_return(object_path_is_valid(prefix
), -EINVAL
);
2171 assert_return(ret_path
, -EINVAL
);
2174 r
= sd_bus_get_unique_name(b
, &sender_id
);
2180 xsprintf(external_buf
, "%"PRIu64
, ++b
->cookie
);
2181 external_id
= external_buf
;
2184 sender_label
= bus_label_escape(sender_id
);
2188 external_label
= bus_label_escape(external_id
);
2189 if (!external_label
)
2192 p
= strjoin(prefix
, "/", sender_label
, "/", external_label
, NULL
);
2201 * bus_path_decode_unique() - decode unique object path
2202 * @path: object path to decode
2203 * @prefix: object path prefix
2204 * @ret_sender: output parameter for sender-id label
2205 * @ret_external: output parameter for external-id label
2207 * This does the reverse of bus_path_encode_unique() (see its description for
2208 * details). Both trailing labels, sender-id and external-id, are unescaped and
2209 * returned in the given output parameters (the caller must free them).
2211 * Note that this function returns 0 if the path does not match the template
2212 * (see bus_path_encode_unique()), 1 if it matched.
2214 * Returns: Negative error code on failure, 0 if the given object path does not
2215 * match the template (return parameters are set to NULL), 1 if it was
2216 * parsed successfully (return parameters contain allocated labels).
2218 int bus_path_decode_unique(const char *path
, const char *prefix
, char **ret_sender
, char **ret_external
) {
2220 char *sender
, *external
;
2222 assert(object_path_is_valid(path
));
2223 assert(object_path_is_valid(prefix
));
2225 assert(ret_external
);
2227 p
= object_path_startswith(path
, prefix
);
2230 *ret_external
= NULL
;
2237 *ret_external
= NULL
;
2241 sender
= bus_label_unescape_n(p
, q
- p
);
2242 external
= bus_label_unescape(q
+ 1);
2243 if (!sender
|| !external
) {
2249 *ret_sender
= sender
;
2250 *ret_external
= external
;
2254 bool is_kdbus_wanted(void) {
2255 _cleanup_free_
char *value
= NULL
;
2257 const bool configured
= true;
2259 const bool configured
= false;
2264 if (get_proc_cmdline_key("kdbus", NULL
) > 0)
2267 r
= get_proc_cmdline_key("kdbus=", &value
);
2271 return parse_boolean(value
) == 1;
2274 bool is_kdbus_available(void) {
2275 _cleanup_close_
int fd
= -1;
2276 struct kdbus_cmd cmd
= { .size
= sizeof(cmd
), .flags
= KDBUS_FLAG_NEGOTIATE
};
2278 if (!is_kdbus_wanted())
2281 fd
= open("/sys/fs/kdbus/control", O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
2285 return ioctl(fd
, KDBUS_CMD_BUS_MAKE
, &cmd
) >= 0;
2288 int bus_property_get_rlimit(
2291 const char *interface
,
2292 const char *property
,
2293 sd_bus_message
*reply
,
2295 sd_bus_error
*error
) {
2305 rl
= *(struct rlimit
**) userdata
;
2309 struct rlimit buf
= {};
2312 z
= rlimit_from_string(strstr(property
, "Limit"));
2319 /* rlim_t might have different sizes, let's map
2320 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
2322 u
= x
== RLIM_INFINITY
? (uint64_t) -1 : (uint64_t) x
;
2324 return sd_bus_message_append(reply
, "t", u
);