diff options
Diffstat (limited to 'rcm-server.c')
-rw-r--r-- | rcm-server.c | 563 |
1 files changed, 0 insertions, 563 deletions
diff --git a/rcm-server.c b/rcm-server.c deleted file mode 100644 index 11223b1..0000000 --- a/rcm-server.c +++ /dev/null @@ -1,563 +0,0 @@ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <libudev.h> -#include <unistd.h> -#include <string.h> -#include <systemd/sd-bus.h> -#include <errno.h> - -#include "utils.h" -#include "rcm-server.h" -#include "rcm-server-keymap.h" - -static int -method_echostring(sd_bus_message *m, void *userdata, sd_bus_error *error) -{ - const char *msg; - int r; - - r = sd_bus_message_read(m, "s", &msg); - if (r < 0) { - fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); - return sd_bus_error_set_errno(error, r); - } - - return sd_bus_reply_method_return(m, "s", msg); -} - -static struct device * -find_device_by_path(struct manager *mgr, const char *path) -{ - struct device *dev; - - list_for_each_entry(dev, &mgr->devices, list) - if (!strcmp(dev->path, path)) - return dev; - - return NULL; -} - -static int -property_get_driver_name(sd_bus *bus, const char *path, const char *interface, - const char *property, sd_bus_message *reply, void *userdata, - sd_bus_error *error) -{ - struct manager *mgr = userdata; - struct device *dev; - - dev = find_device_by_path(mgr, path); - if (!dev) { - sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); - return -EINVAL; - } - - if (!strcmp(property, "DriverName")) - return sd_bus_message_append(reply, "s", dev->driver_name); - else if (!strcmp(property, "KernelKeymapName")) - return sd_bus_message_append(reply, "s", dev->keymap_name); - - sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidProperty", "Sorry, invalid property"); - return -EINVAL; -} - - -static int -method_listkeymaps(sd_bus_message *m, void *userdata, sd_bus_error *error) -{ - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - struct manager *mgr = userdata; - struct device *dev; - struct keymap *keymap; - int r; - - dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); - if (!dev) { - sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); - return -EINVAL; - } - - r = sd_bus_message_new_method_return(m, &reply); - if (r < 0) - goto out; - - r = sd_bus_message_open_container(reply, 'a', "s"); - if (r < 0) - goto out; - - list_for_each_entry(keymap, &dev->keymaps, list) { - printf("Listing keymaps for %s: %s\n", dev->name, keymap->name); - r = sd_bus_message_append(reply, "s", keymap->name); - if (r < 0) - goto out; - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto out; - - r = sd_bus_send(NULL, reply, NULL); - if (r < 0) - goto out; - - return 1; - -out: - return sd_bus_error_set_errno(error, r); -} - -static int -method_getkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) -{ - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - struct manager *mgr = userdata; - struct device *dev; - struct keymap *keymap; - const char *name; - int r; - unsigned i; - - dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); - if (!dev) { - sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); - return -EINVAL; - } - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) { - fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); - return r; - } - - keymap = find_keymap_by_name(dev, name); - if (!keymap) { - sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidKeymap", "Sorry, unknown keymap"); - return -EINVAL; - } - - r = sd_bus_message_new_method_return(m, &reply); - if (r < 0) - goto out; - - r = sd_bus_message_append(reply, "q", keymap->cols); - if (r < 0) - goto out; - - r = sd_bus_message_append(reply, "q", keymap->rows); - if (r < 0) - goto out; - - r = sd_bus_message_open_container(reply, 'a', "a{sv}"); - if (r < 0) - goto out; - - for (i = 0; i < (keymap->rows * keymap->cols); i++) { - r = sd_bus_message_append(reply, "a{sv}", 2, - "name", "s", keymap->layout[i]->name, - "keycode", "s", keymap->layout[i]->value); - if (r < 0) - goto out; - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto out; - - r = sd_bus_send(NULL, reply, NULL); - if (r < 0) - goto out; - - return 1; - -out: - return sd_bus_error_set_errno(error, r); -} - -static const sd_bus_vtable device_vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_PROPERTY("DriverName", "s", property_get_driver_name, 0, 0), - SD_BUS_PROPERTY("KernelKeymapName", "s", property_get_driver_name, 0, 0), - SD_BUS_METHOD("EchoString", "s", "s", method_echostring, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ListKeymaps", NULL, "as", method_listkeymaps, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetKeymap", "s", "qqaa{sv}", method_getkeymap, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END -}; - -static int -my_bus_emit_object_changed(sd_bus *bus, const char *path, bool added) -{ - int r; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - - printf("Sending signal %s for path %s\n", - added ? "InterfacesAdded" : "InterfacesRemoved", - path); - - r = sd_bus_message_new_signal(bus, &m, "/org/gnome/RemoteControlManager", - "org.freedesktop.DBus.ObjectManager", - added ? "InterfacesAdded" : "InterfacesRemoved"); - if (r < 0) - return r; - - r = sd_bus_message_append_basic(m, 'o', path); - if (r < 0) - return r; - - if (added) { - r = sd_bus_message_open_container(m, 'a', "{sa{sv}}"); - if (r < 0) - return r; - - r = sd_bus_message_append(m, "{sa{sv}}", "org.gnome.RemoteControlManager.Device", 0); - if (r < 0) - return r; - } else { - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return r; - - r = sd_bus_message_append(m, "s", "org.gnome.RemoteControlManager.Device"); - if (r < 0) - return r; - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return r; - - r = sd_bus_send(bus, m, NULL); - return r; -} - -static void -remove_device(struct manager *mgr, struct udev_device *udev) -{ - const char *name; - struct device *device; - - name = udev_device_get_sysname(udev); - printf("Asked to remove device %s\n", name); - - list_for_each_entry(device, &mgr->devices, list) { - if (strcmp(device->name, name)) - continue; - list_del(&device->list); - my_bus_emit_object_changed(mgr->bus, device->path, false); - mgr->num_devices--; - break; - } -} - -static void -add_device(struct manager *mgr, struct udev_device *udev) -{ - const char *name; - const char *str; - char *path; - struct device *device; - - name = udev_device_get_sysname(udev); - if (asprintf(&path, "/org/gnome/RemoteControlManager/%s", name) < 0) { - fprintf(stderr, "asprintf failed: %m\n"); - return; - } - - device = malloc(sizeof(*device)); - if (!device) { - fprintf(stderr, "malloc failed: %m\n"); - free(path); - return; - } - - list_init(&device->keymaps); - device->path = path; - device->name = device->path + strlen("/org/gnome/RemoteControlManager/"); - - if (keymaps_load(device) < 0) { - fprintf(stderr, "failed to load keymaps: %m\n"); - free(path); - free(device); - } - - str = udev_device_get_sysattr_value(udev, "uevent"); - if (str) { - char tmp[strlen(str) + 1]; - char *token; - - strcpy(tmp, str); - - for (token = strtok(tmp, "\n"); token; token = strtok(NULL, "\n")) { - if (!strncmp(token, "DRV_NAME=", strlen("DRV_NAME="))) - device->driver_name = strdup(token + strlen("DRV_NAME=")); - else if (!strncmp(token, "NAME=", strlen("NAME="))) - device->keymap_name = strdup(token + strlen("NAME=")); - else - printf("Unused uevent: %s\n", token); - } - } - - printf("Adding Device Object\n"); - printf(" Path : %s\n", udev_device_get_syspath(udev)); - printf(" Node : %s\n", udev_device_get_devnode(udev)); - printf(" Subsystem : %s\n", udev_device_get_subsystem(udev)); - printf(" Devtype : %s\n", udev_device_get_devtype(udev)); - printf(" Action : %s\n", udev_device_get_action(udev)); - printf(" Protocols : %s\n", - udev_device_get_sysattr_value(udev, "protocols")); - printf(" Uevent : %s\n", - udev_device_get_sysattr_value(udev, "uevent")); - - list_add(&device->list, &mgr->devices); - mgr->num_devices++; - - my_bus_emit_object_changed(mgr->bus, path, true); -} - -static int -udev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata) -{ - struct manager *mgr = userdata; - struct udev_device *dev; - - if (revents & EPOLLHUP) { - fprintf(stderr, "udev connection closed!\n"); - return 0; - } - - if (!(revents & EPOLLIN)) { - fprintf(stderr, "unexpected udev event: %" PRIu32 "\n", revents); - return 0; - } - - while ((dev = udev_monitor_receive_device(mgr->udev_mon))) { - printf("Read device: %s\n", udev_device_get_syspath(dev)); - if (!strcmp(udev_device_get_action(dev), "add")) - add_device(mgr, dev); - else if (!strcmp(udev_device_get_action(dev), "remove")) - remove_device(mgr, dev); - udev_device_unref(dev); - } - - return 1; -} - -static int -udev_setup(struct manager *mgr) -{ - struct udev_enumerate *enumerate; - struct udev_list_entry *devices, *dev_list_entry; - struct udev_device *dev; - - mgr->udev = udev_new(); - if (!mgr->udev) - return -ENOMEM; - - mgr->udev_mon = udev_monitor_new_from_netlink(mgr->udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(mgr->udev_mon, "rc", NULL); - udev_monitor_enable_receiving(mgr->udev_mon); - - enumerate = udev_enumerate_new(mgr->udev); - udev_enumerate_add_match_subsystem(enumerate, "rc"); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path; - - path = udev_list_entry_get_name(dev_list_entry); - if (!path) { - printf("Failed to get udev name\n"); - continue; - } - - dev = udev_device_new_from_syspath(mgr->udev, path); - if (!dev) { - printf("Failed to create udev device\n"); - continue; - } - - add_device(mgr, dev); - - udev_device_unref(dev); - } - udev_enumerate_unref(enumerate); - - return sd_event_add_io(mgr->event, &mgr->udev_ev, - udev_monitor_get_fd(mgr->udev_mon), - EPOLLIN, udev_read, mgr); -} - -static int -enumerator(sd_bus *bus, const char *path, void *userdata, char ***retnodes, sd_bus_error *error) -{ - _cleanup_strv_free_ char **nodes = NULL; - struct manager *mgr = userdata; - struct device *device; - int i = 0; - - if (!path) - return 0; - - nodes = zmalloc((mgr->num_devices + 1) * sizeof(char *)); - if (!nodes) - return -ENOMEM; - - list_for_each_entry(device, &mgr->devices, list) { - nodes[i] = strdup(device->path); - if (!nodes[i]) - return -ENOMEM; - i++; - } - - nodes[i++] = NULL; - *retnodes = nodes; - nodes = NULL; - - return 1; -} - -static void -free_manager(struct manager *mgr) { - if (!mgr) - return; - - sd_event_source_unref(mgr->udev_ev); - sd_bus_detach_event(mgr->bus); - sd_event_unref(mgr->event); - udev_monitor_unref(mgr->udev_mon); - udev_unref(mgr->udev); - - while (!list_empty(&mgr->devices)) { - struct device *dev = list_first_entry(&mgr->devices, typeof(*dev), list); - list_del(&dev->list); - free(dev->path); - free(dev->driver_name); - free(dev->keymap_name); - - while (!list_empty(&dev->keymaps)) { - struct keymap *keymap = list_first_entry(&dev->keymaps, typeof(*keymap), list); - list_del(&keymap->list); - free(keymap->name); - free(keymap); - } - - free(dev); - } - free(mgr); -} - -static int -block_signals(void) -{ - sigset_t sigset; - int r; - - r = sigemptyset(&sigset); - if (r < 0) - return r; - - r = sigaddset(&sigset, SIGINT); - if (r < 0) - return r; - - r = sigaddset(&sigset, SIGTERM); - if (r < 0) - return r; - - return sigprocmask(SIG_BLOCK, &sigset, NULL); -} - -int -main(int argc, char **argv) -{ - int r; - struct manager *mgr; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; - _cleanup_bus_slot_unref_ struct sd_bus_slot *vtable_slot = NULL; - _cleanup_bus_slot_unref_ struct sd_bus_slot *enumerator_slot = NULL; - _cleanup_bus_slot_unref_ struct sd_bus_slot *objm_slot = NULL; - _cleanup_event_source_unref_ sd_event_source *sigint_ev = NULL; - _cleanup_event_source_unref_ sd_event_source *sigterm_ev = NULL; - - mgr = zmalloc(sizeof(*mgr)); - if (!mgr) { - fprintf(stderr, "Failed to allocate memory: %m\n"); - goto finish; - } - list_init(&mgr->devices); - - r = sd_bus_open_user(&bus); - if (r < 0) { - fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r)); - goto finish; - } - mgr->bus = bus; - - r = sd_bus_request_name(mgr->bus, "org.gnome.RemoteControlManager", 0); - if (r < 0) { - fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r)); - goto finish; - } - - r = sd_bus_add_fallback_vtable(mgr->bus, &vtable_slot, "/org/gnome/RemoteControlManager", - "org.gnome.RemoteControlManager.Device", - device_vtable, NULL, mgr); - if (r < 0) { - fprintf(stderr, "Failed to add vtable: %s\n", strerror(-r)); - goto finish; - } - - r = sd_bus_add_node_enumerator(mgr->bus, &enumerator_slot, "/org/gnome/RemoteControlManager", enumerator, mgr); - if (r < 0) { - fprintf(stderr, "Failed to create node enumerator: %s\n", strerror(-r)); - goto finish; - } - - r = sd_bus_add_object_manager(mgr->bus, &objm_slot, "/org/gnome/RemoteControlManager"); - if (r < 0) { - fprintf(stderr, "Failed to create object manager: %s\n", strerror(-r)); - goto finish; - } - - r = sd_event_default(&mgr->event); - if (r < 0) { - fprintf(stderr, "Failed to create sd_event: %s\n", strerror(-r)); - goto finish; - } - - r = sd_bus_attach_event(mgr->bus, mgr->event, 0); - if (r < 0) { - fprintf(stderr, "Failed to attach bus to event loop: %s\n", strerror(-r)); - goto finish; - } - - r = udev_setup(mgr); - if (r < 0) { - fprintf(stderr, "Failed to setup udev monitoring: %s\n", strerror(-r)); - goto finish; - } - - r = block_signals(); - if (r < 0) { - fprintf(stderr, "Failed to block signals: %m\n"); - goto finish; - } - - sd_event_add_signal(mgr->event, &sigint_ev, SIGINT, NULL, NULL); - sd_event_add_signal(mgr->event, &sigterm_ev, SIGTERM, NULL, NULL); - - r = sd_event_loop(mgr->event); - if (r < 0) { - fprintf(stderr, "Event loop failed: %s\n", strerror(-r)); - goto finish; - } - - sd_event_get_exit_code(mgr->event, &r); - -finish: - free_manager(mgr); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} - |