#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "shared.h" #include "rcm-server-main.h" #include "rcm-server-udev.h" #include "rcm-server-keymap.h" #include "rcm-server-evdev.h" #include "rcm-server-lirc.h" #include "rcm-server-rcdev.h" #include "rcm-server-kdb.h" static struct rc_device * find_device_by_path(struct manager *mgr, const char *path) { struct rc_device *rcdev; list_for_each_entry(rcdev, &mgr->rc_devs, list) if (!strcmp(rcdev->path, path)) return rcdev; return NULL; } static int property_get(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 rc_device *rcdev; rcdev = find_device_by_path(mgr, path); if (!rcdev) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); return -EINVAL; } if (!strcmp(property, "SysName")) return sd_bus_message_append(reply, "s", rcdev->name); else if (!strcmp(property, "Description")) return sd_bus_message_append(reply, "s", rcdev->input_name); else if (!strcmp(property, "DriverName")) return sd_bus_message_append(reply, "s", rcdev->driver_name); else if (!strcmp(property, "KernelKeymapName")) return sd_bus_message_append(reply, "s", rcdev->keymap_name); else if (!strcmp(property, "HardwareType")) return sd_bus_message_append(reply, "s", "ir"); else if (!strcmp(property, "Error")) return sd_bus_message_append(reply, "s", rcdev->error); sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidProperty", "Sorry, invalid property"); return -EINVAL; } static int sdbus_get_psk_triplet(sd_bus_message *m, unsigned *ret_protocol, uint64_t *ret_scancode, struct linux_input_keycode **ret_keycode) { const char *protocol = NULL; unsigned protocol_numeric; uint64_t scancode; bool scancode_found = false; struct linux_input_keycode *lik = NULL; const char *keycode = NULL; unsigned i; int r; r = sd_bus_message_enter_container(m, 'a', "{sv}"); if (r < 1) return r; while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *name; const char *contents; char type; r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); if (r < 0) return r; r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) return r; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); if (r < 0) return r; r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) return r; if (!strcmp(name, "protocol")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for protocol (%c)\n", type); return -EINVAL; } if (protocol) { printf("Protocol specified more than once\n"); return -EINVAL; } r = sd_bus_message_read_basic(m, type, &protocol); if (r < 0) return r; for (i = 0; rc_protocols[i]; i++) { if (!strcmp(rc_protocols[i], protocol)) break; } if (!rc_protocols[i]) { printf("Invalid protocol name (%s)\n", protocol); return -EINVAL; } protocol_numeric = i; } else if (!strcmp(name, "scancode")) { if (type != SD_BUS_TYPE_UINT64) { printf("Invalid type for scancode (%c)\n", type); return -EINVAL; } if (scancode_found) { printf("Scancode specified more than once\n"); return -EINVAL; } r = sd_bus_message_read_basic(m, type, &scancode); if (r < 0) return r; scancode_found = true; } else if (!strcmp(name, "keycode")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for keycode (%c)\n", type); return -EINVAL; } if (keycode) { printf("Keycode specified more than once\n"); return -EINVAL; } r = sd_bus_message_read_basic(m, type, &keycode); if (r < 0) return r; if (strcmp(keycode, "KEY_RESERVED")) { lik = get_linux_keycode_by_name(keycode); if (!lik) { printf("Invalid keycode name (%s)\n", keycode); return -EINVAL; } } } else { r = sd_bus_message_skip(m, contents); if (r < 0) return r; } r = sd_bus_message_exit_container(m); if (r < 0) return r; r = sd_bus_message_exit_container(m); if (r < 0) return r; } if (r < 0) return r; r = sd_bus_message_exit_container(m); if (r < 0) return r; if (!protocol) { printf("Protocol missing\n"); return -EINVAL; } if (!scancode_found) { printf("Scancode missing\n"); return -EINVAL; } if (!keycode) { printf("Keycode missing\n"); return -EINVAL; } *ret_protocol = protocol_numeric; *ret_scancode = scancode; *ret_keycode = lik; return 1; } static int method_getkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; struct manager *mgr = userdata; struct rc_device *rcdev; unsigned protocol_numeric; uint64_t scancode; struct linux_input_keycode *lik; unsigned i = 0; int r; rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); return -EINVAL; } if (rcdev->evdev_fd < 0) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available"); r = -EINVAL; goto out; } r = sd_bus_message_new_method_return(m, &reply); if (r < 0) goto out; r = sd_bus_message_open_container(reply, 'a', "a{sv}"); if (r < 0) goto out; while ((r = evdev_get_mapping(rcdev, i, &protocol_numeric, &scancode, &lik)) > 0) { r = sd_bus_message_append(reply, "a{sv}", 3, "protocol", "s", rc_protocols[protocol_numeric], "scancode", "t", scancode, "keycode", "s", lik->name); if (r < 0) goto out; i++; } 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_setkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; struct manager *mgr = userdata; struct rc_device *rcdev; unsigned protocol; uint64_t scancode; struct linux_input_keycode *keycode; int r; rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); r = -EINVAL; goto out; } if (rcdev->evdev_fd < 0) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available"); r = -EINVAL; goto out; } r = sd_bus_message_enter_container(m, 'a', "a{sv}"); if (r < 0) goto out; while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &keycode)) > 0) { printf("%s kernel mapping %s:0x%08lx:%s\n", keycode ? "Setting" : "Unsetting", rc_protocols[protocol], scancode, keycode ? keycode->name : ""); evdev_set_mapping(rcdev, protocol, scancode, keycode); } if (r < 0) goto out; r = sd_bus_message_exit_container(m); if (r < 0) goto out; return sd_bus_reply_method_return(m, NULL); out: return sd_bus_error_set_errno(error, r); } 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 rc_device *rcdev; struct keymap *keymap; int r; rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) { 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, &rcdev->keymaps, list) { printf("Listing keymaps for %s: %s\n", rcdev->name, keymap->name); r = sd_bus_message_append(reply, "s", keymap->id); 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 rc_device *rcdev; struct keymap *keymap; const char *id; int r; unsigned i; rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); return -EINVAL; } r = sd_bus_message_read(m, "s", &id); if (r < 0) { fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); return r; } keymap = find_keymap_by_id(rcdev, id); 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, "s", keymap->name); if (r < 0) goto out; r = sd_bus_message_append(reply, "s", keymap->description); 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; /* Keymap */ r = sd_bus_message_open_container(reply, 'a', "a{sv}"); if (r < 0) goto out; for (i = 0; i < keymap->keycode_count; i++) { r = sd_bus_message_append(reply, "a{sv}", 3, "protocol", "s", rc_protocols[keymap->keycodes[i].protocol], "scancode", "t", keymap->keycodes[i].scancode, "keycode", "s", keymap->keycodes[i].lik->name); if (r < 0) goto out; } r = sd_bus_message_close_container(reply); if (r < 0) goto out; /* Layout */ r = sd_bus_message_open_container(reply, 'a', "a{sv}"); if (r < 0) goto out; for (i = 0; i < (keymap->rows * keymap->cols); i++) { if (!keymap->layout[i]) r = sd_bus_message_append(reply, "a{sv}", 1, "type", "s", "blank"); else r = sd_bus_message_append(reply, "a{sv}", 2, "type", "s", "button", "keycode", "s", keymap->layout[i]->lik->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_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap, const char **ret_id, unsigned *ret_keycode_count, uint16_t *ret_cols, uint16_t *ret_rows) { const char *id; const char *name; const char *description; unsigned protocol; uint64_t scancode; struct linux_input_keycode *lik; uint16_t cols, rows; unsigned keycode_count = 0; unsigned layout_count = 0; unsigned i; int r; r = sd_bus_message_rewind(m, 1); if (r < 0) return r; r = sd_bus_message_read(m, "sssqq", &id, &name, &description, &cols, &rows); if (r < 0) { fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); return r; } if (!id) { printf("Id missing\n"); return -EINVAL; } if (!name) { printf("Name missing\n"); return -EINVAL; } if (!description) { printf("Description missing\n"); return -EINVAL; } if (cols < 1 || cols > REMOTE_LAYOUT_MAX_WIDTH) { printf("Invalid column size\n"); return -EINVAL; } if (rows < 1 || rows > REMOTE_LAYOUT_MAX_HEIGHT) { printf("Invalid row size\n"); return -EINVAL; } if (keymap) { keymap->id = strdup(id); keymap->name = strdup(name); keymap->description = strdup(description); keymap->cols = cols; keymap->rows = rows; if (!keymap->id || !keymap->name || !keymap->description) return -ENOMEM; } r = sd_bus_message_enter_container(m, 'a', "a{sv}"); if (r < 0) return r; while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &lik)) > 0) { if (!lik) { printf("Keycode entry without keycode\n"); return -EINVAL; } if (keymap) { keymap->keycodes[keycode_count].protocol = protocol; keymap->keycodes[keycode_count].scancode = scancode; keymap->keycodes[keycode_count].lik = lik; } keycode_count++; } if (r < 0) return r; r = sd_bus_message_exit_container(m); if (r < 0) return r; r = sd_bus_message_enter_container(m, 'a', "a{sv}"); if (r < 0) return r; while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { bool blank = false; bool button = false; struct linux_input_keycode *lik = NULL; while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *name; const char *contents; const char *button_type; const char *keycode; char type; r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); if (r < 0) return r; r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) return r; r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); if (r < 0) return r; r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) return r; if (!strcmp(name, "type")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for type (%c)\n", type); return -EINVAL; } r = sd_bus_message_read_basic(m, type, &button_type); if (r < 0) return r; if (button || blank) { printf("Multiple types specified in layout\n"); return -EINVAL; } if (!strcasecmp(button_type, "button")) button = true; else if (!strcasecmp(button_type, "blank")) blank = true; else { printf("Invalid button type: %s\n", button_type); return -EINVAL; } } else if (!strcmp(name, "keycode")) { if (type != SD_BUS_TYPE_STRING) { printf("Invalid type for keycode (%c)\n", type); return -EINVAL; } if (lik) { printf("Multiple keycodes specified in layout\n"); return -EINVAL; } r = sd_bus_message_read_basic(m, type, &keycode); if (r < 0) return r; lik = get_linux_keycode_by_name(keycode); if (!lik) { printf("Invalid keycode name in layout (%s)\n", keycode); return -EINVAL; } } else { r = sd_bus_message_skip(m, contents); if (r < 0) return r; } r = sd_bus_message_exit_container(m); if (r < 0) return r; r = sd_bus_message_exit_container(m); if (r < 0) return r; } if (r < 0) return r; if ((!blank && !button) || (blank && button) || (button && !lik) || (blank && lik)) { printf("Invalid layout specification\n"); return -EINVAL; } if (keymap) { if (blank) keymap->layout[layout_count] = NULL; else { for (i = 0; i < keycode_count; i++) { if (keymap->keycodes[i].lik == lik) break; } if (i >= keycode_count) { printf("Invalid keycode in layout: '%s'\n", lik->name); return -EINVAL; } keymap->layout[layout_count] = &keymap->keycodes[i]; } } layout_count++; r = sd_bus_message_exit_container(m); if (r < 0) return r; } if (r < 0) return r; r = sd_bus_message_exit_container(m); if (r < 0) return r; if (!sd_bus_message_at_end(m, 1)) { printf("Trailing message parts\n"); return -EINVAL; } if (keycode_count < 1) { printf("No keycodes specified\n"); return -EINVAL; } if (layout_count < 1) { printf("No layout specified\n"); return -EINVAL; } if (rows * cols != layout_count) { fprintf(stderr, "Layout (%u) does not match rows x cols (%ux%u)\n", layout_count, rows, cols); return -EINVAL; } if (ret_id) *ret_id = id; if (ret_keycode_count) *ret_keycode_count = keycode_count; if (keymap) keymap->keycode_count = keycode_count; if (ret_cols) *ret_cols = cols; if (ret_rows) *ret_rows = rows; return 0; } static int method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error) { struct manager *mgr = userdata; struct rc_device *rcdev; struct keymap *old_keymap; struct keymap *new_keymap; const char *id; unsigned keycode_count; uint16_t cols, rows; int r; rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); r = method_setkeymap_parse_dbus_msg(m, NULL, &id, &keycode_count, &cols, &rows); if (r < 0) goto out; old_keymap = find_keymap_by_id(rcdev, id); if (!old_keymap) return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidKeymap", "Sorry, unknown keymap"); printf("Asked to update keymap '%s'\n", id); new_keymap = zmalloc(sizeof(*new_keymap) + sizeof(struct keycode) * keycode_count); if (!new_keymap) { r = -ENOMEM; goto out; } new_keymap->layout = zmalloc(sizeof(struct keycode *) * cols * rows); if (!new_keymap->layout) { r = -ENOMEM; goto out; } r = method_setkeymap_parse_dbus_msg(m, new_keymap, NULL, NULL, NULL, NULL); if (r < 0) goto out; printf("\tUpdated keymap: name (%s), desc (%s), keycodes(%u), rows(%u), cols(%u)\n", new_keymap->name, new_keymap->description, new_keymap->keycode_count, new_keymap->rows, new_keymap->cols); r = keymap_write(new_keymap); if (r < 0) goto out; list_replace(&old_keymap->list, &new_keymap->list); keymap_free(old_keymap); return sd_bus_reply_method_return(m, NULL); out: keymap_free(new_keymap); return sd_bus_error_set_errno(error, r); } static int method_transmit(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; struct manager *mgr = userdata; struct rc_device *rcdev; const void *v; size_t l; int r; const uint32_t *values; size_t count; printf("Transmit method called\n"); rcdev = find_device_by_path(mgr, sd_bus_message_get_path(m)); if (!rcdev) { sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); return -EINVAL; } r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, &v, &l); if (r < 0) { goto out; } else if (r == 0 || l % sizeof(uint32_t) != 0) { r = -EBADMSG; goto out; } values = v; count = l / sizeof(uint32_t); lirc_write(rcdev->lirc_fd, values, count); return sd_bus_reply_method_return(m, NULL); out: return sd_bus_error_set_errno(error, r); } static const sd_bus_vtable device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("SysName", "s", property_get, 0, 0), SD_BUS_PROPERTY("Description", "s", property_get, 0, 0), SD_BUS_PROPERTY("DriverName", "s", property_get, 0, 0), SD_BUS_PROPERTY("KernelKeymapName", "s", property_get, 0, 0), SD_BUS_PROPERTY("HardwareType", "s", property_get, 0, 0), SD_BUS_PROPERTY("Error", "s", property_get, 0, 0), SD_BUS_METHOD("GetKernelMappings", NULL, "aa{sv}", method_getkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetKernelMappings", "aa{sv}", NULL, method_setkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ListKeymaps", NULL, "as", method_listkeymaps, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetKeymap", "s", "ssqqaa{sv}aa{sv}", method_getkeymap, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetKeymap", "sssqqaa{sv}aa{sv}", NULL, method_setkeymap, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Transmit", "au", NULL, method_transmit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("KeyPressed", "sts", 0), SD_BUS_SIGNAL("KeyReleased", "s", 0), SD_BUS_SIGNAL("Event", "s", 0), SD_BUS_VTABLE_END }; 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 rc_device *rcdev; int i = 0; if (!path) return 0; nodes = zmalloc((mgr->num_rc_devs + 1) * sizeof(char *)); if (!nodes) return -ENOMEM; list_for_each_entry(rcdev, &mgr->rc_devs, list) { nodes[i] = strdup(rcdev->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; kdb_close(mgr); sd_event_source_unref(mgr->udev_ev); sd_bus_detach_event(mgr->bus); sd_event_unref(mgr->event); udev_close(mgr); while (!list_empty(&mgr->rc_devs)) { struct rc_device *rcdev = list_first_entry(&mgr->rc_devs, typeof(*rcdev), list); rcdev_free(rcdev); } 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_flush_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->rc_devs); r = sd_event_default(&mgr->event); if (r < 0) { fprintf(stderr, "Failed to create sd_event: %s\n", strerror(-r)); goto finish; } r = kdb_init(mgr, "./rcm.sqlite"); if (r < 0) { fprintf(stderr, "Failed to open/create sqlite database\n"); goto finish; } r = kdb_add_directory(mgr, "./keymaps/db"); if (r < 0) { fprintf(stderr, "Failed to add keymap directory: %s\n", strerror(-r)); goto finish; } 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_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; }