X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-util.c;h=ad1cb1a6d0fe84e5ab6cbe56ca1454341b885f98;hb=e65040306900e36aaa84b52428be3490bf107850;hp=0046b486cf0225e4cb477943d0c447daca300f9a;hpb=0c842e0ac0293ca395724fa3aefcc2e65390c8b7;p=elogind.git diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index 0046b486c..ad1cb1a6d 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -21,13 +21,16 @@ #include -#include "sd-event.h" -#include "sd-bus.h" - #include "util.h" +#include "strv.h" #include "macro.h" #include "def.h" +#include "sd-event.h" +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-message.h" + #include "bus-util.h" static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) { @@ -83,7 +86,7 @@ int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t if (r == SD_EVENT_FINISHED) break; - r = sd_event_run(e, exiting ? (uint64_t) -1 : DEFAULT_EXIT_USEC); + r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout); if (r < 0) return r; @@ -148,7 +151,7 @@ int bus_verify_polkit( #ifdef ENABLE_POLKIT else { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - bool authorized = false, challenge = false; + unsigned authorized = false, challenge = false; r = sd_bus_call_method( bus, @@ -267,7 +270,7 @@ int bus_verify_polkit_async( #ifdef ENABLE_POLKIT q = hashmap_remove(*registry, m); if (q) { - bool authorized, challenge; + unsigned authorized, challenge; /* This is the second invocation of this function, and * there's already a response from polkit, let's @@ -380,26 +383,22 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) { } static int bus_check_peercred(sd_bus *c) { - int fd; struct ucred ucred; socklen_t l; + int fd; assert(c); fd = sd_bus_get_fd(c); - - assert(fd >= 0); + if (fd < 0) + return fd; l = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) { - log_error("SO_PEERCRED failed: %m"); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) return -errno; - } - if (l != sizeof(struct ucred)) { - log_error("SO_PEERCRED returned wrong size."); + if (l != sizeof(struct ucred)) return -E2BIG; - } if (ucred.uid != 0 && ucred.uid != geteuid()) return -EPERM; @@ -407,46 +406,416 @@ static int bus_check_peercred(sd_bus *c) { return 1; } -int bus_connect_system(sd_bus **_bus) { - sd_bus *bus = NULL; +int bus_open_system_systemd(sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; int r; - bool private = true; assert(_bus); - if (geteuid() == 0) { - /* If we are root, then let's talk directly to the - * system instance, instead of going via the bus */ + if (geteuid() != 0) + return sd_bus_open_system(_bus); + + /* If we are root, then let's talk directly to the system + * instance, instead of going via the bus */ + + r = sd_bus_new(&bus); + if (r < 0) + return r; + + r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + if (r < 0) + return r; + + r = sd_bus_start(bus); + if (r < 0) + return r; + + r = bus_check_peercred(bus); + if (r < 0) + return r; + + *_bus = bus; + bus = NULL; + + return 0; +} + +int bus_generic_print_property(const char *name, sd_bus_message *property, bool all) { + char type; + const char *contents; + + assert(name); + assert(property); + + sd_bus_message_peek_type(property, &type, &contents); + + switch (type) { + + case SD_BUS_TYPE_STRING: { + const char *s; + sd_bus_message_read_basic(property, type, &s); + + if (all || !isempty(s)) + printf("%s=%s\n", name, s); + + return 1; + } + + case SD_BUS_TYPE_BOOLEAN: { + bool b; + + sd_bus_message_read_basic(property, type, &b); + printf("%s=%s\n", name, yes_no(b)); + + return 1; + } + + case SD_BUS_TYPE_UINT64: { + uint64_t u; + + sd_bus_message_read_basic(property, type, &u); + + /* Yes, heuristics! But we can change this check + * should it turn out to not be sufficient */ + + if (endswith(name, "Timestamp")) { + char timestamp[FORMAT_TIMESTAMP_MAX], *t; - r = sd_bus_new(&bus); + t = format_timestamp(timestamp, sizeof(timestamp), u); + if (t || all) + printf("%s=%s\n", name, strempty(t)); + + } else if (strstr(name, "USec")) { + char timespan[FORMAT_TIMESPAN_MAX]; + + printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0)); + } else + printf("%s=%llu\n", name, (unsigned long long) u); + + return 1; + } + + case SD_BUS_TYPE_UINT32: { + uint32_t u; + + sd_bus_message_read_basic(property, type, &u); + + if (strstr(name, "UMask") || strstr(name, "Mode")) + printf("%s=%04o\n", name, u); + else + printf("%s=%u\n", name, (unsigned) u); + + return 1; + } + + case SD_BUS_TYPE_INT32: { + int32_t i; + + sd_bus_message_read_basic(property, type, &i); + + printf("%s=%i\n", name, (int) i); + return 1; + } + + case SD_BUS_TYPE_DOUBLE: { + double d; + + sd_bus_message_read_basic(property, type, &d); + + printf("%s=%g\n", name, d); + return 1; + } + + case SD_BUS_TYPE_ARRAY: + + if (streq(contents, "s")) { + bool space = false; + char tp; + const char *cnt; + + sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents); + + sd_bus_message_peek_type(property, &tp, &cnt); + if (all || cnt) { + const char *str; + + printf("%s=", name); + + + while(sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str) > 0) { + printf("%s%s", space ? " " : "", str); + + space = true; + } + + puts(""); + } + + sd_bus_message_exit_container(property); + + return 1; + + } else if (streq(contents, "y")) { + const uint8_t *u; + size_t n; + + sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n); + if (all || n > 0) { + unsigned int i; + + printf("%s=", name); + + for (i = 0; i < n; i++) + printf("%02x", u[i]); + + puts(""); + } + + return 1; + + } else if (streq(contents, "u")) { + uint32_t *u; + size_t n; + + sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n); + if (all || n > 0) { + unsigned int i; + + printf("%s=", name); + + for (i = 0; i < n; i++) + printf("%08x", u[i]); + + puts(""); + } + + return 1; + } + + break; + } + + return 0; +} + +int bus_map_all_properties(sd_bus *bus, + const char *destination, + const char *path, + const struct bus_properties_map *map) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_call_method( bus, + destination, + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &m, + "s", ""); + if (r < 0) { + log_error("Could not get properties: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *name; + char type; + const char *contents; + unsigned i; + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); if (r < 0) return r; - r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) return r; - r = sd_bus_start(bus); + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); if (r < 0) return r; - } else { - r = sd_bus_open_system(&bus); + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) { + log_error("Could not determine type of message: %s", strerror(-r)); + return r; + } + + switch (type) { + case SD_BUS_TYPE_STRING: { + const char *s; + + sd_bus_message_read_basic(m, type, &s); + if (isempty(s)) + break; + + for (i = 0; map[i].type; i++) { + char **p; + + if (!streq(map[i].type, "s")) + continue; + if (!streq(map[i].name, name)) + continue; + + p = map[i].ptr; + free(*p); + *p = strdup(s); + if (!*p) { + r = -ENOMEM; + goto fail; + } + } + break; + } + + case SD_BUS_TYPE_ARRAY: { + _cleanup_strv_free_ char **l = NULL; + + if (!streq(contents, "s")) + break; + + for (i = 0; map[i].type; i++) { + char ***p; + + if (!streq(map[i].type, "as")) + continue; + if (!streq(map[i].name, name)) + continue; + + r = bus_message_read_strv_extend(m, &l); + if (r < 0) + break; + + p = map[i].ptr; + strv_free(*p); + *p = l; + l = NULL; + } + break; + } + + case SD_BUS_TYPE_BOOLEAN: { + unsigned b; + + sd_bus_message_read_basic(m, type, &b); + + for (i = 0; map[i].type; i++) { + bool *p; + + if (!streq(map[i].type, "b")) + continue; + if (!streq(map[i].name, name)) + continue; + + p = map[i].ptr; + *p = b; + } + break; + } + + case SD_BUS_TYPE_UINT64: { + uint64_t t; + + sd_bus_message_read_basic(m, type, &t); + + for (i = 0; map[i].type; i++) { + uint64_t *p; + + if (!streq(map[i].type, "t")) + continue; + if (!streq(map[i].name, name)) + continue; + + p = map[i].ptr; + *p = t; + } + break; + } + + default: + break; + } + + r = sd_bus_message_exit_container(m); if (r < 0) return r; - private = false; + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; } - if (private) { - r = bus_check_peercred(bus); - if (r < 0) { - sd_bus_unref(bus); +fail: + return r; +} - return -EACCES; - } +int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) { + int r; + + assert(transport >= 0); + assert(transport < _BUS_TRANSPORT_MAX); + assert(bus); + + assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL); + assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP); + + switch (transport) { + + case BUS_TRANSPORT_LOCAL: + if (user) + r = sd_bus_open_user(bus); + else + r = sd_bus_open_system(bus); + + break; + + case BUS_TRANSPORT_REMOTE: + r = sd_bus_open_system_remote(host, bus); + break; + + case BUS_TRANSPORT_CONTAINER: + r = sd_bus_open_system_container(host, bus); + break; + + default: + assert_not_reached("Hmm, unknown transport type."); } - *_bus = bus; - return 0; + return r; +} + +int bus_property_get_bool( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + int b = *(bool*) userdata; + + return sd_bus_message_append_basic(reply, 'b', &b); +} + +int bus_property_get_uid( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + assert_cc(sizeof(uint32_t) == sizeof(uid_t)); + assert_cc(sizeof(uint32_t) == sizeof(gid_t)); + assert_cc(sizeof(uint32_t) == sizeof(pid_t)); + + return sd_bus_message_append_basic(reply, 'u', userdata); }