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) {
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',"
96 "arg1='", unique, "',",
99 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
103 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
110 int bus_event_loop_with_idle(
115 check_idle_t check_idle,
117 bool exiting = false;
127 r = sd_event_get_state(e);
130 if (r == SD_EVENT_FINISHED)
134 idle = check_idle(userdata);
138 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
142 if (r == 0 && !exiting && idle) {
144 r = sd_bus_try_close(bus);
148 /* Fallback for dbus1 connections: we
149 * unregister the name and wait for the
150 * response to come through for it */
151 if (r == -EOPNOTSUPP) {
153 /* Inform the service manager that we
154 * are going down, so that it will
155 * queue all further start requests,
156 * instead of assuming we are already
158 sd_notify(false, "STOPPING=1");
160 r = bus_async_unregister_and_exit(e, bus, name);
176 r = sd_event_get_exit_code(e, &code);
184 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
185 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
186 int r, has_owner = 0;
191 r = sd_bus_call_method(c,
192 "org.freedesktop.DBus",
193 "/org/freedesktop/dbus",
194 "org.freedesktop.DBus",
203 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
205 return sd_bus_error_set_errno(error, r);
210 static int check_good_user(sd_bus_message *m, uid_t good_user) {
211 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
217 if (good_user == UID_INVALID)
220 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
224 /* Don't trust augmented credentials for authorization */
225 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
227 r = sd_bus_creds_get_euid(creds, &sender_uid);
231 return sender_uid == good_user;
235 sd_bus_message *call,
238 const char **details,
248 /* Tests non-interactively! */
250 r = check_good_user(call, good_user);
254 r = sd_bus_query_sender_privilege(call, capability);
261 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
262 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
263 int authorized = false, challenge = false;
264 const char *sender, **k, **v;
266 sender = sd_bus_message_get_sender(call);
270 r = sd_bus_message_new_method_call(
273 "org.freedesktop.PolicyKit1",
274 "/org/freedesktop/PolicyKit1/Authority",
275 "org.freedesktop.PolicyKit1.Authority",
276 "CheckAuthorization");
280 r = sd_bus_message_append(
283 "system-bus-name", 1, "name", "s", sender,
288 r = sd_bus_message_open_container(request, 'a', "{ss}");
292 STRV_FOREACH_PAIR(k, v, details) {
293 r = sd_bus_message_append(request, "{ss}", *k, *v);
298 r = sd_bus_message_close_container(request);
302 r = sd_bus_message_append(request, "us", 0, NULL);
306 r = sd_bus_call(call->bus, request, 0, e, &reply);
308 /* Treat no PK available as access denied */
309 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
310 sd_bus_error_free(e);
317 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
321 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
329 *_challenge = challenge;
340 typedef struct AsyncPolkitQuery {
341 sd_bus_message *request, *reply;
342 sd_bus_message_handler_t callback;
348 static void async_polkit_query_free(AsyncPolkitQuery *q) {
353 sd_bus_slot_unref(q->slot);
355 if (q->registry && q->request)
356 hashmap_remove(q->registry, q->request);
358 sd_bus_message_unref(q->request);
359 sd_bus_message_unref(q->reply);
364 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
365 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
366 AsyncPolkitQuery *q = userdata;
372 q->slot = sd_bus_slot_unref(q->slot);
373 q->reply = sd_bus_message_ref(reply);
375 r = sd_bus_message_rewind(q->request, true);
377 r = sd_bus_reply_method_errno(q->request, r, NULL);
381 r = q->callback(q->request, q->userdata, &error_buffer);
382 r = bus_maybe_reply_error(q->request, r, &error_buffer);
385 async_polkit_query_free(q);
392 int bus_verify_polkit_async(
393 sd_bus_message *call,
396 const char **details,
400 sd_bus_error *error) {
403 _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
405 const char *sender, **k, **v;
406 sd_bus_message_handler_t callback;
416 r = check_good_user(call, good_user);
421 q = hashmap_get(*registry, call);
423 int authorized, challenge;
425 /* This is the second invocation of this function, and
426 * there's already a response from polkit, let's
430 if (sd_bus_message_is_method_error(q->reply, NULL)) {
431 const sd_bus_error *e;
433 /* Copy error from polkit reply */
434 e = sd_bus_message_get_error(q->reply);
435 sd_bus_error_copy(error, e);
437 /* Treat no PK available as access denied */
438 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
441 return -sd_bus_error_get_errno(e);
444 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
446 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
455 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
461 r = sd_bus_query_sender_privilege(call, capability);
468 if (sd_bus_get_current_message(call->bus) != call)
471 callback = sd_bus_get_current_handler(call->bus);
475 userdata = sd_bus_get_current_userdata(call->bus);
477 sender = sd_bus_message_get_sender(call);
481 c = sd_bus_message_get_allow_interactive_authorization(call);
487 r = hashmap_ensure_allocated(registry, NULL);
491 r = sd_bus_message_new_method_call(
494 "org.freedesktop.PolicyKit1",
495 "/org/freedesktop/PolicyKit1/Authority",
496 "org.freedesktop.PolicyKit1.Authority",
497 "CheckAuthorization");
501 r = sd_bus_message_append(
504 "system-bus-name", 1, "name", "s", sender,
509 r = sd_bus_message_open_container(pk, 'a', "{ss}");
513 STRV_FOREACH_PAIR(k, v, details) {
514 r = sd_bus_message_append(pk, "{ss}", *k, *v);
519 r = sd_bus_message_close_container(pk);
523 r = sd_bus_message_append(pk, "us", !!interactive, NULL);
527 q = new0(AsyncPolkitQuery, 1);
531 q->request = sd_bus_message_ref(call);
532 q->callback = callback;
533 q->userdata = userdata;
535 r = hashmap_put(*registry, call, q);
537 async_polkit_query_free(q);
541 q->registry = *registry;
543 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
545 async_polkit_query_free(q);
555 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
557 hashmap_free_with_destructor(registry, async_polkit_query_free);
561 #if 0 /// UNNEEDED by elogind
562 int bus_check_peercred(sd_bus *c) {
568 fd = sd_bus_get_fd(c);
572 r = getpeercred(fd, &ucred);
576 if (ucred.uid != 0 && ucred.uid != geteuid())
582 int bus_connect_system_systemd(sd_bus **_bus) {
583 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
589 return sd_bus_default_system(_bus);
591 /* If we are root then let's talk directly to the system
592 * instance, instead of going via the bus */
594 r = sd_bus_new(&bus);
598 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
602 r = sd_bus_start(bus);
604 return sd_bus_default_system(_bus);
606 r = bus_check_peercred(bus);
616 int bus_connect_user_systemd(sd_bus **_bus) {
617 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
618 _cleanup_free_ char *ee = NULL;
624 e = secure_getenv("XDG_RUNTIME_DIR");
626 return sd_bus_default_user(_bus);
628 ee = bus_address_escape(e);
632 r = sd_bus_new(&bus);
636 bus->address = strjoin("unix:path=", ee, "/systemd/private");
640 r = sd_bus_start(bus);
642 return sd_bus_default_user(_bus);
644 r = bus_check_peercred(bus);
655 #define print_property(name, fmt, ...) \
658 printf(fmt "\n", __VA_ARGS__); \
660 printf("%s=" fmt "\n", name, __VA_ARGS__); \
663 int bus_print_property(const char *name, sd_bus_message *m, bool value, bool all) {
665 const char *contents;
671 r = sd_bus_message_peek_type(m, &type, &contents);
677 case SD_BUS_TYPE_STRING: {
680 r = sd_bus_message_read_basic(m, type, &s);
684 if (all || !isempty(s)) {
687 /* This property has a single value, so we need to take
688 * care not to print a new line, everything else is OK. */
689 good = !strchr(s, '\n');
690 print_property(name, "%s", good ? s : "[unprintable]");
696 case SD_BUS_TYPE_BOOLEAN: {
699 r = sd_bus_message_read_basic(m, type, &b);
703 print_property(name, "%s", yes_no(b));
708 case SD_BUS_TYPE_UINT64: {
711 r = sd_bus_message_read_basic(m, type, &u);
715 /* Yes, heuristics! But we can change this check
716 * should it turn out to not be sufficient */
718 if (endswith(name, "Timestamp") || STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec")) {
719 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
721 t = format_timestamp(timestamp, sizeof(timestamp), u);
723 print_property(name, "%s", strempty(t));
725 } else if (strstr(name, "USec")) {
726 char timespan[FORMAT_TIMESPAN_MAX];
728 print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
729 } else if (streq(name, "RestrictNamespaces")) {
730 _cleanup_free_ char *s = NULL;
733 if ((u & NAMESPACE_FLAGS_ALL) == 0)
735 else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
738 r = namespace_flag_to_string_many(u, &s);
745 print_property(name, "%s", result);
747 } else if (streq(name, "MountFlags")) {
750 result = mount_propagation_flags_to_string(u);
754 print_property(name, "%s", result);
756 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
757 _cleanup_free_ char *s = NULL;
759 r = capability_set_to_string_alloc(u, &s);
763 print_property(name, "%s", s);
765 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
766 (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
767 (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
768 (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
769 (endswith(name, "NSec") && u == (uint64_t) -1))
771 print_property(name, "%s", "[not set]");
773 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
774 (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
775 (startswith(name, "Limit") && u == (uint64_t) -1) ||
776 (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
778 print_property(name, "%s", "infinity");
780 print_property(name, "%"PRIu64, u);
785 case SD_BUS_TYPE_INT64: {
788 r = sd_bus_message_read_basic(m, type, &i);
792 print_property(name, "%"PRIi64, i);
797 case SD_BUS_TYPE_UINT32: {
800 r = sd_bus_message_read_basic(m, type, &u);
804 if (strstr(name, "UMask") || strstr(name, "Mode"))
805 print_property(name, "%04o", u);
806 else if (streq(name, "UID")) {
807 if (u == UID_INVALID)
808 print_property(name, "%s", "[not set]");
810 print_property(name, "%"PRIu32, u);
811 } else if (streq(name, "GID")) {
812 if (u == GID_INVALID)
813 print_property(name, "%s", "[not set]");
815 print_property(name, "%"PRIu32, u);
817 print_property(name, "%"PRIu32, u);
822 case SD_BUS_TYPE_INT32: {
825 r = sd_bus_message_read_basic(m, type, &i);
829 print_property(name, "%"PRIi32, i);
833 case SD_BUS_TYPE_DOUBLE: {
836 r = sd_bus_message_read_basic(m, type, &d);
840 print_property(name, "%g", d);
844 case SD_BUS_TYPE_ARRAY:
845 if (streq(contents, "s")) {
849 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
853 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
859 /* This property has multiple space-separated values, so
860 * neither spaces not newlines can be allowed in a value. */
861 good = str[strcspn(str, " \n")] == '\0';
863 printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
870 if (first && all && !value)
875 r = sd_bus_message_exit_container(m);
881 } else if (streq(contents, "y")) {
885 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
895 for (i = 0; i < n; i++)
896 printf("%02x", u[i]);
903 } else if (streq(contents, "u")) {
907 r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
917 for (i = 0; i < n; i++)
918 printf("%08x", u[i]);
932 int bus_message_print_all_properties(
934 bus_message_print_t func,
938 Set **found_properties) {
944 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
948 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
950 const char *contents;
952 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
956 if (found_properties) {
957 r = set_ensure_allocated(found_properties, &string_hash_ops);
961 r = set_put(*found_properties, name);
962 if (r < 0 && r != EEXIST)
966 if (!filter || strv_find(filter, name)) {
967 r = sd_bus_message_peek_type(m, NULL, &contents);
971 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
976 r = func(name, m, value, all);
978 r = bus_print_property(name, m, value, all);
983 printf("%s=[unprintable]\n", name);
984 /* skip what we didn't read */
985 r = sd_bus_message_skip(m, contents);
990 r = sd_bus_message_exit_container(m);
994 r = sd_bus_message_skip(m, "v");
999 r = sd_bus_message_exit_container(m);
1006 r = sd_bus_message_exit_container(m);
1013 int bus_print_all_properties(
1017 bus_message_print_t func,
1021 Set **found_properties) {
1023 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1024 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1030 r = sd_bus_call_method(bus,
1033 "org.freedesktop.DBus.Properties",
1041 return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
1044 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1045 sd_id128_t *p = userdata;
1050 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1057 memcpy((*p).bytes, v, n);
1064 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool copy_string) {
1068 r = sd_bus_message_peek_type(m, &type, NULL);
1074 case SD_BUS_TYPE_STRING: {
1075 const char **p = userdata;
1078 r = sd_bus_message_read_basic(m, type, &s);
1086 return free_and_strdup((char **) userdata, s);
1092 case SD_BUS_TYPE_ARRAY: {
1093 _cleanup_strv_free_ char **l = NULL;
1094 char ***p = userdata;
1096 r = bus_message_read_strv_extend(m, &l);
1105 case SD_BUS_TYPE_BOOLEAN: {
1109 r = sd_bus_message_read_basic(m, type, &b);
1117 case SD_BUS_TYPE_INT32:
1118 case SD_BUS_TYPE_UINT32: {
1119 uint32_t u, *p = userdata;
1121 r = sd_bus_message_read_basic(m, type, &u);
1129 case SD_BUS_TYPE_INT64:
1130 case SD_BUS_TYPE_UINT64: {
1131 uint64_t t, *p = userdata;
1133 r = sd_bus_message_read_basic(m, type, &t);
1141 case SD_BUS_TYPE_DOUBLE: {
1142 double d, *p = userdata;
1144 r = sd_bus_message_read_basic(m, type, &d);
1155 int bus_message_map_all_properties(
1157 const struct bus_properties_map *map,
1159 sd_bus_error *error,
1167 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1171 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1172 const struct bus_properties_map *prop;
1174 const char *contents;
1178 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1182 for (i = 0, prop = NULL; map[i].member; i++)
1183 if (streq(map[i].member, member)) {
1189 r = sd_bus_message_peek_type(m, NULL, &contents);
1193 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1197 v = (uint8_t *)userdata + prop->offset;
1199 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1201 r = map_basic(sd_bus_message_get_bus(m), member, m, error, v, copy_string);
1205 r = sd_bus_message_exit_container(m);
1209 r = sd_bus_message_skip(m, "v");
1214 r = sd_bus_message_exit_container(m);
1221 return sd_bus_message_exit_container(m);
1224 #if 0 /// UNNEEDED by elogind
1225 int bus_message_map_properties_changed(
1227 const struct bus_properties_map *map,
1229 sd_bus_error *error,
1233 int r, invalidated, i;
1238 r = bus_message_map_all_properties(m, map, copy_string, error, userdata);
1242 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1247 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1248 for (i = 0; map[i].member; i++)
1249 if (streq(map[i].member, member)) {
1256 r = sd_bus_message_exit_container(m);
1264 int bus_map_all_properties(
1266 const char *destination,
1268 const struct bus_properties_map *map,
1269 sd_bus_error *error,
1270 sd_bus_message **reply,
1273 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1277 assert(destination);
1281 r = sd_bus_call_method(
1285 "org.freedesktop.DBus.Properties",
1293 r = bus_message_map_all_properties(m, map, !reply, error, userdata);
1298 *reply = sd_bus_message_ref(m);
1303 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1304 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1307 assert(transport >= 0);
1308 assert(transport < _BUS_TRANSPORT_MAX);
1311 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1312 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1314 switch (transport) {
1316 case BUS_TRANSPORT_LOCAL:
1317 #if 0 /// elogind does not support a user bus
1319 r = sd_bus_default_user(&bus);
1322 r = sd_bus_default_system(&bus);
1326 case BUS_TRANSPORT_REMOTE:
1327 r = sd_bus_open_system_remote(&bus, host);
1330 case BUS_TRANSPORT_MACHINE:
1331 r = sd_bus_open_system_machine(&bus, host);
1335 assert_not_reached("Hmm, unknown transport type.");
1340 r = sd_bus_set_exit_on_disconnect(bus, true);
1350 #if 0 /// UNNEEDED by elogind
1351 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1354 assert(transport >= 0);
1355 assert(transport < _BUS_TRANSPORT_MAX);
1358 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1359 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1361 switch (transport) {
1363 case BUS_TRANSPORT_LOCAL:
1365 r = bus_connect_user_systemd(bus);
1367 r = bus_connect_system_systemd(bus);
1371 case BUS_TRANSPORT_REMOTE:
1372 r = sd_bus_open_system_remote(bus, host);
1375 case BUS_TRANSPORT_MACHINE:
1376 r = sd_bus_open_system_machine(bus, host);
1380 assert_not_reached("Hmm, unknown transport type.");
1387 int bus_property_get_bool(
1390 const char *interface,
1391 const char *property,
1392 sd_bus_message *reply,
1394 sd_bus_error *error) {
1396 int b = *(bool*) userdata;
1398 return sd_bus_message_append_basic(reply, 'b', &b);
1401 int bus_property_set_bool(
1404 const char *interface,
1405 const char *property,
1406 sd_bus_message *value,
1408 sd_bus_error *error) {
1412 r = sd_bus_message_read(value, "b", &b);
1416 *(bool *) userdata = !!b;
1420 #if 0 /// UNNEEDED by elogind
1421 int bus_property_get_id128(
1424 const char *interface,
1425 const char *property,
1426 sd_bus_message *reply,
1428 sd_bus_error *error) {
1430 sd_id128_t *id = userdata;
1432 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1433 return sd_bus_message_append(reply, "ay", 0);
1435 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1439 #if __SIZEOF_SIZE_T__ != 8
1440 int bus_property_get_size(
1443 const char *interface,
1444 const char *property,
1445 sd_bus_message *reply,
1447 sd_bus_error *error) {
1449 uint64_t sz = *(size_t*) userdata;
1451 return sd_bus_message_append_basic(reply, 't', &sz);
1455 #if __SIZEOF_LONG__ != 8
1456 int bus_property_get_long(
1459 const char *interface,
1460 const char *property,
1461 sd_bus_message *reply,
1463 sd_bus_error *error) {
1465 int64_t l = *(long*) userdata;
1467 return sd_bus_message_append_basic(reply, 'x', &l);
1470 int bus_property_get_ulong(
1473 const char *interface,
1474 const char *property,
1475 sd_bus_message *reply,
1477 sd_bus_error *error) {
1479 uint64_t ul = *(unsigned long*) userdata;
1481 return sd_bus_message_append_basic(reply, 't', &ul);
1485 int bus_log_parse_error(int r) {
1486 return log_error_errno(r, "Failed to parse bus message: %m");
1489 #if 0 /// UNNEEDED by elogind
1490 int bus_log_create_error(int r) {
1491 return log_error_errno(r, "Failed to create bus message: %m");
1495 #if 0 /// UNNEEDED by elogind
1497 * bus_path_encode_unique() - encode unique object path
1498 * @b: bus connection or NULL
1499 * @prefix: object path prefix
1500 * @sender_id: unique-name of client, or NULL
1501 * @external_id: external ID to be chosen by client, or NULL
1502 * @ret_path: storage for encoded object path pointer
1504 * Whenever we provide a bus API that allows clients to create and manage
1505 * server-side objects, we need to provide a unique name for these objects. If
1506 * we let the server choose the name, we suffer from a race condition: If a
1507 * client creates an object asynchronously, it cannot destroy that object until
1508 * it received the method reply. It cannot know the name of the new object,
1509 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1511 * Therefore, many APIs allow the client to choose the unique name for newly
1512 * created objects. There're two problems to solve, though:
1513 * 1) Object names are usually defined via dbus object paths, which are
1514 * usually globally namespaced. Therefore, multiple clients must be able
1515 * to choose unique object names without interference.
1516 * 2) If multiple libraries share the same bus connection, they must be
1517 * able to choose unique object names without interference.
1518 * The first problem is solved easily by prefixing a name with the
1519 * unique-bus-name of a connection. The server side must enforce this and
1520 * reject any other name. The second problem is solved by providing unique
1521 * suffixes from within sd-bus.
1523 * This helper allows clients to create unique object-paths. It uses the
1524 * template '/prefix/sender_id/external_id' and returns the new path in
1525 * @ret_path (must be freed by the caller).
1526 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1527 * NULL, this function allocates a unique suffix via @b (by requesting a new
1528 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1531 * Returns: 0 on success, negative error code on failure.
1533 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1534 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1535 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1538 assert_return(b || (sender_id && external_id), -EINVAL);
1539 assert_return(object_path_is_valid(prefix), -EINVAL);
1540 assert_return(ret_path, -EINVAL);
1543 r = sd_bus_get_unique_name(b, &sender_id);
1549 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1550 external_id = external_buf;
1553 sender_label = bus_label_escape(sender_id);
1557 external_label = bus_label_escape(external_id);
1558 if (!external_label)
1561 p = strjoin(prefix, "/", sender_label, "/", external_label);
1570 * bus_path_decode_unique() - decode unique object path
1571 * @path: object path to decode
1572 * @prefix: object path prefix
1573 * @ret_sender: output parameter for sender-id label
1574 * @ret_external: output parameter for external-id label
1576 * This does the reverse of bus_path_encode_unique() (see its description for
1577 * details). Both trailing labels, sender-id and external-id, are unescaped and
1578 * returned in the given output parameters (the caller must free them).
1580 * Note that this function returns 0 if the path does not match the template
1581 * (see bus_path_encode_unique()), 1 if it matched.
1583 * Returns: Negative error code on failure, 0 if the given object path does not
1584 * match the template (return parameters are set to NULL), 1 if it was
1585 * parsed successfully (return parameters contain allocated labels).
1587 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1589 char *sender, *external;
1591 assert(object_path_is_valid(path));
1592 assert(object_path_is_valid(prefix));
1594 assert(ret_external);
1596 p = object_path_startswith(path, prefix);
1599 *ret_external = NULL;
1606 *ret_external = NULL;
1610 sender = bus_label_unescape_n(p, q - p);
1611 external = bus_label_unescape(q + 1);
1612 if (!sender || !external) {
1618 *ret_sender = sender;
1619 *ret_external = external;
1624 #if 0 /// UNNEEDED by elogind
1625 int bus_property_get_rlimit(
1628 const char *interface,
1629 const char *property,
1630 sd_bus_message *reply,
1632 sd_bus_error *error) {
1637 const char *is_soft;
1643 is_soft = endswith(property, "Soft");
1644 rl = *(struct rlimit**) userdata;
1646 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1648 struct rlimit buf = {};
1652 s = is_soft ? strndupa(property, is_soft - property) : property;
1654 z = rlimit_from_string(strstr(s, "Limit"));
1658 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1661 /* rlim_t might have different sizes, let's map
1662 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
1664 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1666 return sd_bus_message_append(reply, "t", u);
1669 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1675 /* Continues adding after failure, and returns the first failure. */
1677 STRV_FOREACH(i, l) {
1680 k = sd_bus_track_add_name(t, *i);
1681 if (k < 0 && r >= 0)
1689 int bus_open_system_watch_bind(sd_bus **ret) {
1690 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1696 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
1698 r = sd_bus_new(&bus);
1702 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1704 e = DEFAULT_SYSTEM_BUS_ADDRESS;
1706 r = sd_bus_set_address(bus, e);
1710 r = sd_bus_set_bus_client(bus, true);
1714 r = sd_bus_set_trusted(bus, true);
1718 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1722 r = sd_bus_set_watch_bind(bus, true);
1726 r = sd_bus_set_connected_signal(bus, true);
1730 r = sd_bus_start(bus);