int linux_netlink_start_event_monitor(void) { int socktype = SOCK_RAW; int ret; snl.nl_groups = KERNEL; #if defined(SOCK_CLOEXEC) socktype |= SOCK_CLOEXEC; #endif #if defined(SOCK_NONBLOCK) socktype |= SOCK_NONBLOCK; #endif linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT); if (-1 == linux_netlink_socket && EINVAL == errno) { linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); } if (-1 == linux_netlink_socket) { return LIBUSB_ERROR_OTHER; } ret = set_fd_cloexec_nb (linux_netlink_socket); if (0 != ret) { close (linux_netlink_socket); linux_netlink_socket = -1; return LIBUSB_ERROR_OTHER; } ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl)); if (0 != ret) { close(linux_netlink_socket); return LIBUSB_ERROR_OTHER; } /* TODO -- add authentication */ /* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */ ret = usbi_pipe(netlink_control_pipe); if (ret) { usbi_err(NULL, "could not create netlink control pipe"); close(linux_netlink_socket); return LIBUSB_ERROR_OTHER; } ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); if (0 != ret) { close(netlink_control_pipe[0]); close(netlink_control_pipe[1]); close(linux_netlink_socket); return LIBUSB_ERROR_OTHER; } return LIBUSB_SUCCESS; }
int event_init_platform(void) { int phase = 0; // create read set if (event_reserve_socket_set(&_socket_read_set, 32) < 0) { log_error("Could not create socket read set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 1; // create write set if (event_reserve_socket_set(&_socket_write_set, 32) < 0) { log_error("Could not create socket write set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 2; // create error set if (event_reserve_socket_set(&_socket_error_set, 32) < 0) { log_error("Could not create socket error set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 3; // create stop pipe if (pipe_create(&_stop_pipe, 0) < 0) { log_error("Could not create stop pipe: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 4; if (event_add_source(_stop_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC, EVENT_READ, NULL, NULL) < 0) { goto cleanup; } phase = 5; // create USB poll thread _usb_poll_running = false; _usb_poll_stuck = false; if (usbi_pipe(_usb_poll_suspend_pipe) < 0) { log_error("Could not create USB suspend pipe"); goto cleanup; } phase = 6; if (pipe_create(&_usb_poll_ready_pipe, 0) < 0) { log_error("Could not create USB ready pipe: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 7; if (array_create(&_usb_poll_pollfds, 32, sizeof(struct usbi_pollfd), true) < 0) { log_error("Could not create USB pollfd array: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 8; if (semaphore_create(&_usb_poll_resume) < 0) { log_error("Could not create USB resume semaphore: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 9; if (semaphore_create(&_usb_poll_suspend) < 0) { log_error("Could not create USB suspend semaphore: %s (%d)", get_errno_name(errno), errno); goto cleanup; } phase = 10; cleanup: switch (phase) { // no breaks, all cases fall through intentionally case 9: semaphore_destroy(&_usb_poll_suspend); case 8: semaphore_destroy(&_usb_poll_resume); case 7: pipe_destroy(&_usb_poll_ready_pipe); case 6: usbi_close(_usb_poll_suspend_pipe[0]); usbi_close(_usb_poll_suspend_pipe[1]); case 5: event_remove_source(_stop_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC); case 4: pipe_destroy(&_stop_pipe); case 3: free(_socket_error_set); case 2: free(_socket_write_set); case 1: free(_socket_read_set); default: break; } return phase == 10 ? 0 : -1; }
int linux_udev_start_event_monitor(void) { int r; assert(udev_ctx == NULL); udev_ctx = udev_new(); if (!udev_ctx) { usbi_err(NULL, "could not create udev context"); goto err; } udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev"); if (!udev_monitor) { usbi_err(NULL, "could not initialize udev monitor"); goto err_free_ctx; } r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0); if (r) { usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem"); goto err_free_monitor; } if (udev_monitor_enable_receiving(udev_monitor)) { usbi_err(NULL, "failed to enable the udev monitor"); goto err_free_monitor; } udev_monitor_fd = udev_monitor_get_fd(udev_monitor); /* Some older versions of udev are not non-blocking by default, * so make sure this is set */ r = fcntl(udev_monitor_fd, F_GETFL); if (r == -1) { usbi_err(NULL, "getting udev monitor fd flags (%d)", errno); goto err_free_monitor; } r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK); if (r) { usbi_err(NULL, "setting udev monitor fd flags (%d)", errno); goto err_free_monitor; } r = usbi_pipe(udev_control_pipe); if (r) { usbi_err(NULL, "could not create udev control pipe"); goto err_free_monitor; } r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL); if (r) { usbi_err(NULL, "creating hotplug event thread (%d)", r); goto err_close_pipe; } return LIBUSB_SUCCESS; err_close_pipe: close(udev_control_pipe[0]); close(udev_control_pipe[1]); err_free_monitor: udev_monitor_unref(udev_monitor); udev_monitor = NULL; udev_monitor_fd = -1; err_free_ctx: udev_unref(udev_ctx); err: udev_ctx = NULL; return LIBUSB_ERROR_OTHER; }