]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/rfkill/rfkill.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <linux/rfkill.h>
9 #include "alloc-util.h"
10 #include "device-util.h"
16 #include "parse-util.h"
17 #include "proc-cmdline.h"
18 #include "string-table.h"
19 #include "string-util.h"
23 /* Note that any write is delayed until exit and the rfkill state will not be
24 * stored for rfkill indices that disappear after a change. */
25 #define EXIT_USEC (5 * USEC_PER_SEC)
27 typedef struct write_queue_item
{
28 LIST_FIELDS(struct write_queue_item
, queue
);
34 static struct write_queue_item
* write_queue_item_free(struct write_queue_item
*item
) {
42 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
43 [RFKILL_TYPE_ALL
] = "all",
44 [RFKILL_TYPE_WLAN
] = "wlan",
45 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
46 [RFKILL_TYPE_UWB
] = "uwb",
47 [RFKILL_TYPE_WIMAX
] = "wimax",
48 [RFKILL_TYPE_WWAN
] = "wwan",
49 [RFKILL_TYPE_GPS
] = "gps",
50 [RFKILL_TYPE_FM
] = "fm",
51 [RFKILL_TYPE_NFC
] = "nfc",
54 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
56 static int find_device(
57 const struct rfkill_event
*event
,
59 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
60 _cleanup_free_
char *sysname
= NULL
;
67 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
70 r
= sd_device_new_from_subsystem_sysname(&device
, "rfkill", sysname
);
72 return log_full_errno(IN_SET(r
, -ENOENT
, -ENXIO
, -ENODEV
) ? LOG_DEBUG
: LOG_ERR
, r
,
73 "Failed to open device '%s': %m", sysname
);
75 r
= sd_device_get_sysattr_value(device
, "name", &name
);
77 return log_device_debug_errno(device
, r
, "Device has no name, ignoring: %m");
79 log_device_debug(device
, "Operating on rfkill device '%s'.", name
);
81 *ret
= TAKE_PTR(device
);
85 struct DeviceMonitorData
{
90 static int device_monitor_handler(sd_device_monitor
*monitor
, sd_device
*device
, void *userdata
) {
91 struct DeviceMonitorData
*data
= userdata
;
96 assert(data
->sysname
);
98 if (sd_device_get_sysname(device
, &sysname
) >= 0 && streq(sysname
, data
->sysname
)) {
99 data
->device
= sd_device_ref(device
);
100 return sd_event_exit(sd_device_monitor_get_event(monitor
), 0);
106 static int wait_for_initialized(
110 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*monitor
= NULL
;
111 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
112 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
113 struct DeviceMonitorData data
= {};
119 if (sd_device_get_is_initialized(device
) > 0) {
120 *ret
= sd_device_ref(device
);
124 assert_se(sd_device_get_sysname(device
, &data
.sysname
) >= 0);
126 /* Wait until the device is initialized, so that we can get
127 * access to the ID_PATH property */
129 r
= sd_event_default(&event
);
131 return log_error_errno(r
, "Failed to get default event: %m");
133 r
= sd_device_monitor_new(&monitor
);
135 return log_error_errno(r
, "Failed to acquire monitor: %m");
137 r
= sd_device_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
139 return log_error_errno(r
, "Failed to add rfkill device match to monitor: %m");
141 r
= sd_device_monitor_attach_event(monitor
, event
);
143 return log_error_errno(r
, "Failed to attach event to device monitor: %m");
145 r
= sd_device_monitor_start(monitor
, device_monitor_handler
, &data
);
147 return log_error_errno(r
, "Failed to start device monitor: %m");
149 /* Check again, maybe things changed */
150 r
= sd_device_new_from_subsystem_sysname(&d
, "rfkill", data
.sysname
);
152 return log_full_errno(IN_SET(r
, -ENOENT
, -ENXIO
, -ENODEV
) ? LOG_DEBUG
: LOG_ERR
, r
,
153 "Failed to open device '%s': %m", data
.sysname
);
155 if (sd_device_get_is_initialized(d
) > 0) {
160 r
= sd_event_loop(event
);
162 return log_error_errno(r
, "Event loop failed: %m");
164 *ret
= TAKE_PTR(data
.device
);
168 static int determine_state_file(
169 const struct rfkill_event
*event
,
172 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
, *device
= NULL
;
173 const char *path_id
, *type
;
180 r
= find_device(event
, &d
);
184 r
= wait_for_initialized(d
, &device
);
188 assert_se(type
= rfkill_type_to_string(event
->type
));
190 if (sd_device_get_property_value(device
, "ID_PATH", &path_id
) >= 0) {
191 _cleanup_free_
char *escaped_path_id
= NULL
;
193 escaped_path_id
= cescape(path_id
);
194 if (!escaped_path_id
)
197 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
);
199 state_file
= strjoin("/var/lib/systemd/rfkill/", type
);
208 static int load_state(
210 const struct rfkill_event
*event
) {
212 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
213 struct rfkill_event we
;
217 assert(rfkill_fd
>= 0);
220 if (shall_restore_state() == 0)
223 r
= determine_state_file(event
, &state_file
);
227 r
= read_one_line_file(state_file
, &value
);
229 /* No state file? Then save the current state */
231 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
233 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
235 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
239 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
241 b
= parse_boolean(value
);
243 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
245 we
= (struct rfkill_event
) {
246 .op
= RFKILL_OP_CHANGE
,
251 l
= write(rfkill_fd
, &we
, sizeof(we
));
253 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
254 if (l
!= sizeof(we
)) {
255 log_error("Couldn't write rfkill event structure, too short.");
259 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
263 static void save_state_queue_remove(
264 struct write_queue_item
**write_queue
,
268 struct write_queue_item
*item
, *tmp
;
270 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
271 if ((state_file
&& streq(item
->file
, state_file
)) || idx
== item
->rfkill_idx
) {
272 log_debug("Canceled previous save state of '%s' to %s.", one_zero(item
->state
), item
->file
);
273 LIST_REMOVE(queue
, *write_queue
, item
);
274 write_queue_item_free(item
);
279 static int save_state_queue(
280 struct write_queue_item
**write_queue
,
282 const struct rfkill_event
*event
) {
284 _cleanup_free_
char *state_file
= NULL
;
285 struct write_queue_item
*item
;
288 assert(rfkill_fd
>= 0);
291 r
= determine_state_file(event
, &state_file
);
295 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
297 item
= new0(struct write_queue_item
, 1);
301 item
->file
= TAKE_PTR(state_file
);
302 item
->rfkill_idx
= event
->idx
;
303 item
->state
= event
->soft
;
305 LIST_APPEND(queue
, *write_queue
, item
);
310 static int save_state_cancel(
311 struct write_queue_item
**write_queue
,
313 const struct rfkill_event
*event
) {
315 _cleanup_free_
char *state_file
= NULL
;
318 assert(rfkill_fd
>= 0);
321 r
= determine_state_file(event
, &state_file
);
322 save_state_queue_remove(write_queue
, event
->idx
, state_file
);
329 static int save_state_write(struct write_queue_item
**write_queue
) {
330 struct write_queue_item
*item
, *tmp
;
332 bool error_logged
= false;
335 LIST_FOREACH_SAFE(queue
, item
, tmp
, *write_queue
) {
336 r
= write_string_file(item
->file
, one_zero(item
->state
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
340 log_error_errno(r
, "Failed to write state file %s: %m", item
->file
);
343 log_warning_errno(r
, "Failed to write state file %s: %m", item
->file
);
345 log_debug("Saved state '%s' to %s.", one_zero(item
->state
), item
->file
);
347 LIST_REMOVE(queue
, *write_queue
, item
);
348 write_queue_item_free(item
);
353 int main(int argc
, char *argv
[]) {
354 LIST_HEAD(write_queue_item
, write_queue
);
355 _cleanup_close_
int rfkill_fd
= -1;
360 log_error("This program requires no arguments.");
364 LIST_HEAD_INIT(write_queue
);
366 log_set_target(LOG_TARGET_AUTO
);
367 log_parse_environment();
372 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
374 log_error_errno(r
, "Failed to create rfkill directory: %m");
378 n
= sd_listen_fds(false);
380 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
384 log_error("Got too many file descriptors.");
390 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
392 if (errno
== ENOENT
) {
393 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
398 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
402 rfkill_fd
= SD_LISTEN_FDS_START
;
404 r
= fd_nonblock(rfkill_fd
, 1);
406 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
412 struct rfkill_event event
;
416 l
= read(rfkill_fd
, &event
, sizeof(event
));
418 if (errno
== EAGAIN
) {
421 /* Notify manager that we are
423 * processing whatever was
425 (void) sd_notify(false, "READY=1");
429 /* Hang around for a bit, maybe there's more coming */
431 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
435 log_error_errno(r
, "Failed to poll() on device: %m");
441 log_debug("All events read and idle, exiting.");
445 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
448 if (l
!= RFKILL_EVENT_SIZE_V1
) {
449 log_error("Read event structure of invalid size.");
454 type
= rfkill_type_to_string(event
.type
);
456 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
463 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
464 (void) load_state(rfkill_fd
, &event
);
468 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
469 (void) save_state_cancel(&write_queue
, rfkill_fd
, &event
);
472 case RFKILL_OP_CHANGE
:
473 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
474 (void) save_state_queue(&write_queue
, rfkill_fd
, &event
);
478 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
486 (void) save_state_write(&write_queue
);
488 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;