1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/rfkill.h>
25 #include "sd-daemon.h"
27 #include "alloc-util.h"
33 #include "parse-util.h"
34 #include "proc-cmdline.h"
35 #include "string-table.h"
36 #include "string-util.h"
37 #include "udev-util.h"
41 /* Note that any write is delayed until exit and the rfkill state will not be
42 * stored for rfkill indices that disappear after a change. */
43 #define EXIT_USEC (5 * USEC_PER_SEC)
45 typedef struct write_queue_item
{
46 LIST_FIELDS(struct write_queue_item
, queue
);
52 static void write_queue_item_free(struct write_queue_item
*item
)
60 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
61 [RFKILL_TYPE_ALL
] = "all",
62 [RFKILL_TYPE_WLAN
] = "wlan",
63 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
64 [RFKILL_TYPE_UWB
] = "uwb",
65 [RFKILL_TYPE_WIMAX
] = "wimax",
66 [RFKILL_TYPE_WWAN
] = "wwan",
67 [RFKILL_TYPE_GPS
] = "gps",
68 [RFKILL_TYPE_FM
] = "fm",
69 [RFKILL_TYPE_NFC
] = "nfc",
72 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
74 static int find_device(
76 const struct rfkill_event
*event
,
77 struct udev_device
**ret
) {
79 _cleanup_free_
char *sysname
= NULL
;
80 struct udev_device
*device
;
87 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
90 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
92 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
93 "Failed to open device %s: %m", sysname
);
95 name
= udev_device_get_sysattr_value(device
, "name");
97 log_debug("Device has no name, ignoring.");
98 udev_device_unref(device
);
102 log_debug("Operating on rfkill device '%s'.", name
);
108 static int wait_for_initialized(
110 struct udev_device
*device
,
111 struct udev_device
**ret
) {
113 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
114 struct udev_device
*d
;
122 if (udev_device_get_is_initialized(device
) != 0) {
123 *ret
= udev_device_ref(device
);
127 assert_se(sysname
= udev_device_get_sysname(device
));
129 /* Wait until the device is initialized, so that we can get
130 * access to the ID_PATH property */
132 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
134 return log_error_errno(errno
, "Failed to acquire monitor: %m");
136 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
138 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
140 r
= udev_monitor_enable_receiving(monitor
);
142 return log_error_errno(r
, "Failed to enable udev receiving: %m");
144 watch_fd
= udev_monitor_get_fd(monitor
);
146 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
148 /* Check again, maybe things changed */
149 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
151 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
152 "Failed to open device %s: %m", sysname
);
154 if (udev_device_get_is_initialized(d
) != 0) {
160 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
162 r
= fd_wait_for_event(watch_fd
, POLLIN
, EXIT_USEC
);
166 return log_error_errno(r
, "Failed to watch udev monitor: %m");
168 log_error("Timed out waiting for udev monitor.");
172 t
= udev_monitor_receive_device(monitor
);
176 if (streq_ptr(udev_device_get_sysname(t
), sysname
)) {
177 *ret
= udev_device_ref(t
);
183 static int determine_state_file(
185 const struct rfkill_event
*event
,
188 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
189 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
190 const char *path_id
, *type
;
197 r
= find_device(udev
, event
, &d
);
201 r
= wait_for_initialized(udev
, d
, &device
);
205 assert_se(type
= rfkill_type_to_string(event
->type
));
207 path_id
= udev_device_get_property_value(device
, "ID_PATH");
209 _cleanup_free_
char *escaped_path_id
= NULL
;
211 escaped_path_id
= cescape(path_id
);
212 if (!escaped_path_id
)
215 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
);
217 state_file
= strjoin("/var/lib/systemd/rfkill/", type
);
226 static int load_state(
229 const struct rfkill_event
*event
) {
231 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
232 struct rfkill_event we
;
236 assert(rfkill_fd
>= 0);
240 if (shall_restore_state() == 0)
243 r
= determine_state_file(udev
, event
, &state_file
);
247 r
= read_one_line_file(state_file
, &value
);
249 /* No state file? Then save the current state */
251 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
253 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
255 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
259 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
261 b
= parse_boolean(value
);
263 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
265 we
= (struct rfkill_event
) {
266 .op
= RFKILL_OP_CHANGE
,
271 l
= write(rfkill_fd
, &we
, sizeof(we
));
273 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
274 if (l
!= sizeof(we
)) {
275 log_error("Couldn't write rfkill event structure, too short.");
279 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
283 static void save_state_queue_remove(
284 struct write_queue_item
**write_queue
,
288 struct write_queue_item
*item
, *tmp
;
290 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
291 if ((state_file
&& streq(item
->file
, state_file
)) || idx
== item
->rfkill_idx
) {
292 log_debug("Canceled previous save state of '%s' to %s.", one_zero(item
->state
), item
->file
);
293 LIST_REMOVE(queue
, *write_queue
, item
);
294 write_queue_item_free(item
);
299 static int save_state_queue(
300 struct write_queue_item
**write_queue
,
303 const struct rfkill_event
*event
) {
305 _cleanup_free_
char *state_file
= NULL
;
306 struct write_queue_item
*item
;
309 assert(rfkill_fd
>= 0);
313 r
= determine_state_file(udev
, event
, &state_file
);
316 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
318 item
= new0(struct write_queue_item
, 1);
322 item
->file
= state_file
;
323 item
->rfkill_idx
= event
->idx
;
324 item
->state
= event
->soft
;
327 LIST_APPEND(queue
, *write_queue
, item
);
332 static int save_state_cancel(
333 struct write_queue_item
**write_queue
,
336 const struct rfkill_event
*event
) {
338 _cleanup_free_
char *state_file
= NULL
;
341 assert(rfkill_fd
>= 0);
345 r
= determine_state_file(udev
, event
, &state_file
);
346 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
353 static int save_state_write(struct write_queue_item
**write_queue
) {
354 struct write_queue_item
*item
, *tmp
;
356 bool error_logged
= false;
359 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
360 r
= write_string_file(item
->file
, one_zero(item
->state
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
364 log_error_errno(r
, "Failed to write state file %s: %m", item
->file
);
367 log_warning_errno(r
, "Failed to write state file %s: %m", item
->file
);
369 log_debug("Saved state '%s' to %s.", one_zero(item
->state
), item
->file
);
371 LIST_REMOVE(queue
, *write_queue
, item
);
372 write_queue_item_free(item
);
377 int main(int argc
, char *argv
[]) {
378 LIST_HEAD(write_queue_item
, write_queue
);
379 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
380 _cleanup_close_
int rfkill_fd
= -1;
385 log_error("This program requires no arguments.");
389 LIST_HEAD_INIT(write_queue
);
391 log_set_target(LOG_TARGET_AUTO
);
392 log_parse_environment();
403 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
405 log_error_errno(r
, "Failed to create rfkill directory: %m");
409 n
= sd_listen_fds(false);
411 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
415 log_error("Got too many file descriptors.");
421 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
423 if (errno
== ENOENT
) {
424 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
429 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
433 rfkill_fd
= SD_LISTEN_FDS_START
;
435 r
= fd_nonblock(rfkill_fd
, 1);
437 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
443 struct rfkill_event event
;
447 l
= read(rfkill_fd
, &event
, sizeof(event
));
449 if (errno
== EAGAIN
) {
452 /* Notify manager that we are
454 * processing whatever was
456 (void) sd_notify(false, "READY=1");
460 /* Hang around for a bit, maybe there's more coming */
462 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
466 log_error_errno(r
, "Failed to poll() on device: %m");
472 log_debug("All events read and idle, exiting.");
476 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
479 if (l
!= RFKILL_EVENT_SIZE_V1
) {
480 log_error("Read event structure of invalid size.");
485 type
= rfkill_type_to_string(event
.type
);
487 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
494 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
495 (void) load_state(rfkill_fd
, udev
, &event
);
499 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
500 (void) save_state_cancel(&write_queue
, rfkill_fd
, udev
, &event
);
503 case RFKILL_OP_CHANGE
:
504 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
505 (void) save_state_queue(&write_queue
, rfkill_fd
, udev
, &event
);
509 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
517 (void) save_state_write(&write_queue
);
519 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;