3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering/***
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering This file is part of systemd.
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering Copyright 2013 Lennart Poettering
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart 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
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
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/>.
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering***/
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include <linux/rfkill.h>
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include <poll.h>
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
b4bbcaa9c44260e88402cb8f9a5fb8ac7f35e123Thomas Hindoe Paaboel Andersen#include "libudev.h"
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include "sd-daemon.h"
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include "escape.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include "fileio.h"
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include "io-util.h"
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include "mkdir.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "parse-util.h"
4e731273edfe852a3eee2949cd20f49fd5b4f6d7Lennart Poettering#include "proc-cmdline.h"
8b43440b7ef4b81c69c31de7ff820dc07a780254Lennart Poettering#include "string-table.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering#include "udev-util.h"
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#include "util.h"
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering#define EXIT_USEC (5 * USEC_PER_SEC)
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_ALL] = "all",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_WLAN] = "wlan",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_BLUETOOTH] = "bluetooth",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_UWB] = "uwb",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_WIMAX] = "wimax",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_WWAN] = "wwan",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering [RFKILL_TYPE_GPS] = "gps",
ac9455efdd4b455acf1ead9eccd549ff662ccf81Thomas Hindoe Paaboel Andersen [RFKILL_TYPE_FM] = "fm",
ac9455efdd4b455acf1ead9eccd549ff662ccf81Thomas Hindoe Paaboel Andersen [RFKILL_TYPE_NFC] = "nfc",
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering};
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart PoetteringDEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic int find_device(
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev *udev,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const struct rfkill_event *event,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device **ret) {
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *sysname = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device *device;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const char *name;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(udev);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(ret);
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_oom();
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!device)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering name = udev_device_get_sysattr_value(device, "name");
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering if (!name) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Device has no name, ignoring.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering udev_device_unref(device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return -ENOENT;
4844262f25a3ff6bd23de05a0a6f84a8e2983d74Lennart Poettering }
4844262f25a3ff6bd23de05a0a6f84a8e2983d74Lennart Poettering
4844262f25a3ff6bd23de05a0a6f84a8e2983d74Lennart Poettering log_debug("Operating on rfkill device '%s'.", name);
4844262f25a3ff6bd23de05a0a6f84a8e2983d74Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering *ret = device;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering}
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic int wait_for_initialized(
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev *udev,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device *device,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device **ret) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device *d;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const char *sysname;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int watch_fd, r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(udev);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(ret);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (udev_device_get_is_initialized(device) != 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering *ret = udev_device_ref(device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert_se(sysname = udev_device_get_sysname(device));
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Wait until the device is initialized, so that we can get
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * access to the ID_PATH property */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering monitor = udev_monitor_new_from_netlink(udev, "udev");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!monitor)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(errno, "Failed to acquire monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = udev_monitor_enable_receiving(monitor);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to enable udev receiving: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering watch_fd = udev_monitor_get_fd(monitor);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (watch_fd < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(watch_fd, "Failed to get watch fd: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Check again, maybe things changed */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!d)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (udev_device_get_is_initialized(d) != 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering *ret = d;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering for (;;) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *t = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r == -EINTR)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering continue;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to watch udev monitor: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering t = udev_monitor_receive_device(monitor);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!t)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering continue;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (streq_ptr(udev_device_get_sysname(device), sysname)) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering *ret = udev_device_ref(t);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering}
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic int determine_state_file(
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev *udev,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const struct rfkill_event *event,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev_device *d,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering char **ret) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const char *path_id, *type;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering char *state_file;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(d);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(ret);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = wait_for_initialized(udev, d, &device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert_se(type = rfkill_type_to_string(event->type));
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering path_id = udev_device_get_property_value(device, "ID_PATH");
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering if (path_id) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *escaped_path_id = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering escaped_path_id = cescape(path_id);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!escaped_path_id)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_oom();
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type, NULL);
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering } else
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering state_file = strjoin("/var/lib/systemd/rfkill/", type, NULL);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!state_file)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_oom();
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering *ret = state_file;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering}
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic int load_state(
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int rfkill_fd,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev *udev,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const struct rfkill_event *event) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *state_file = NULL, *value = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct rfkill_event we;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering ssize_t l;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int b, r;
f6f738db7273f8a2092ac372852f37f2a34cea17Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(rfkill_fd >= 0);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(udev);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
934ae16baf543af03f3f521277d14524ca772d17Lennart Poettering if (shall_restore_state() == 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = find_device(udev, event, &device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = determine_state_file(udev, event, device, &state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = read_one_line_file(state_file, &value);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r == -ENOENT) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* No state file? Then save the current state */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to write state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to read state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering b = parse_boolean(value);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (b < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering we = (struct rfkill_event) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering .op = RFKILL_OP_CHANGE,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering .idx = event->idx,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering .soft = b,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering };
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering l = write(rfkill_fd, &we, sizeof(we));
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (l < 0)
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 return -EIO;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering}
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringstatic int save_state(
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int rfkill_fd,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct udev *udev,
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const struct rfkill_event *event) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_free_ char *state_file = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(rfkill_fd >= 0);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(udev);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering assert(event);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = find_device(udev, event, &device);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = determine_state_file(udev, event, device, &state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return log_error_errno(r, "Failed to write state file %s: %m", state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering}
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringint main(int argc, char *argv[]) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering _cleanup_close_ int rfkill_fd = -1;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering bool ready = false;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering int r, n;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (argc > 1) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("This program requires no arguments.");
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering return EXIT_FAILURE;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_set_target(LOG_TARGET_AUTO);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_parse_environment();
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_open();
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering umask(0022);
354806fb4632575fe2e399dd90ca607c9c127f3bBastien Nocera
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering udev = udev_new();
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!udev) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = log_oom();
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = mkdir_p("/var/lib/systemd/rfkill", 0755);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to create rfkill directory: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering n = sd_listen_fds(false);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (n < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (n > 1) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("Got too many file descriptors.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = -EINVAL;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (n == 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (rfkill_fd < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (errno == ENOENT) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering } else {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering rfkill_fd = SD_LISTEN_FDS_START;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = fd_nonblock(rfkill_fd, 1);
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering if (r < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering for (;;) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering struct rfkill_event event;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering const char *type;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering ssize_t l;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering l = read(rfkill_fd, &event, sizeof(event));
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (l < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (errno == EAGAIN) {
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!ready) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Notify manager that we are
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * now finished with
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * processing whatever was
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering * queued */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering (void) sd_notify(false, "READY=1");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering ready = true;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering /* Hang around for a bit, maybe there's more coming */
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r == -EINTR)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering continue;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r < 0) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(r, "Failed to poll() on device: %m");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (r > 0)
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering continue;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("All events read and idle, exiting.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering break;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (l != RFKILL_EVENT_SIZE_V1) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_error("Read event structure of invalid size.");
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = -EIO;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering goto finish;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering type = rfkill_type_to_string(event.type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering if (!type) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering continue;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering switch (event.op) {
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering case RFKILL_OP_ADD:
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 break;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering case RFKILL_OP_DEL:
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering break;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering case RFKILL_OP_CHANGE:
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 break;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering default:
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering break;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering }
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering r = 0;
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poetteringfinish:
d35c1bb1f4b90993124f817f6f54a933e3be5f6bLennart Poettering return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
3990f247652c3bd41e4ea074e6302277eb9c7aa3Lennart Poettering}