1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/ioctl.h>
28 #include <sys/resource.h>
29 #include <sys/socket.h>
32 #include "sd-bus-protocol.h"
34 #include "sd-daemon.h"
38 #include "alloc-util.h"
39 #include "bus-internal.h"
40 #include "bus-label.h"
41 #include "bus-message.h"
44 #include "cgroup-util.h"
49 #include "mount-util.h"
51 #include "parse-util.h"
52 #include "proc-cmdline.h"
53 //#include "rlimit-util.h"
54 #include "stdio-util.h"
56 #include "user-util.h"
58 #if 0 /// UNNEEDED by elogind
59 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
60 sd_event *e = userdata;
65 sd_bus_close(sd_bus_message_get_bus(m));
71 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
72 _cleanup_free_ char *match = NULL;
80 /* We unregister the name here and then wait for the
81 * NameOwnerChanged signal for this event to arrive before we
82 * quit. We do this in order to make sure that any queued
83 * requests are still processed before we really exit. */
85 r = sd_bus_get_unique_name(bus, &unique);
90 "sender='org.freedesktop.DBus',"
92 "interface='org.freedesktop.DBus',"
93 "member='NameOwnerChanged',"
94 "path='/org/freedesktop/DBus',"
97 "arg2=''", name, unique);
101 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
105 r = sd_bus_release_name(bus, name);
112 int bus_event_loop_with_idle(
117 check_idle_t check_idle,
119 bool exiting = false;
129 r = sd_event_get_state(e);
132 if (r == SD_EVENT_FINISHED)
136 idle = check_idle(userdata);
140 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
144 if (r == 0 && !exiting && idle) {
146 r = sd_bus_try_close(bus);
150 /* Fallback for dbus1 connections: we
151 * unregister the name and wait for the
152 * response to come through for it */
153 if (r == -EOPNOTSUPP) {
155 /* Inform the service manager that we
156 * are going down, so that it will
157 * queue all further start requests,
158 * instead of assuming we are already
160 sd_notify(false, "STOPPING=1");
162 r = bus_async_unregister_and_exit(e, bus, name);
178 r = sd_event_get_exit_code(e, &code);
186 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
187 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
188 int r, has_owner = 0;
193 r = sd_bus_call_method(c,
194 "org.freedesktop.DBus",
195 "/org/freedesktop/dbus",
196 "org.freedesktop.DBus",
205 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
207 return sd_bus_error_set_errno(error, r);
212 static int check_good_user(sd_bus_message *m, uid_t good_user) {
213 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
219 if (good_user == UID_INVALID)
222 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
226 /* Don't trust augmented credentials for authorization */
227 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
229 r = sd_bus_creds_get_euid(creds, &sender_uid);
233 return sender_uid == good_user;
237 sd_bus_message *call,
240 const char **details,
250 /* Tests non-interactively! */
252 r = check_good_user(call, good_user);
256 r = sd_bus_query_sender_privilege(call, capability);
263 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
264 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
265 int authorized = false, challenge = false;
266 const char *sender, **k, **v;
268 sender = sd_bus_message_get_sender(call);
272 r = sd_bus_message_new_method_call(
275 "org.freedesktop.PolicyKit1",
276 "/org/freedesktop/PolicyKit1/Authority",
277 "org.freedesktop.PolicyKit1.Authority",
278 "CheckAuthorization");
282 r = sd_bus_message_append(
285 "system-bus-name", 1, "name", "s", sender,
290 r = sd_bus_message_open_container(request, 'a', "{ss}");
294 STRV_FOREACH_PAIR(k, v, details) {
295 r = sd_bus_message_append(request, "{ss}", *k, *v);
300 r = sd_bus_message_close_container(request);
304 r = sd_bus_message_append(request, "us", 0, NULL);
308 r = sd_bus_call(call->bus, request, 0, e, &reply);
310 /* Treat no PK available as access denied */
311 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
312 sd_bus_error_free(e);
319 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
323 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
331 *_challenge = challenge;
342 typedef struct AsyncPolkitQuery {
343 sd_bus_message *request, *reply;
344 sd_bus_message_handler_t callback;
350 static void async_polkit_query_free(AsyncPolkitQuery *q) {
355 sd_bus_slot_unref(q->slot);
357 if (q->registry && q->request)
358 hashmap_remove(q->registry, q->request);
360 sd_bus_message_unref(q->request);
361 sd_bus_message_unref(q->reply);
366 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
367 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
368 AsyncPolkitQuery *q = userdata;
374 q->slot = sd_bus_slot_unref(q->slot);
375 q->reply = sd_bus_message_ref(reply);
377 r = sd_bus_message_rewind(q->request, true);
379 r = sd_bus_reply_method_errno(q->request, r, NULL);
383 r = q->callback(q->request, q->userdata, &error_buffer);
384 r = bus_maybe_reply_error(q->request, r, &error_buffer);
387 async_polkit_query_free(q);
394 int bus_verify_polkit_async(
395 sd_bus_message *call,
398 const char **details,
402 sd_bus_error *error) {
405 _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
407 const char *sender, **k, **v;
408 sd_bus_message_handler_t callback;
418 r = check_good_user(call, good_user);
423 q = hashmap_get(*registry, call);
425 int authorized, challenge;
427 /* This is the second invocation of this function, and
428 * there's already a response from polkit, let's
432 if (sd_bus_message_is_method_error(q->reply, NULL)) {
433 const sd_bus_error *e;
435 /* Copy error from polkit reply */
436 e = sd_bus_message_get_error(q->reply);
437 sd_bus_error_copy(error, e);
439 /* Treat no PK available as access denied */
440 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
443 return -sd_bus_error_get_errno(e);
446 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
448 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
457 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
463 r = sd_bus_query_sender_privilege(call, capability);
470 if (sd_bus_get_current_message(call->bus) != call)
473 callback = sd_bus_get_current_handler(call->bus);
477 userdata = sd_bus_get_current_userdata(call->bus);
479 sender = sd_bus_message_get_sender(call);
483 c = sd_bus_message_get_allow_interactive_authorization(call);
489 r = hashmap_ensure_allocated(registry, NULL);
493 r = sd_bus_message_new_method_call(
496 "org.freedesktop.PolicyKit1",
497 "/org/freedesktop/PolicyKit1/Authority",
498 "org.freedesktop.PolicyKit1.Authority",
499 "CheckAuthorization");
503 r = sd_bus_message_append(
506 "system-bus-name", 1, "name", "s", sender,
511 r = sd_bus_message_open_container(pk, 'a', "{ss}");
515 STRV_FOREACH_PAIR(k, v, details) {
516 r = sd_bus_message_append(pk, "{ss}", *k, *v);
521 r = sd_bus_message_close_container(pk);
525 r = sd_bus_message_append(pk, "us", !!interactive, NULL);
529 q = new0(AsyncPolkitQuery, 1);
533 q->request = sd_bus_message_ref(call);
534 q->callback = callback;
535 q->userdata = userdata;
537 r = hashmap_put(*registry, call, q);
539 async_polkit_query_free(q);
543 q->registry = *registry;
545 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
547 async_polkit_query_free(q);
557 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
559 hashmap_free_with_destructor(registry, async_polkit_query_free);
563 #if 0 /// UNNEEDED by elogind
564 int bus_check_peercred(sd_bus *c) {
570 fd = sd_bus_get_fd(c);
574 r = getpeercred(fd, &ucred);
578 if (ucred.uid != 0 && ucred.uid != geteuid())
584 int bus_connect_system_systemd(sd_bus **_bus) {
585 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
591 return sd_bus_default_system(_bus);
593 /* If we are root then let's talk directly to the system
594 * instance, instead of going via the bus */
596 r = sd_bus_new(&bus);
600 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
604 r = sd_bus_start(bus);
606 return sd_bus_default_system(_bus);
608 r = bus_check_peercred(bus);
618 int bus_connect_user_systemd(sd_bus **_bus) {
619 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
620 _cleanup_free_ char *ee = NULL;
626 e = secure_getenv("XDG_RUNTIME_DIR");
628 return sd_bus_default_user(_bus);
630 ee = bus_address_escape(e);
634 r = sd_bus_new(&bus);
638 bus->address = strjoin("unix:path=", ee, "/systemd/private");
642 r = sd_bus_start(bus);
644 return sd_bus_default_user(_bus);
646 r = bus_check_peercred(bus);
657 #define print_property(name, fmt, ...) \
660 printf(fmt "\n", __VA_ARGS__); \
662 printf("%s=" fmt "\n", name, __VA_ARGS__); \
665 int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
667 const char *contents;
673 r = sd_bus_message_peek_type(property, &type, &contents);
679 case SD_BUS_TYPE_STRING: {
682 r = sd_bus_message_read_basic(property, type, &s);
686 if (all || !isempty(s)) {
689 /* This property has a single value, so we need to take
690 * care not to print a new line, everything else is OK. */
691 good = !strchr(s, '\n');
692 print_property(name, "%s", good ? s : "[unprintable]");
698 case SD_BUS_TYPE_BOOLEAN: {
701 r = sd_bus_message_read_basic(property, type, &b);
705 print_property(name, "%s", yes_no(b));
710 case SD_BUS_TYPE_UINT64: {
713 r = sd_bus_message_read_basic(property, type, &u);
717 /* Yes, heuristics! But we can change this check
718 * should it turn out to not be sufficient */
720 if (endswith(name, "Timestamp")) {
721 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
723 t = format_timestamp(timestamp, sizeof(timestamp), u);
725 print_property(name, "%s", strempty(t));
727 } else if (strstr(name, "USec")) {
728 char timespan[FORMAT_TIMESPAN_MAX];
730 print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
731 } else if (streq(name, "RestrictNamespaces")) {
732 _cleanup_free_ char *s = NULL;
735 if ((u & NAMESPACE_FLAGS_ALL) == 0)
737 else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
740 r = namespace_flag_to_string_many(u, &s);
747 print_property(name, "%s", result);
749 } else if (streq(name, "MountFlags")) {
752 result = mount_propagation_flags_to_string(u);
756 print_property(name, "%s", result);
758 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
759 _cleanup_free_ char *s = NULL;
761 r = capability_set_to_string_alloc(u, &s);
765 print_property(name, "%s", s);
767 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
768 (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
769 (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
770 (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
771 (endswith(name, "NSec") && u == (uint64_t) -1))
773 print_property(name, "%s", "[not set]");
775 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
776 (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
777 (startswith(name, "Limit") && u == (uint64_t) -1) ||
778 (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
780 print_property(name, "%s", "infinity");
782 print_property(name, "%"PRIu64, u);
787 case SD_BUS_TYPE_INT64: {
790 r = sd_bus_message_read_basic(property, type, &i);
794 print_property(name, "%"PRIi64, i);
799 case SD_BUS_TYPE_UINT32: {
802 r = sd_bus_message_read_basic(property, type, &u);
806 if (strstr(name, "UMask") || strstr(name, "Mode"))
807 print_property(name, "%04o", u);
808 else if (streq(name, "UID")) {
809 if (u == UID_INVALID)
810 print_property(name, "%s", "[not set]");
812 print_property(name, "%"PRIu32, u);
813 } else if (streq(name, "GID")) {
814 if (u == GID_INVALID)
815 print_property(name, "%s", "[not set]");
817 print_property(name, "%"PRIu32, u);
819 print_property(name, "%"PRIu32, u);
824 case SD_BUS_TYPE_INT32: {
827 r = sd_bus_message_read_basic(property, type, &i);
831 print_property(name, "%"PRIi32, i);
835 case SD_BUS_TYPE_DOUBLE: {
838 r = sd_bus_message_read_basic(property, type, &d);
842 print_property(name, "%g", d);
846 case SD_BUS_TYPE_ARRAY:
847 if (streq(contents, "s")) {
851 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
855 while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
861 /* This property has multiple space-separated values, so
862 * neither spaces not newlines can be allowed in a value. */
863 good = str[strcspn(str, " \n")] == '\0';
865 printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
872 if (first && all && !value)
877 r = sd_bus_message_exit_container(property);
883 } else if (streq(contents, "y")) {
887 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
897 for (i = 0; i < n; i++)
898 printf("%02x", u[i]);
905 } else if (streq(contents, "u")) {
909 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
919 for (i = 0; i < n; i++)
920 printf("%08x", u[i]);
934 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) {
935 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
936 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
942 r = sd_bus_call_method(bus,
945 "org.freedesktop.DBus.Properties",
953 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
957 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
959 const char *contents;
961 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
965 if (!filter || strv_find(filter, name)) {
966 r = sd_bus_message_peek_type(reply, NULL, &contents);
970 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
974 r = bus_print_property(name, reply, value, all);
979 printf("%s=[unprintable]\n", name);
980 /* skip what we didn't read */
981 r = sd_bus_message_skip(reply, contents);
986 r = sd_bus_message_exit_container(reply);
990 r = sd_bus_message_skip(reply, "v");
995 r = sd_bus_message_exit_container(reply);
1002 r = sd_bus_message_exit_container(reply);
1009 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1010 sd_id128_t *p = userdata;
1015 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1022 memcpy((*p).bytes, v, n);
1029 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1033 r = sd_bus_message_peek_type(m, &type, NULL);
1039 case SD_BUS_TYPE_STRING: {
1040 char **p = userdata;
1043 r = sd_bus_message_read_basic(m, type, &s);
1050 return free_and_strdup(p, s);
1053 case SD_BUS_TYPE_ARRAY: {
1054 _cleanup_strv_free_ char **l = NULL;
1055 char ***p = userdata;
1057 r = bus_message_read_strv_extend(m, &l);
1067 case SD_BUS_TYPE_BOOLEAN: {
1071 r = sd_bus_message_read_basic(m, type, &b);
1079 case SD_BUS_TYPE_INT32:
1080 case SD_BUS_TYPE_UINT32: {
1081 uint32_t u, *p = userdata;
1083 r = sd_bus_message_read_basic(m, type, &u);
1091 case SD_BUS_TYPE_INT64:
1092 case SD_BUS_TYPE_UINT64: {
1093 uint64_t t, *p = userdata;
1095 r = sd_bus_message_read_basic(m, type, &t);
1103 case SD_BUS_TYPE_DOUBLE: {
1104 double d, *p = userdata;
1106 r = sd_bus_message_read_basic(m, type, &d);
1117 int bus_message_map_all_properties(
1119 const struct bus_properties_map *map,
1120 sd_bus_error *error,
1128 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1132 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1133 const struct bus_properties_map *prop;
1135 const char *contents;
1139 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1143 for (i = 0, prop = NULL; map[i].member; i++)
1144 if (streq(map[i].member, member)) {
1150 r = sd_bus_message_peek_type(m, NULL, &contents);
1154 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1158 v = (uint8_t *)userdata + prop->offset;
1160 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1162 r = map_basic(sd_bus_message_get_bus(m), member, m, error, v);
1166 r = sd_bus_message_exit_container(m);
1170 r = sd_bus_message_skip(m, "v");
1175 r = sd_bus_message_exit_container(m);
1182 return sd_bus_message_exit_container(m);
1185 #if 0 /// UNNEEDED by elogind
1186 int bus_message_map_properties_changed(
1188 const struct bus_properties_map *map,
1189 sd_bus_error *error,
1193 int r, invalidated, i;
1198 r = bus_message_map_all_properties(m, map, error, userdata);
1202 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1207 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1208 for (i = 0; map[i].member; i++)
1209 if (streq(map[i].member, member)) {
1216 r = sd_bus_message_exit_container(m);
1224 int bus_map_all_properties(
1226 const char *destination,
1228 const struct bus_properties_map *map,
1229 sd_bus_error *error,
1232 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1236 assert(destination);
1240 r = sd_bus_call_method(
1244 "org.freedesktop.DBus.Properties",
1252 return bus_message_map_all_properties(m, map, error, userdata);
1255 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1256 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1259 assert(transport >= 0);
1260 assert(transport < _BUS_TRANSPORT_MAX);
1263 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1264 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1266 switch (transport) {
1268 case BUS_TRANSPORT_LOCAL:
1269 #if 0 /// elogind does not support a user bus
1271 r = sd_bus_default_user(&bus);
1274 r = sd_bus_default_system(&bus);
1278 case BUS_TRANSPORT_REMOTE:
1279 r = sd_bus_open_system_remote(&bus, host);
1282 case BUS_TRANSPORT_MACHINE:
1283 r = sd_bus_open_system_machine(&bus, host);
1287 assert_not_reached("Hmm, unknown transport type.");
1292 r = sd_bus_set_exit_on_disconnect(bus, true);
1302 #if 0 /// UNNEEDED by elogind
1303 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1306 assert(transport >= 0);
1307 assert(transport < _BUS_TRANSPORT_MAX);
1310 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1311 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1313 switch (transport) {
1315 case BUS_TRANSPORT_LOCAL:
1317 r = bus_connect_user_systemd(bus);
1319 r = bus_connect_system_systemd(bus);
1323 case BUS_TRANSPORT_REMOTE:
1324 r = sd_bus_open_system_remote(bus, host);
1327 case BUS_TRANSPORT_MACHINE:
1328 r = sd_bus_open_system_machine(bus, host);
1332 assert_not_reached("Hmm, unknown transport type.");
1339 int bus_property_get_bool(
1342 const char *interface,
1343 const char *property,
1344 sd_bus_message *reply,
1346 sd_bus_error *error) {
1348 int b = *(bool*) userdata;
1350 return sd_bus_message_append_basic(reply, 'b', &b);
1353 #if 0 /// UNNEEDED by elogind
1354 int bus_property_get_id128(
1357 const char *interface,
1358 const char *property,
1359 sd_bus_message *reply,
1361 sd_bus_error *error) {
1363 sd_id128_t *id = userdata;
1365 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1366 return sd_bus_message_append(reply, "ay", 0);
1368 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1372 #if __SIZEOF_SIZE_T__ != 8
1373 int bus_property_get_size(
1376 const char *interface,
1377 const char *property,
1378 sd_bus_message *reply,
1380 sd_bus_error *error) {
1382 uint64_t sz = *(size_t*) userdata;
1384 return sd_bus_message_append_basic(reply, 't', &sz);
1388 #if __SIZEOF_LONG__ != 8
1389 int bus_property_get_long(
1392 const char *interface,
1393 const char *property,
1394 sd_bus_message *reply,
1396 sd_bus_error *error) {
1398 int64_t l = *(long*) userdata;
1400 return sd_bus_message_append_basic(reply, 'x', &l);
1403 int bus_property_get_ulong(
1406 const char *interface,
1407 const char *property,
1408 sd_bus_message *reply,
1410 sd_bus_error *error) {
1412 uint64_t ul = *(unsigned long*) userdata;
1414 return sd_bus_message_append_basic(reply, 't', &ul);
1418 int bus_log_parse_error(int r) {
1419 return log_error_errno(r, "Failed to parse bus message: %m");
1422 #if 0 /// UNNEEDED by elogind
1423 int bus_log_create_error(int r) {
1424 return log_error_errno(r, "Failed to create bus message: %m");
1428 #if 0 /// UNNEEDED by elogind
1430 * bus_path_encode_unique() - encode unique object path
1431 * @b: bus connection or NULL
1432 * @prefix: object path prefix
1433 * @sender_id: unique-name of client, or NULL
1434 * @external_id: external ID to be chosen by client, or NULL
1435 * @ret_path: storage for encoded object path pointer
1437 * Whenever we provide a bus API that allows clients to create and manage
1438 * server-side objects, we need to provide a unique name for these objects. If
1439 * we let the server choose the name, we suffer from a race condition: If a
1440 * client creates an object asynchronously, it cannot destroy that object until
1441 * it received the method reply. It cannot know the name of the new object,
1442 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1444 * Therefore, many APIs allow the client to choose the unique name for newly
1445 * created objects. There're two problems to solve, though:
1446 * 1) Object names are usually defined via dbus object paths, which are
1447 * usually globally namespaced. Therefore, multiple clients must be able
1448 * to choose unique object names without interference.
1449 * 2) If multiple libraries share the same bus connection, they must be
1450 * able to choose unique object names without interference.
1451 * The first problem is solved easily by prefixing a name with the
1452 * unique-bus-name of a connection. The server side must enforce this and
1453 * reject any other name. The second problem is solved by providing unique
1454 * suffixes from within sd-bus.
1456 * This helper allows clients to create unique object-paths. It uses the
1457 * template '/prefix/sender_id/external_id' and returns the new path in
1458 * @ret_path (must be freed by the caller).
1459 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1460 * NULL, this function allocates a unique suffix via @b (by requesting a new
1461 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1464 * Returns: 0 on success, negative error code on failure.
1466 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1467 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1468 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1471 assert_return(b || (sender_id && external_id), -EINVAL);
1472 assert_return(object_path_is_valid(prefix), -EINVAL);
1473 assert_return(ret_path, -EINVAL);
1476 r = sd_bus_get_unique_name(b, &sender_id);
1482 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1483 external_id = external_buf;
1486 sender_label = bus_label_escape(sender_id);
1490 external_label = bus_label_escape(external_id);
1491 if (!external_label)
1494 p = strjoin(prefix, "/", sender_label, "/", external_label);
1503 * bus_path_decode_unique() - decode unique object path
1504 * @path: object path to decode
1505 * @prefix: object path prefix
1506 * @ret_sender: output parameter for sender-id label
1507 * @ret_external: output parameter for external-id label
1509 * This does the reverse of bus_path_encode_unique() (see its description for
1510 * details). Both trailing labels, sender-id and external-id, are unescaped and
1511 * returned in the given output parameters (the caller must free them).
1513 * Note that this function returns 0 if the path does not match the template
1514 * (see bus_path_encode_unique()), 1 if it matched.
1516 * Returns: Negative error code on failure, 0 if the given object path does not
1517 * match the template (return parameters are set to NULL), 1 if it was
1518 * parsed successfully (return parameters contain allocated labels).
1520 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1522 char *sender, *external;
1524 assert(object_path_is_valid(path));
1525 assert(object_path_is_valid(prefix));
1527 assert(ret_external);
1529 p = object_path_startswith(path, prefix);
1532 *ret_external = NULL;
1539 *ret_external = NULL;
1543 sender = bus_label_unescape_n(p, q - p);
1544 external = bus_label_unescape(q + 1);
1545 if (!sender || !external) {
1551 *ret_sender = sender;
1552 *ret_external = external;
1557 #if 0 /// UNNEEDED by elogind
1558 int bus_property_get_rlimit(
1561 const char *interface,
1562 const char *property,
1563 sd_bus_message *reply,
1565 sd_bus_error *error) {
1570 const char *is_soft;
1576 is_soft = endswith(property, "Soft");
1577 rl = *(struct rlimit**) userdata;
1579 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1581 struct rlimit buf = {};
1585 s = is_soft ? strndupa(property, is_soft - property) : property;
1587 z = rlimit_from_string(strstr(s, "Limit"));
1591 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1594 /* rlim_t might have different sizes, let's map
1595 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
1597 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1599 return sd_bus_message_append(reply, "t", u);
1602 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1608 /* Continues adding after failure, and returns the first failure. */
1610 STRV_FOREACH(i, l) {
1613 k = sd_bus_track_add_name(t, *i);
1614 if (k < 0 && r >= 0)