diff options
Diffstat (limited to 'src/rfkill/rfkill.c')
-rw-r--r-- | src/rfkill/rfkill.c | 321 |
1 files changed, 98 insertions, 223 deletions
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index 7f3e055b1a..ac21dc064c 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -3,14 +3,16 @@ #include <linux/rfkill.h> #include <poll.h> -#include "libudev.h" #include "sd-daemon.h" +#include "sd-device.h" #include "alloc-util.h" +#include "device-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" #include "io-util.h" +#include "main-func.h" #include "mkdir.h" #include "parse-util.h" #include "proc-cmdline.h" @@ -31,6 +33,11 @@ typedef struct write_queue_item { int state; } write_queue_item; +typedef struct Context { + LIST_HEAD(write_queue_item, write_queue); + int rfkill_fd; +} Context; + static struct write_queue_item* write_queue_item_free(struct write_queue_item *item) { if (!item) return NULL; @@ -54,121 +61,39 @@ static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int); static int find_device( - struct udev *udev, const struct rfkill_event *event, - struct udev_device **ret) { - + sd_device **ret) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_free_ char *sysname = NULL; - struct udev_device *device; const char *name; + int r; - assert(udev); assert(event); assert(ret); if (asprintf(&sysname, "rfkill%i", event->idx) < 0) return log_oom(); - device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname); - if (!device) - return log_full_errno(IN_SET(errno, ENOENT, ENXIO, ENODEV) ? LOG_DEBUG : LOG_ERR, errno, - "Failed to open device '%s': %m", sysname); - - name = udev_device_get_sysattr_value(device, "name"); - if (!name) { - log_debug("Device has no name, ignoring."); - udev_device_unref(device); - return -ENOENT; - } - - log_debug("Operating on rfkill device '%s'.", name); - - *ret = device; - return 0; -} - -static int wait_for_initialized( - struct udev *udev, - struct udev_device *device, - struct udev_device **ret) { - - _cleanup_(udev_monitor_unrefp) struct udev_monitor *monitor = NULL; - struct udev_device *d; - const char *sysname; - int watch_fd, r; - - assert(udev); - assert(device); - assert(ret); - - if (udev_device_get_is_initialized(device) != 0) { - *ret = udev_device_ref(device); - return 0; - } - - assert_se(sysname = udev_device_get_sysname(device)); - - /* Wait until the device is initialized, so that we can get - * access to the ID_PATH property */ - - monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (!monitor) - return log_error_errno(errno, "Failed to acquire monitor: %m"); - - r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL); + r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname); if (r < 0) - return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m"); - - r = udev_monitor_enable_receiving(monitor); - if (r < 0) - return log_error_errno(r, "Failed to enable udev receiving: %m"); - - watch_fd = udev_monitor_get_fd(monitor); - if (watch_fd < 0) - return log_error_errno(watch_fd, "Failed to get watch fd: %m"); - - /* Check again, maybe things changed */ - d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname); - if (!d) - return log_full_errno(IN_SET(errno, ENOENT, ENXIO, ENODEV) ? LOG_DEBUG : LOG_ERR, errno, + return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r, "Failed to open device '%s': %m", sysname); - if (udev_device_get_is_initialized(d) != 0) { - *ret = d; - return 0; - } - - for (;;) { - _cleanup_(udev_device_unrefp) struct udev_device *t = NULL; - - r = fd_wait_for_event(watch_fd, POLLIN, EXIT_USEC); - if (r == -EINTR) - continue; - if (r < 0) - return log_error_errno(r, "Failed to watch udev monitor: %m"); - if (r == 0) { - log_error("Timed out waiting for udev monitor."); - return -ETIMEDOUT; - } + r = sd_device_get_sysattr_value(device, "name", &name); + if (r < 0) + return log_device_debug_errno(device, r, "Device has no name, ignoring: %m"); - t = udev_monitor_receive_device(monitor); - if (!t) - continue; + log_device_debug(device, "Operating on rfkill device '%s'.", name); - if (streq_ptr(udev_device_get_sysname(t), sysname)) { - *ret = udev_device_ref(t); - return 0; - } - } + *ret = TAKE_PTR(device); + return 0; } static int determine_state_file( - struct udev *udev, const struct rfkill_event *event, char **ret) { - _cleanup_(udev_device_unrefp) struct udev_device *d = NULL; - _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *d = NULL, *device = NULL; const char *path_id, *type; char *state_file; int r; @@ -176,18 +101,17 @@ static int determine_state_file( assert(event); assert(ret); - r = find_device(udev, event, &d); + r = find_device(event, &d); if (r < 0) return r; - r = wait_for_initialized(udev, d, &device); + r = device_wait_for_initialization(d, "rfkill", &device); if (r < 0) return r; assert_se(type = rfkill_type_to_string(event->type)); - path_id = udev_device_get_property_value(device, "ID_PATH"); - if (path_id) { + if (sd_device_get_property_value(device, "ID_PATH", &path_id) >= 0) { _cleanup_free_ char *escaped_path_id = NULL; escaped_path_id = cescape(path_id); @@ -205,24 +129,20 @@ static int determine_state_file( return 0; } -static int load_state( - int rfkill_fd, - struct udev *udev, - const struct rfkill_event *event) { - +static int load_state(Context *c, const struct rfkill_event *event) { _cleanup_free_ char *state_file = NULL, *value = NULL; struct rfkill_event we; ssize_t l; int b, r; - assert(rfkill_fd >= 0); - assert(udev); + assert(c); + assert(c->rfkill_fd >= 0); assert(event); if (shall_restore_state() == 0) return 0; - r = determine_state_file(udev, event, &state_file); + r = determine_state_file(event, &state_file); if (r < 0) return r; @@ -250,53 +170,45 @@ static int load_state( .soft = b, }; - l = write(rfkill_fd, &we, sizeof(we)); + l = write(c->rfkill_fd, &we, sizeof(we)); if (l < 0) return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx); - if (l != sizeof(we)) { - log_error("Couldn't write rfkill event structure, too short."); - return -EIO; - } + if (l != sizeof(we)) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Couldn't write rfkill event structure, too short."); log_debug("Loaded state '%s' from %s.", one_zero(b), state_file); return 0; } -static void save_state_queue_remove( - struct write_queue_item **write_queue, - int idx, - char *state_file) { - +static void save_state_queue_remove(Context *c, int idx, const char *state_file) { struct write_queue_item *item, *tmp; - LIST_FOREACH_SAFE(queue, item, tmp, *write_queue) { + assert(c); + + LIST_FOREACH_SAFE(queue, item, tmp, c->write_queue) { if ((state_file && streq(item->file, state_file)) || idx == item->rfkill_idx) { log_debug("Canceled previous save state of '%s' to %s.", one_zero(item->state), item->file); - LIST_REMOVE(queue, *write_queue, item); + LIST_REMOVE(queue, c->write_queue, item); write_queue_item_free(item); } } } -static int save_state_queue( - struct write_queue_item **write_queue, - int rfkill_fd, - struct udev *udev, - const struct rfkill_event *event) { - +static int save_state_queue(Context *c, const struct rfkill_event *event) { _cleanup_free_ char *state_file = NULL; struct write_queue_item *item; int r; - assert(rfkill_fd >= 0); - assert(udev); + assert(c); + assert(c->rfkill_fd >= 0); assert(event); - r = determine_state_file(udev, event, &state_file); + r = determine_state_file(event, &state_file); if (r < 0) return r; - save_state_queue_remove(write_queue, event->idx, state_file); + save_state_queue_remove(c, event->idx, state_file); item = new0(struct write_queue_item, 1); if (!item) @@ -306,119 +218,90 @@ static int save_state_queue( item->rfkill_idx = event->idx; item->state = event->soft; - LIST_APPEND(queue, *write_queue, item); + LIST_APPEND(queue, c->write_queue, item); return 0; } -static int save_state_cancel( - struct write_queue_item **write_queue, - int rfkill_fd, - struct udev *udev, - const struct rfkill_event *event) { - +static int save_state_cancel(Context *c, const struct rfkill_event *event) { _cleanup_free_ char *state_file = NULL; int r; - assert(rfkill_fd >= 0); - assert(udev); + assert(c); + assert(c->rfkill_fd >= 0); assert(event); - r = determine_state_file(udev, event, &state_file); - save_state_queue_remove(write_queue, event->idx, state_file); + r = determine_state_file(event, &state_file); + save_state_queue_remove(c, event->idx, state_file); if (r < 0) return r; return 0; } -static int save_state_write(struct write_queue_item **write_queue) { - struct write_queue_item *item, *tmp; - int result = 0; - bool error_logged = false; +static int save_state_write_one(struct write_queue_item *item) { int r; - LIST_FOREACH_SAFE(queue, item, tmp, *write_queue) { - r = write_string_file(item->file, one_zero(item->state), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); - if (r < 0) { - result = r; - if (!error_logged) { - log_error_errno(r, "Failed to write state file %s: %m", item->file); - error_logged = true; - } else - log_warning_errno(r, "Failed to write state file %s: %m", item->file); - } else - log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file); - - LIST_REMOVE(queue, *write_queue, item); - write_queue_item_free(item); + r = write_string_file(item->file, one_zero(item->state), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + if (r < 0) + return log_error_errno(r, "Failed to write state file %s: %m", item->file); + + log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file); + return 0; +} + +static void context_save_and_clear(Context *c) { + struct write_queue_item *i; + + assert(c); + + while ((i = c->write_queue)) { + LIST_REMOVE(queue, c->write_queue, i); + (void) save_state_write_one(i); + write_queue_item_free(i); } - return result; + + safe_close(c->rfkill_fd); } -int main(int argc, char *argv[]) { - LIST_HEAD(write_queue_item, write_queue); - _cleanup_(udev_unrefp) struct udev *udev = NULL; - _cleanup_close_ int rfkill_fd = -1; +static int run(int argc, char *argv[]) { + _cleanup_(context_save_and_clear) Context c = { .rfkill_fd = -1 }; bool ready = false; int r, n; - if (argc > 1) { - log_error("This program requires no arguments."); - return EXIT_FAILURE; - } - - LIST_HEAD_INIT(write_queue); + if (argc > 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires no arguments."); - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); + log_setup_service(); umask(0022); - udev = udev_new(); - if (!udev) { - r = log_oom(); - goto finish; - } - r = mkdir_p("/var/lib/systemd/rfkill", 0755); - if (r < 0) { - log_error_errno(r, "Failed to create rfkill directory: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to create rfkill directory: %m"); n = sd_listen_fds(false); - if (n < 0) { - r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m"); - goto finish; - } - if (n > 1) { - log_error("Got too many file descriptors."); - r = -EINVAL; - goto finish; - } + if (n < 0) + return log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m"); + if (n > 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got too many file descriptors."); if (n == 0) { - rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); - if (rfkill_fd < 0) { + c.rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (c.rfkill_fd < 0) { if (errno == ENOENT) { log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting."); - r = 0; - goto finish; + return 0; } - r = log_error_errno(errno, "Failed to open /dev/rfkill: %m"); - goto finish; + return log_error_errno(errno, "Failed to open /dev/rfkill: %m"); } } else { - rfkill_fd = SD_LISTEN_FDS_START; + c.rfkill_fd = SD_LISTEN_FDS_START; - r = fd_nonblock(rfkill_fd, 1); - if (r < 0) { - log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m"); - goto finish; - } + r = fd_nonblock(c.rfkill_fd, 1); + if (r < 0) + return log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m"); } for (;;) { @@ -426,7 +309,7 @@ int main(int argc, char *argv[]) { const char *type; ssize_t l; - l = read(rfkill_fd, &event, sizeof(event)); + l = read(c.rfkill_fd, &event, sizeof(event)); if (l < 0) { if (errno == EAGAIN) { @@ -441,13 +324,11 @@ int main(int argc, char *argv[]) { /* Hang around for a bit, maybe there's more coming */ - r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC); + r = fd_wait_for_event(c.rfkill_fd, POLLIN, EXIT_USEC); if (r == -EINTR) continue; - if (r < 0) { - log_error_errno(r, "Failed to poll() on device: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to poll() on device: %m"); if (r > 0) continue; @@ -458,11 +339,8 @@ int main(int argc, char *argv[]) { log_error_errno(errno, "Failed to read from /dev/rfkill: %m"); } - if (l != RFKILL_EVENT_SIZE_V1) { - log_error("Read event structure of invalid size."); - r = -EIO; - goto finish; - } + if (l != RFKILL_EVENT_SIZE_V1) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Read event structure of invalid size."); type = rfkill_type_to_string(event.type); if (!type) { @@ -474,17 +352,17 @@ int main(int argc, char *argv[]) { case RFKILL_OP_ADD: log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type); - (void) load_state(rfkill_fd, udev, &event); + (void) load_state(&c, &event); break; case RFKILL_OP_DEL: log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type); - (void) save_state_cancel(&write_queue, rfkill_fd, udev, &event); + (void) save_state_cancel(&c, &event); break; case RFKILL_OP_CHANGE: log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type); - (void) save_state_queue(&write_queue, rfkill_fd, udev, &event); + (void) save_state_queue(&c, &event); break; default: @@ -493,10 +371,7 @@ int main(int argc, char *argv[]) { } } - r = 0; - -finish: - (void) save_state_write(&write_queue); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return 0; } + +DEFINE_MAIN_FUNCTION(run); |