]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/rfkill/rfkill.c
330c4e8629b1ee2a8a73c3df0a1ae7196f4ddb7e
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
8 #include <linux/rfkill.h>
12 #include "sd-daemon.h"
14 #include "alloc-util.h"
20 #include "parse-util.h"
21 #include "proc-cmdline.h"
22 #include "string-table.h"
23 #include "string-util.h"
24 #include "udev-util.h"
28 /* Note that any write is delayed until exit and the rfkill state will not be
29 * stored for rfkill indices that disappear after a change. */
30 #define EXIT_USEC (5 * USEC_PER_SEC)
32 typedef struct write_queue_item
{
33 LIST_FIELDS(struct write_queue_item
, queue
);
39 static struct write_queue_item
* write_queue_item_free(struct write_queue_item
*item
) {
47 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
48 [RFKILL_TYPE_ALL
] = "all",
49 [RFKILL_TYPE_WLAN
] = "wlan",
50 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
51 [RFKILL_TYPE_UWB
] = "uwb",
52 [RFKILL_TYPE_WIMAX
] = "wimax",
53 [RFKILL_TYPE_WWAN
] = "wwan",
54 [RFKILL_TYPE_GPS
] = "gps",
55 [RFKILL_TYPE_FM
] = "fm",
56 [RFKILL_TYPE_NFC
] = "nfc",
59 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
61 static int find_device(
63 const struct rfkill_event
*event
,
64 struct udev_device
**ret
) {
66 _cleanup_free_
char *sysname
= NULL
;
67 struct udev_device
*device
;
74 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
77 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
79 return log_full_errno(IN_SET(errno
, ENOENT
, ENXIO
, ENODEV
) ? LOG_DEBUG
: LOG_ERR
, errno
,
80 "Failed to open device '%s': %m", sysname
);
82 name
= udev_device_get_sysattr_value(device
, "name");
84 log_debug("Device has no name, ignoring.");
85 udev_device_unref(device
);
89 log_debug("Operating on rfkill device '%s'.", name
);
95 static int wait_for_initialized(
97 struct udev_device
*device
,
98 struct udev_device
**ret
) {
100 _cleanup_(udev_monitor_unrefp
) struct udev_monitor
*monitor
= NULL
;
101 struct udev_device
*d
;
109 if (udev_device_get_is_initialized(device
) != 0) {
110 *ret
= udev_device_ref(device
);
114 assert_se(sysname
= udev_device_get_sysname(device
));
116 /* Wait until the device is initialized, so that we can get
117 * access to the ID_PATH property */
119 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
121 return log_error_errno(errno
, "Failed to acquire monitor: %m");
123 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
125 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
127 r
= udev_monitor_enable_receiving(monitor
);
129 return log_error_errno(r
, "Failed to enable udev receiving: %m");
131 watch_fd
= udev_monitor_get_fd(monitor
);
133 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
135 /* Check again, maybe things changed */
136 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
138 return log_full_errno(IN_SET(errno
, ENOENT
, ENXIO
, ENODEV
) ? LOG_DEBUG
: LOG_ERR
, errno
,
139 "Failed to open device '%s': %m", sysname
);
141 if (udev_device_get_is_initialized(d
) != 0) {
147 _cleanup_(udev_device_unrefp
) struct udev_device
*t
= NULL
;
149 r
= fd_wait_for_event(watch_fd
, POLLIN
, EXIT_USEC
);
153 return log_error_errno(r
, "Failed to watch udev monitor: %m");
155 log_error("Timed out waiting for udev monitor.");
159 t
= udev_monitor_receive_device(monitor
);
163 if (streq_ptr(udev_device_get_sysname(t
), sysname
)) {
164 *ret
= udev_device_ref(t
);
170 static int determine_state_file(
172 const struct rfkill_event
*event
,
175 _cleanup_(udev_device_unrefp
) struct udev_device
*d
= NULL
;
176 _cleanup_(udev_device_unrefp
) struct udev_device
*device
= NULL
;
177 const char *path_id
, *type
;
184 r
= find_device(udev
, event
, &d
);
188 r
= wait_for_initialized(udev
, d
, &device
);
192 assert_se(type
= rfkill_type_to_string(event
->type
));
194 path_id
= udev_device_get_property_value(device
, "ID_PATH");
196 _cleanup_free_
char *escaped_path_id
= NULL
;
198 escaped_path_id
= cescape(path_id
);
199 if (!escaped_path_id
)
202 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
);
204 state_file
= strjoin("/var/lib/systemd/rfkill/", type
);
213 static int load_state(
216 const struct rfkill_event
*event
) {
218 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
219 struct rfkill_event we
;
223 assert(rfkill_fd
>= 0);
227 if (shall_restore_state() == 0)
230 r
= determine_state_file(udev
, event
, &state_file
);
234 r
= read_one_line_file(state_file
, &value
);
236 /* No state file? Then save the current state */
238 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
240 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
242 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
246 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
248 b
= parse_boolean(value
);
250 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
252 we
= (struct rfkill_event
) {
253 .op
= RFKILL_OP_CHANGE
,
258 l
= write(rfkill_fd
, &we
, sizeof(we
));
260 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
261 if (l
!= sizeof(we
)) {
262 log_error("Couldn't write rfkill event structure, too short.");
266 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
270 static void save_state_queue_remove(
271 struct write_queue_item
**write_queue
,
275 struct write_queue_item
*item
, *tmp
;
277 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
278 if ((state_file
&& streq(item
->file
, state_file
)) || idx
== item
->rfkill_idx
) {
279 log_debug("Canceled previous save state of '%s' to %s.", one_zero(item
->state
), item
->file
);
280 LIST_REMOVE(queue
, *write_queue
, item
);
281 write_queue_item_free(item
);
286 static int save_state_queue(
287 struct write_queue_item
**write_queue
,
290 const struct rfkill_event
*event
) {
292 _cleanup_free_
char *state_file
= NULL
;
293 struct write_queue_item
*item
;
296 assert(rfkill_fd
>= 0);
300 r
= determine_state_file(udev
, event
, &state_file
);
304 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
306 item
= new0(struct write_queue_item
, 1);
310 item
->file
= TAKE_PTR(state_file
);
311 item
->rfkill_idx
= event
->idx
;
312 item
->state
= event
->soft
;
314 LIST_APPEND(queue
, *write_queue
, item
);
319 static int save_state_cancel(
320 struct write_queue_item
**write_queue
,
323 const struct rfkill_event
*event
) {
325 _cleanup_free_
char *state_file
= NULL
;
328 assert(rfkill_fd
>= 0);
332 r
= determine_state_file(udev
, event
, &state_file
);
333 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
340 static int save_state_write(struct write_queue_item
**write_queue
) {
341 struct write_queue_item
*item
, *tmp
;
343 bool error_logged
= false;
346 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
347 r
= write_string_file(item
->file
, one_zero(item
->state
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
351 log_error_errno(r
, "Failed to write state file %s: %m", item
->file
);
354 log_warning_errno(r
, "Failed to write state file %s: %m", item
->file
);
356 log_debug("Saved state '%s' to %s.", one_zero(item
->state
), item
->file
);
358 LIST_REMOVE(queue
, *write_queue
, item
);
359 write_queue_item_free(item
);
364 int main(int argc
, char *argv
[]) {
365 LIST_HEAD(write_queue_item
, write_queue
);
366 _cleanup_(udev_unrefp
) struct udev
*udev
= NULL
;
367 _cleanup_close_
int rfkill_fd
= -1;
372 log_error("This program requires no arguments.");
376 LIST_HEAD_INIT(write_queue
);
378 log_set_target(LOG_TARGET_AUTO
);
379 log_parse_environment();
390 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
392 log_error_errno(r
, "Failed to create rfkill directory: %m");
396 n
= sd_listen_fds(false);
398 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
402 log_error("Got too many file descriptors.");
408 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
410 if (errno
== ENOENT
) {
411 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
416 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
420 rfkill_fd
= SD_LISTEN_FDS_START
;
422 r
= fd_nonblock(rfkill_fd
, 1);
424 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
430 struct rfkill_event event
;
434 l
= read(rfkill_fd
, &event
, sizeof(event
));
436 if (errno
== EAGAIN
) {
439 /* Notify manager that we are
441 * processing whatever was
443 (void) sd_notify(false, "READY=1");
447 /* Hang around for a bit, maybe there's more coming */
449 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
453 log_error_errno(r
, "Failed to poll() on device: %m");
459 log_debug("All events read and idle, exiting.");
463 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
466 if (l
!= RFKILL_EVENT_SIZE_V1
) {
467 log_error("Read event structure of invalid size.");
472 type
= rfkill_type_to_string(event
.type
);
474 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
481 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
482 (void) load_state(rfkill_fd
, udev
, &event
);
486 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
487 (void) save_state_cancel(&write_queue
, rfkill_fd
, udev
, &event
);
490 case RFKILL_OP_CHANGE
:
491 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
492 (void) save_state_queue(&write_queue
, rfkill_fd
, udev
, &event
);
496 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
504 (void) save_state_write(&write_queue
);
506 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;