summaryrefslogtreecommitdiff
path: root/src/rfkill/rfkill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rfkill/rfkill.c')
-rw-r--r--src/rfkill/rfkill.c321
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);