diff options
Diffstat (limited to 'xorg-server/config/dbus.c')
-rw-r--r-- | xorg-server/config/dbus.c | 884 |
1 files changed, 442 insertions, 442 deletions
diff --git a/xorg-server/config/dbus.c b/xorg-server/config/dbus.c index 86d9d287f..d6316623b 100644 --- a/xorg-server/config/dbus.c +++ b/xorg-server/config/dbus.c @@ -1,442 +1,442 @@ -/* - * Copyright © 2006-2007 Daniel Stone - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Daniel Stone <daniel@fooishbar.org> - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#define DBUS_API_SUBJECT_TO_CHANGE -#include <dbus/dbus.h> -#include <string.h> - -#include <X11/X.h> - -#include "config-backends.h" -#include "opaque.h" /* for 'display': there should be a better way. */ -#include "input.h" -#include "inputstr.h" - -#define API_VERSION 2 - -#define MATCH_RULE "type='method_call',interface='org.x.config.input'" - -#define MALFORMED_MSG "[config/dbus] malformed message, dropping" -#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \ - ret = BadValue; \ - goto unwind; } -#define MALFORMED_MESSAGE_ERROR() { DebugF(MALFORMED_MSG ": %s, %s", \ - error->name, error->message); \ - ret = BadValue; \ - goto unwind; } - -struct connection_info { - char busobject[32]; - char busname[64]; - DBusConnection *connection; -}; - -static void -reset_info(struct connection_info *info) -{ - info->connection = NULL; - info->busname[0] = '\0'; - info->busobject[0] = '\0'; -} - -static int -add_device(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DBusMessageIter iter, reply_iter, subiter; - InputOption *tmpo = NULL, *options = NULL; - char *tmp = NULL; - int ret, err; - DeviceIntPtr dev = NULL; - - dbus_message_iter_init_append(reply, &reply_iter); - - if (!dbus_message_iter_init(message, &iter)) { - ErrorF("[config/dbus] couldn't initialise iterator\n"); - MALFORMED_MESSAGE(); - } - - options = xcalloc(sizeof(*options), 1); - if (!options) { - ErrorF("[config/dbus] couldn't allocate option\n"); - return BadAlloc; - } - - options->key = xstrdup("_source"); - options->value = xstrdup("client/dbus"); - if (!options->key || !options->value) { - ErrorF("[config/dbus] couldn't allocate first key/value pair\n"); - ret = BadAlloc; - goto unwind; - } - - /* signature should be [ss][ss]... */ - while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { - tmpo = xcalloc(sizeof(*tmpo), 1); - if (!tmpo) { - ErrorF("[config/dbus] couldn't allocate option\n"); - ret = BadAlloc; - goto unwind; - } - tmpo->next = options; - options = tmpo; - - dbus_message_iter_recurse(&iter, &subiter); - - if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) - MALFORMED_MESSAGE(); - - dbus_message_iter_get_basic(&subiter, &tmp); - if (!tmp) - MALFORMED_MESSAGE(); - /* The _ prefix refers to internal settings, and may not be given by - * the client. */ - if (tmp[0] == '_') { - ErrorF("[config/dbus] attempted subterfuge: option name %s given\n", - tmp); - MALFORMED_MESSAGE(); - } - options->key = xstrdup(tmp); - if (!options->key) { - ErrorF("[config/dbus] couldn't duplicate key!\n"); - ret = BadAlloc; - goto unwind; - } - - if (!dbus_message_iter_has_next(&subiter)) - MALFORMED_MESSAGE(); - dbus_message_iter_next(&subiter); - if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) - MALFORMED_MESSAGE(); - - dbus_message_iter_get_basic(&subiter, &tmp); - if (!tmp) - MALFORMED_MESSAGE(); - options->value = xstrdup(tmp); - if (!options->value) { - ErrorF("[config/dbus] couldn't duplicate option!\n"); - ret = BadAlloc; - goto unwind; - } - - dbus_message_iter_next(&iter); - } - - ret = NewInputDeviceRequest(options, NULL, &dev); - if (ret != Success) { - DebugF("[config/dbus] NewInputDeviceRequest failed\n"); - goto unwind; - } - - if (!dev) { - DebugF("[config/dbus] NewInputDeviceRequest provided no device\n"); - ret = BadImplementation; - goto unwind; - } - - /* XXX: If we fail halfway through, we don't seem to have any way to - * empty the iterator, so you'll end up with some device IDs, - * plus an error. This seems to be a shortcoming in the D-Bus - * API. */ - for (; dev; dev = dev->next) { - if (!dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, - &dev->id)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - ret = BadAlloc; - goto unwind; - } - } - -unwind: - if (ret != Success) { - if (dev) - RemoveDevice(dev, TRUE); - - err = -ret; - dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); - } - - while (options) { - tmpo = options; - options = options->next; - if (tmpo->key) - xfree(tmpo->key); - if (tmpo->value) - xfree(tmpo->value); - xfree(tmpo); - } - - return ret; -} - -static int -remove_device(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - int deviceid, ret, err; - DeviceIntPtr dev; - DBusMessageIter iter, reply_iter; - - dbus_message_iter_init_append(reply, &reply_iter); - - if (!dbus_message_iter_init(message, &iter)) { - ErrorF("[config/dbus] failed to init iterator\n"); - MALFORMED_MESSAGE(); - } - - if (!dbus_message_get_args(message, error, DBUS_TYPE_UINT32, - &deviceid, DBUS_TYPE_INVALID)) { - MALFORMED_MESSAGE_ERROR(); - } - - dixLookupDevice(&dev, deviceid, serverClient, DixDestroyAccess); - if (!dev) { - DebugF("[config/dbus] bogus device id %d given\n", deviceid); - ret = BadMatch; - goto unwind; - } - - DebugF("[config/dbus] removing device %s (id %d)\n", dev->name, deviceid); - - /* Call PIE here so we don't try to dereference a device that's - * already been removed. */ - OsBlockSignals(); - ProcessInputEvents(); - DeleteInputDeviceRequest(dev); - OsReleaseSignals(); - - ret = Success; - -unwind: - err = (ret == Success) ? ret : -ret; - dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); - - return ret; -} - -static int -list_devices(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DeviceIntPtr dev; - DBusMessageIter iter, subiter; - - dbus_message_iter_init_append(reply, &iter); - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, - &subiter)) { - ErrorF("[config/dbus] couldn't init container\n"); - return BadAlloc; - } - if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UINT32, - &dev->id)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - return BadAlloc; - } - if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, - &dev->name)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - return BadAlloc; - } - if (!dbus_message_iter_close_container(&iter, &subiter)) { - ErrorF("[config/dbus] couldn't close container\n"); - return BadAlloc; - } - } - - return Success; -} - -static int -get_version(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DBusMessageIter iter; - unsigned int version = API_VERSION; - - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &version)) { - ErrorF("[config/dbus] couldn't append version\n"); - return BadAlloc; - } - - return Success; -} - -static DBusHandlerResult -message_handler(DBusConnection *connection, DBusMessage *message, void *data) -{ - DBusError error; - DBusMessage *reply; - struct connection_info *info = data; - - /* ret is the overall D-Bus handler result, whereas err is the internal - * X error from our individual functions. */ - int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - int err; - - DebugF("[config/dbus] received a message for %s\n", - dbus_message_get_interface(message)); - - dbus_error_init(&error); - - reply = dbus_message_new_method_return(message); - if (!reply) { - ErrorF("[config/dbus] failed to create reply\n"); - ret = DBUS_HANDLER_RESULT_NEED_MEMORY; - goto err_start; - } - - if (strcmp(dbus_message_get_member(message), "add") == 0) - err = add_device(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "remove") == 0) - err = remove_device(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "listDevices") == 0) - err = list_devices(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "version") == 0) - err = get_version(message, reply, &error); - else - goto err_reply; - - /* Failure to allocate is a special case. */ - if (err == BadAlloc) { - ret = DBUS_HANDLER_RESULT_NEED_MEMORY; - goto err_reply; - } - - /* While failure here is always an OOM, we don't return that, - * since that would result in devices being double-added/removed. */ - if (dbus_connection_send(info->connection, reply, NULL)) - dbus_connection_flush(info->connection); - else - ErrorF("[config/dbus] failed to send reply\n"); - - ret = DBUS_HANDLER_RESULT_HANDLED; - -err_reply: - dbus_message_unref(reply); -err_start: - dbus_error_free(&error); - - return ret; -} - -static void -connect_hook(DBusConnection *connection, void *data) -{ - DBusError error; - DBusObjectPathVTable vtable = { .message_function = message_handler, }; - struct connection_info *info = data; - - info->connection = connection; - - dbus_error_init(&error); - - dbus_bus_request_name(info->connection, info->busname, 0, &error); - if (dbus_error_is_set(&error)) { - ErrorF("[config/dbus] couldn't take over org.x.config: %s (%s)\n", - error.name, error.message); - goto err_start; - } - - /* blocks until we get a reply. */ - dbus_bus_add_match(info->connection, MATCH_RULE, &error); - if (dbus_error_is_set(&error)) { - ErrorF("[config/dbus] couldn't add match: %s (%s)\n", error.name, - error.message); - goto err_name; - } - - if (!dbus_connection_register_object_path(info->connection, - info->busobject, &vtable, - info)) { - ErrorF("[config/dbus] couldn't register object path\n"); - goto err_match; - } - - DebugF("[dbus] registered %s, %s\n", info->busname, info->busobject); - - dbus_error_free(&error); - - return; - -err_match: - dbus_bus_remove_match(info->connection, MATCH_RULE, &error); -err_name: - dbus_bus_release_name(info->connection, info->busname, &error); -err_start: - dbus_error_free(&error); - - reset_info(info); -} - -static void -disconnect_hook(void *data) -{ -} - -#if 0 -void -pre_disconnect_hook(void) -{ - DBusError error; - - dbus_error_init(&error); - dbus_connection_unregister_object_path(connection_data->connection, - connection_data->busobject); - dbus_bus_remove_match(connection_data->connection, MATCH_RULE, - &error); - dbus_bus_release_name(connection_data->connection, - connection_data->busname, &error); - dbus_error_free(&error); -} -#endif - -static struct connection_info connection_data; -static struct config_dbus_core_hook core_hook = { - .connect = connect_hook, - .disconnect = disconnect_hook, - .data = &connection_data, -}; - -int -config_dbus_init(void) -{ - snprintf(connection_data.busname, sizeof(connection_data.busname), - "org.x.config.display%d", atoi(display)); - snprintf(connection_data.busobject, sizeof(connection_data.busobject), - "/org/x/config/%d", atoi(display)); - - return config_dbus_core_add_hook(&core_hook); -} - -void -config_dbus_fini(void) -{ - config_dbus_core_remove_hook(&core_hook); - connection_data.busname[0] = '\0'; - connection_data.busobject[0] = '\0'; -} +/*
+ * Copyright © 2006-2007 Daniel Stone
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <string.h>
+
+#include <X11/X.h>
+
+#include "config-backends.h"
+#include "opaque.h" /* for 'display': there should be a better way. */
+#include "input.h"
+#include "inputstr.h"
+
+#define API_VERSION 2
+
+#define MATCH_RULE "type='method_call',interface='org.x.config.input'"
+
+#define MALFORMED_MSG "[config/dbus] malformed message, dropping"
+#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \
+ ret = BadValue; \
+ goto unwind; }
+#define MALFORMED_MESSAGE_ERROR() { DebugF(MALFORMED_MSG ": %s, %s", \
+ error->name, error->message); \
+ ret = BadValue; \
+ goto unwind; }
+
+struct connection_info {
+ char busobject[32];
+ char busname[64];
+ DBusConnection *connection;
+};
+
+static void
+reset_info(struct connection_info *info)
+{
+ info->connection = NULL;
+ info->busname[0] = '\0';
+ info->busobject[0] = '\0';
+}
+
+static int
+add_device(DBusMessage *message, DBusMessage *reply, DBusError *error)
+{
+ DBusMessageIter iter, reply_iter, subiter;
+ InputOption *tmpo = NULL, *options = NULL;
+ char *tmp = NULL;
+ int ret, err;
+ DeviceIntPtr dev = NULL;
+
+ dbus_message_iter_init_append(reply, &reply_iter);
+
+ if (!dbus_message_iter_init(message, &iter)) {
+ ErrorF("[config/dbus] couldn't initialise iterator\n");
+ MALFORMED_MESSAGE();
+ }
+
+ options = calloc(sizeof(*options), 1);
+ if (!options) {
+ ErrorF("[config/dbus] couldn't allocate option\n");
+ return BadAlloc;
+ }
+
+ options->key = xstrdup("_source");
+ options->value = xstrdup("client/dbus");
+ if (!options->key || !options->value) {
+ ErrorF("[config/dbus] couldn't allocate first key/value pair\n");
+ ret = BadAlloc;
+ goto unwind;
+ }
+
+ /* signature should be [ss][ss]... */
+ while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
+ tmpo = calloc(sizeof(*tmpo), 1);
+ if (!tmpo) {
+ ErrorF("[config/dbus] couldn't allocate option\n");
+ ret = BadAlloc;
+ goto unwind;
+ }
+ tmpo->next = options;
+ options = tmpo;
+
+ dbus_message_iter_recurse(&iter, &subiter);
+
+ if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING)
+ MALFORMED_MESSAGE();
+
+ dbus_message_iter_get_basic(&subiter, &tmp);
+ if (!tmp)
+ MALFORMED_MESSAGE();
+ /* The _ prefix refers to internal settings, and may not be given by
+ * the client. */
+ if (tmp[0] == '_') {
+ ErrorF("[config/dbus] attempted subterfuge: option name %s given\n",
+ tmp);
+ MALFORMED_MESSAGE();
+ }
+ options->key = xstrdup(tmp);
+ if (!options->key) {
+ ErrorF("[config/dbus] couldn't duplicate key!\n");
+ ret = BadAlloc;
+ goto unwind;
+ }
+
+ if (!dbus_message_iter_has_next(&subiter))
+ MALFORMED_MESSAGE();
+ dbus_message_iter_next(&subiter);
+ if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING)
+ MALFORMED_MESSAGE();
+
+ dbus_message_iter_get_basic(&subiter, &tmp);
+ if (!tmp)
+ MALFORMED_MESSAGE();
+ options->value = xstrdup(tmp);
+ if (!options->value) {
+ ErrorF("[config/dbus] couldn't duplicate option!\n");
+ ret = BadAlloc;
+ goto unwind;
+ }
+
+ dbus_message_iter_next(&iter);
+ }
+
+ ret = NewInputDeviceRequest(options, NULL, &dev);
+ if (ret != Success) {
+ DebugF("[config/dbus] NewInputDeviceRequest failed\n");
+ goto unwind;
+ }
+
+ if (!dev) {
+ DebugF("[config/dbus] NewInputDeviceRequest provided no device\n");
+ ret = BadImplementation;
+ goto unwind;
+ }
+
+ /* XXX: If we fail halfway through, we don't seem to have any way to
+ * empty the iterator, so you'll end up with some device IDs,
+ * plus an error. This seems to be a shortcoming in the D-Bus
+ * API. */
+ for (; dev; dev = dev->next) {
+ if (!dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32,
+ &dev->id)) {
+ ErrorF("[config/dbus] couldn't append to iterator\n");
+ ret = BadAlloc;
+ goto unwind;
+ }
+ }
+
+unwind:
+ if (ret != Success) {
+ if (dev)
+ RemoveDevice(dev, TRUE);
+
+ err = -ret;
+ dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err);
+ }
+
+ while (options) {
+ tmpo = options;
+ options = options->next;
+ if (tmpo->key)
+ free(tmpo->key);
+ if (tmpo->value)
+ free(tmpo->value);
+ free(tmpo);
+ }
+
+ return ret;
+}
+
+static int
+remove_device(DBusMessage *message, DBusMessage *reply, DBusError *error)
+{
+ int deviceid, ret, err;
+ DeviceIntPtr dev;
+ DBusMessageIter iter, reply_iter;
+
+ dbus_message_iter_init_append(reply, &reply_iter);
+
+ if (!dbus_message_iter_init(message, &iter)) {
+ ErrorF("[config/dbus] failed to init iterator\n");
+ MALFORMED_MESSAGE();
+ }
+
+ if (!dbus_message_get_args(message, error, DBUS_TYPE_UINT32,
+ &deviceid, DBUS_TYPE_INVALID)) {
+ MALFORMED_MESSAGE_ERROR();
+ }
+
+ dixLookupDevice(&dev, deviceid, serverClient, DixDestroyAccess);
+ if (!dev) {
+ DebugF("[config/dbus] bogus device id %d given\n", deviceid);
+ ret = BadMatch;
+ goto unwind;
+ }
+
+ DebugF("[config/dbus] removing device %s (id %d)\n", dev->name, deviceid);
+
+ /* Call PIE here so we don't try to dereference a device that's
+ * already been removed. */
+ OsBlockSignals();
+ ProcessInputEvents();
+ DeleteInputDeviceRequest(dev);
+ OsReleaseSignals();
+
+ ret = Success;
+
+unwind:
+ err = (ret == Success) ? ret : -ret;
+ dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err);
+
+ return ret;
+}
+
+static int
+list_devices(DBusMessage *message, DBusMessage *reply, DBusError *error)
+{
+ DeviceIntPtr dev;
+ DBusMessageIter iter, subiter;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL,
+ &subiter)) {
+ ErrorF("[config/dbus] couldn't init container\n");
+ return BadAlloc;
+ }
+ if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UINT32,
+ &dev->id)) {
+ ErrorF("[config/dbus] couldn't append to iterator\n");
+ return BadAlloc;
+ }
+ if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING,
+ &dev->name)) {
+ ErrorF("[config/dbus] couldn't append to iterator\n");
+ return BadAlloc;
+ }
+ if (!dbus_message_iter_close_container(&iter, &subiter)) {
+ ErrorF("[config/dbus] couldn't close container\n");
+ return BadAlloc;
+ }
+ }
+
+ return Success;
+}
+
+static int
+get_version(DBusMessage *message, DBusMessage *reply, DBusError *error)
+{
+ DBusMessageIter iter;
+ unsigned int version = API_VERSION;
+
+ dbus_message_iter_init_append(reply, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &version)) {
+ ErrorF("[config/dbus] couldn't append version\n");
+ return BadAlloc;
+ }
+
+ return Success;
+}
+
+static DBusHandlerResult
+message_handler(DBusConnection *connection, DBusMessage *message, void *data)
+{
+ DBusError error;
+ DBusMessage *reply;
+ struct connection_info *info = data;
+
+ /* ret is the overall D-Bus handler result, whereas err is the internal
+ * X error from our individual functions. */
+ int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ int err;
+
+ DebugF("[config/dbus] received a message for %s\n",
+ dbus_message_get_interface(message));
+
+ dbus_error_init(&error);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ ErrorF("[config/dbus] failed to create reply\n");
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto err_start;
+ }
+
+ if (strcmp(dbus_message_get_member(message), "add") == 0)
+ err = add_device(message, reply, &error);
+ else if (strcmp(dbus_message_get_member(message), "remove") == 0)
+ err = remove_device(message, reply, &error);
+ else if (strcmp(dbus_message_get_member(message), "listDevices") == 0)
+ err = list_devices(message, reply, &error);
+ else if (strcmp(dbus_message_get_member(message), "version") == 0)
+ err = get_version(message, reply, &error);
+ else
+ goto err_reply;
+
+ /* Failure to allocate is a special case. */
+ if (err == BadAlloc) {
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto err_reply;
+ }
+
+ /* While failure here is always an OOM, we don't return that,
+ * since that would result in devices being double-added/removed. */
+ if (dbus_connection_send(info->connection, reply, NULL))
+ dbus_connection_flush(info->connection);
+ else
+ ErrorF("[config/dbus] failed to send reply\n");
+
+ ret = DBUS_HANDLER_RESULT_HANDLED;
+
+err_reply:
+ dbus_message_unref(reply);
+err_start:
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static void
+connect_hook(DBusConnection *connection, void *data)
+{
+ DBusError error;
+ DBusObjectPathVTable vtable = { .message_function = message_handler, };
+ struct connection_info *info = data;
+
+ info->connection = connection;
+
+ dbus_error_init(&error);
+
+ dbus_bus_request_name(info->connection, info->busname, 0, &error);
+ if (dbus_error_is_set(&error)) {
+ ErrorF("[config/dbus] couldn't take over org.x.config: %s (%s)\n",
+ error.name, error.message);
+ goto err_start;
+ }
+
+ /* blocks until we get a reply. */
+ dbus_bus_add_match(info->connection, MATCH_RULE, &error);
+ if (dbus_error_is_set(&error)) {
+ ErrorF("[config/dbus] couldn't add match: %s (%s)\n", error.name,
+ error.message);
+ goto err_name;
+ }
+
+ if (!dbus_connection_register_object_path(info->connection,
+ info->busobject, &vtable,
+ info)) {
+ ErrorF("[config/dbus] couldn't register object path\n");
+ goto err_match;
+ }
+
+ DebugF("[dbus] registered %s, %s\n", info->busname, info->busobject);
+
+ dbus_error_free(&error);
+
+ return;
+
+err_match:
+ dbus_bus_remove_match(info->connection, MATCH_RULE, &error);
+err_name:
+ dbus_bus_release_name(info->connection, info->busname, &error);
+err_start:
+ dbus_error_free(&error);
+
+ reset_info(info);
+}
+
+static void
+disconnect_hook(void *data)
+{
+}
+
+#if 0
+void
+pre_disconnect_hook(void)
+{
+ DBusError error;
+
+ dbus_error_init(&error);
+ dbus_connection_unregister_object_path(connection_data->connection,
+ connection_data->busobject);
+ dbus_bus_remove_match(connection_data->connection, MATCH_RULE,
+ &error);
+ dbus_bus_release_name(connection_data->connection,
+ connection_data->busname, &error);
+ dbus_error_free(&error);
+}
+#endif
+
+static struct connection_info connection_data;
+static struct config_dbus_core_hook core_hook = {
+ .connect = connect_hook,
+ .disconnect = disconnect_hook,
+ .data = &connection_data,
+};
+
+int
+config_dbus_init(void)
+{
+ snprintf(connection_data.busname, sizeof(connection_data.busname),
+ "org.x.config.display%d", atoi(display));
+ snprintf(connection_data.busobject, sizeof(connection_data.busobject),
+ "/org/x/config/%d", atoi(display));
+
+ return config_dbus_core_add_hook(&core_hook);
+}
+
+void
+config_dbus_fini(void)
+{
+ config_dbus_core_remove_hook(&core_hook);
+ connection_data.busname[0] = '\0';
+ connection_data.busobject[0] = '\0';
+}
|