X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fdbus-common.c;h=bcbef77b53411d2739874145b275d38470f62c56;hb=3137e0bd5290fea67e52cfe7ff657c3af400b548;hp=038fdd41a020c6a0449e2094b04365dce555870d;hpb=f33d3ec1d7521c91da8b30ad5cb345d6416bb07d;p=elogind.git diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c index 038fdd41a..bcbef77b5 100644 --- a/src/shared/dbus-common.c +++ b/src/shared/dbus-common.c @@ -121,7 +121,7 @@ int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError * try via XDG_RUNTIME_DIR first, then * fallback to normal bus access */ - e = getenv("XDG_RUNTIME_DIR"); + e = __secure_getenv("XDG_RUNTIME_DIR"); if (e) { char *p; @@ -245,7 +245,8 @@ int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) { } const char *bus_error_message(const DBusError *error) { - assert(error); + if (!error) + return NULL; /* Sometimes the D-Bus server is a little bit too verbose with * its error messages, so let's override them here */ @@ -255,6 +256,14 @@ const char *bus_error_message(const DBusError *error) { return error->message; } +const char *bus_error_message_or_strerror(const DBusError *error, int err) { + + if (error && dbus_error_is_set(error)) + return bus_error_message(error); + + return strerror(err); +} + DBusHandlerResult bus_default_message_handler( DBusConnection *c, DBusMessage *message, @@ -403,6 +412,7 @@ get_prop: DBusMessageIter sub; char *sig; void *data; + DBusMessage *changed; if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) @@ -454,22 +464,34 @@ set_prop: dbus_free(sig); return bus_send_error_reply(c, message, NULL, -EINVAL); } - dbus_free(sig); - data = (char*)bp->base + p->offset; + data = (uint8_t*) bp->base + p->offset; if (p->indirect) data = *(void**)data; + r = p->set(&sub, property, data); - if (r < 0) { - if (r == -ENOMEM) - goto oom; + if (r == -ENOMEM) + goto oom; + else if (r < 0) return bus_send_error_reply(c, message, NULL, r); - } reply = dbus_message_new_method_return(message); if (!reply) goto oom; + + /* Send out a signal about this, but it doesn't really + * matter if this fails, so eat all errors */ + changed = bus_properties_changed_one_new( + dbus_message_get_path(message), + interface, + property); + if (changed) { + dbus_connection_send(c, changed, NULL); + dbus_message_unref(changed); + } + + } else { const char *interface = dbus_message_get_interface(message); @@ -647,6 +669,16 @@ int bus_property_append_long(DBusMessageIter *i, const char *property, void *dat return 0; } +int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) { + uint64_t *t = data; + + assert(i); + assert(property); + + dbus_message_iter_get_basic(i, t); + return 0; +} + const char *bus_errno_to_dbus(int error) { switch(error) { @@ -729,7 +761,8 @@ DBusMessage* bus_properties_changed_new(const char *path, const char *interface, assert(interface); assert(properties); - if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"))) + m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); + if (!m) goto oom; dbus_message_iter_init_append(m, &iter); @@ -759,6 +792,43 @@ oom: return NULL; } +DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) { + DBusMessage *m; + DBusMessageIter iter, sub; + + assert(interface); + assert(property); + + m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); + if (!m) + goto oom; + + dbus_message_iter_init_append(m, &iter); + + /* We won't send any property values, since they might be + * large and sometimes not cheap to generated */ + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || + !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || + !dbus_message_iter_close_container(&iter, &sub) || + !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) + goto oom; + + if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property)) + goto oom; + + if (!dbus_message_iter_close_container(&iter, &sub)) + goto oom; + + return m; + +oom: + if (m) + dbus_message_unref(m); + + return NULL; +} + uint32_t bus_flags_to_events(DBusWatch *bus_watch) { unsigned flags; uint32_t events = 0; @@ -1012,6 +1082,29 @@ int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { puts(""); } + return 1; + + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) { + DBusMessageIter sub; + + dbus_message_iter_recurse(iter, &sub); + if (all || + dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + printf("%s=", name); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + uint32_t u; + + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32); + dbus_message_iter_get_basic(&sub, &u); + printf("%08x", u); + + dbus_message_iter_next(&sub); + } + + puts(""); + } + return 1; } @@ -1068,7 +1161,7 @@ void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) { return; oom: - log_error("Out of memory"); + log_oom(); if (pending) { dbus_pending_call_cancel(pending); @@ -1086,7 +1179,7 @@ DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void assert(m); assert(remain_until); - /* Everytime we get a new message we reset out timeout */ + /* Every time we get a new message we reset out timeout */ *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) @@ -1094,3 +1187,130 @@ DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } + +/* This mimics dbus_bus_get_unix_user() */ +pid_t bus_get_unix_process_id( + DBusConnection *connection, + const char *name, + DBusError *error) { + + DBusMessage *m = NULL, *reply = NULL; + uint32_t pid = 0; + + m = dbus_message_new_method_call( + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixProcessID"); + if (!m) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); + goto finish; + } + + if (!dbus_message_append_args( + m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); + if (!reply) + goto finish; + + if (dbus_set_error_from_message(error, reply)) + goto finish; + + if (!dbus_message_get_args( + reply, error, + DBUS_TYPE_UINT32, &pid, + DBUS_TYPE_INVALID)) + goto finish; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return (pid_t) pid; +} + +bool bus_error_is_no_service(const DBusError *error) { + assert(error); + + if (!dbus_error_is_set(error)) + return false; + + if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER)) + return true; + + if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN)) + return true; + + return startswith(error->name, "org.freedesktop.DBus.Error.Spawn."); +} + +int bus_method_call_with_reply(DBusConnection *bus, + const char *destination, + const char *path, + const char *interface, + const char *method, + DBusMessage **return_reply, + DBusError *return_error, + int first_arg_type, ...) { + DBusError error; + DBusMessage *m, *reply; + va_list ap; + int r = 0; + + dbus_error_init(&error); + assert(bus); + + m = dbus_message_new_method_call(destination, path, interface, method); + if (!m) { + r = log_oom(); + goto finish; + } + + va_start(ap, first_arg_type); + if (!dbus_message_append_args_valist(m, first_arg_type, ap)) { + va_end(ap); + r = log_oom(); + goto finish; + } + va_end(ap); + + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); + if (!reply) { + if (!return_error) + log_error("Failed to issue method call: %s", bus_error_message(&error)); + if (bus_error_is_no_service(&error)) + r = -ENOENT; + else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) + r = -EACCES; + else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) + r = -ETIMEDOUT; + else + r = -EIO; + goto finish; + } + + if (return_reply) + *return_reply = reply; + else + dbus_message_unref(reply); + +finish: + if (m) + dbus_message_unref(m); + + if (return_error) + *return_error = error; + else + dbus_error_free(&error); + + return r; +}