3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering This file is part of systemd.
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering Copyright 2013 Lennart Poettering
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering systemd is free software; you can redistribute it and/or modify it
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering under the terms of the GNU Lesser General Public License as published by
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering (at your option) any later version.
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering systemd is distributed in the hope that it will be useful, but
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering Lesser General Public License for more details.
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering You should have received a copy of the GNU Lesser General Public License
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart PoetteringDEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering name = udev_device_get_sysattr_value(device, "name");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Device has no name, ignoring.");
4844262f25a3ff6bd23de05a0a6f84a8e2983d74Lennart Poettering log_debug("Operating on rfkill device '%s'.", name);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (udev_device_get_is_initialized(device) != 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert_se(sysname = udev_device_get_sysname(device));
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Wait until the device is initialized, so that we can get
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * access to the ID_PATH property */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering monitor = udev_monitor_new_from_netlink(udev, "udev");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(errno, "Failed to acquire monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = udev_monitor_enable_receiving(monitor);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to enable udev receiving: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(watch_fd, "Failed to get watch fd: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Check again, maybe things changed */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (udev_device_get_is_initialized(d) != 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *t = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to watch udev monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering t = udev_monitor_receive_device(monitor);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (streq_ptr(udev_device_get_sysname(device), sysname)) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = wait_for_initialized(udev, d, &device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert_se(type = rfkill_type_to_string(event->type));
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering path_id = udev_device_get_property_value(device, "ID_PATH");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *escaped_path_id = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type, NULL);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering state_file = strjoin("/var/lib/systemd/rfkill/", type, NULL);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *state_file = NULL, *value = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = determine_state_file(udev, event, device, &state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = read_one_line_file(state_file, &value);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* No state file? Then save the current state */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to write state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to read state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (l != sizeof(we)) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("Couldn't write rfkill event structure, too short.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = determine_state_file(udev, event, device, &state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to write state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("This program requires no arguments.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = mkdir_p("/var/lib/systemd/rfkill", 0755);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to create rfkill directory: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("Got too many file descriptors.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering l = read(rfkill_fd, &event, sizeof(event));
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Notify manager that we are
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * now finished with
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * processing whatever was
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Hang around for a bit, maybe there's more coming */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to poll() on device: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("All events read and idle, exiting.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("Read event structure of invalid size.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering type = rfkill_type_to_string(event.type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering (void) load_state(rfkill_fd, udev, &event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering (void) save_state(rfkill_fd, udev, &event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);