]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/rfkill/rfkill.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / rfkill / rfkill.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <linux/rfkill.h>
22 #include <poll.h>
23
24 #include "libudev.h"
25 #include "sd-daemon.h"
26
27 #include "alloc-util.h"
28 #include "escape.h"
29 #include "fd-util.h"
30 #include "fileio.h"
31 #include "io-util.h"
32 #include "mkdir.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"
38 #include "util.h"
39 #include "list.h"
40
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)
44
45 typedef struct write_queue_item {
46 LIST_FIELDS(struct write_queue_item, queue);
47 int rfkill_idx;
48 char *file;
49 int state;
50 } write_queue_item;
51
52 static void write_queue_item_free(struct write_queue_item *item)
53 {
54 assert(item);
55
56 free(item->file);
57 free(item);
58 }
59
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",
70 };
71
72 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
73
74 static int find_device(
75 struct udev *udev,
76 const struct rfkill_event *event,
77 struct udev_device **ret) {
78
79 _cleanup_free_ char *sysname = NULL;
80 struct udev_device *device;
81 const char *name;
82
83 assert(udev);
84 assert(event);
85 assert(ret);
86
87 if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
88 return log_oom();
89
90 device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
91 if (!device)
92 return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
93 "Failed to open device %s: %m", sysname);
94
95 name = udev_device_get_sysattr_value(device, "name");
96 if (!name) {
97 log_debug("Device has no name, ignoring.");
98 udev_device_unref(device);
99 return -ENOENT;
100 }
101
102 log_debug("Operating on rfkill device '%s'.", name);
103
104 *ret = device;
105 return 0;
106 }
107
108 static int wait_for_initialized(
109 struct udev *udev,
110 struct udev_device *device,
111 struct udev_device **ret) {
112
113 _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
114 struct udev_device *d;
115 const char *sysname;
116 int watch_fd, r;
117
118 assert(udev);
119 assert(device);
120 assert(ret);
121
122 if (udev_device_get_is_initialized(device) != 0) {
123 *ret = udev_device_ref(device);
124 return 0;
125 }
126
127 assert_se(sysname = udev_device_get_sysname(device));
128
129 /* Wait until the device is initialized, so that we can get
130 * access to the ID_PATH property */
131
132 monitor = udev_monitor_new_from_netlink(udev, "udev");
133 if (!monitor)
134 return log_error_errno(errno, "Failed to acquire monitor: %m");
135
136 r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
137 if (r < 0)
138 return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m");
139
140 r = udev_monitor_enable_receiving(monitor);
141 if (r < 0)
142 return log_error_errno(r, "Failed to enable udev receiving: %m");
143
144 watch_fd = udev_monitor_get_fd(monitor);
145 if (watch_fd < 0)
146 return log_error_errno(watch_fd, "Failed to get watch fd: %m");
147
148 /* Check again, maybe things changed */
149 d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
150 if (!d)
151 return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
152 "Failed to open device %s: %m", sysname);
153
154 if (udev_device_get_is_initialized(d) != 0) {
155 *ret = d;
156 return 0;
157 }
158
159 for (;;) {
160 _cleanup_udev_device_unref_ struct udev_device *t = NULL;
161
162 r = fd_wait_for_event(watch_fd, POLLIN, EXIT_USEC);
163 if (r == -EINTR)
164 continue;
165 if (r < 0)
166 return log_error_errno(r, "Failed to watch udev monitor: %m");
167 if (r == 0) {
168 log_error("Timed out waiting for udev monitor.");
169 return -ETIMEDOUT;
170 }
171
172 t = udev_monitor_receive_device(monitor);
173 if (!t)
174 continue;
175
176 if (streq_ptr(udev_device_get_sysname(t), sysname)) {
177 *ret = udev_device_ref(t);
178 return 0;
179 }
180 }
181 }
182
183 static int determine_state_file(
184 struct udev *udev,
185 const struct rfkill_event *event,
186 char **ret) {
187
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;
191 char *state_file;
192 int r;
193
194 assert(event);
195 assert(ret);
196
197 r = find_device(udev, event, &d);
198 if (r < 0)
199 return r;
200
201 r = wait_for_initialized(udev, d, &device);
202 if (r < 0)
203 return r;
204
205 assert_se(type = rfkill_type_to_string(event->type));
206
207 path_id = udev_device_get_property_value(device, "ID_PATH");
208 if (path_id) {
209 _cleanup_free_ char *escaped_path_id = NULL;
210
211 escaped_path_id = cescape(path_id);
212 if (!escaped_path_id)
213 return log_oom();
214
215 state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type);
216 } else
217 state_file = strjoin("/var/lib/systemd/rfkill/", type);
218
219 if (!state_file)
220 return log_oom();
221
222 *ret = state_file;
223 return 0;
224 }
225
226 static int load_state(
227 int rfkill_fd,
228 struct udev *udev,
229 const struct rfkill_event *event) {
230
231 _cleanup_free_ char *state_file = NULL, *value = NULL;
232 struct rfkill_event we;
233 ssize_t l;
234 int b, r;
235
236 assert(rfkill_fd >= 0);
237 assert(udev);
238 assert(event);
239
240 if (shall_restore_state() == 0)
241 return 0;
242
243 r = determine_state_file(udev, event, &state_file);
244 if (r < 0)
245 return r;
246
247 r = read_one_line_file(state_file, &value);
248 if (r == -ENOENT) {
249 /* No state file? Then save the current state */
250
251 r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
252 if (r < 0)
253 return log_error_errno(r, "Failed to write state file %s: %m", state_file);
254
255 log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
256 return 0;
257 }
258 if (r < 0)
259 return log_error_errno(r, "Failed to read state file %s: %m", state_file);
260
261 b = parse_boolean(value);
262 if (b < 0)
263 return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
264
265 we = (struct rfkill_event) {
266 .op = RFKILL_OP_CHANGE,
267 .idx = event->idx,
268 .soft = b,
269 };
270
271 l = write(rfkill_fd, &we, sizeof(we));
272 if (l < 0)
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.");
276 return -EIO;
277 }
278
279 log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
280 return 0;
281 }
282
283 static void save_state_queue_remove(
284 struct write_queue_item **write_queue,
285 int idx,
286 char *state_file) {
287
288 struct write_queue_item *item, *tmp;
289
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);
295 }
296 }
297 }
298
299 static int save_state_queue(
300 struct write_queue_item **write_queue,
301 int rfkill_fd,
302 struct udev *udev,
303 const struct rfkill_event *event) {
304
305 _cleanup_free_ char *state_file = NULL;
306 struct write_queue_item *item;
307 int r;
308
309 assert(rfkill_fd >= 0);
310 assert(udev);
311 assert(event);
312
313 r = determine_state_file(udev, event, &state_file);
314 if (r < 0)
315 return r;
316 save_state_queue_remove(write_queue, event->idx, state_file);
317
318 item = new0(struct write_queue_item, 1);
319 if (!item)
320 return -ENOMEM;
321
322 item->file = state_file;
323 item->rfkill_idx = event->idx;
324 item->state = event->soft;
325 state_file = NULL;
326
327 LIST_APPEND(queue, *write_queue, item);
328
329 return 0;
330 }
331
332 static int save_state_cancel(
333 struct write_queue_item **write_queue,
334 int rfkill_fd,
335 struct udev *udev,
336 const struct rfkill_event *event) {
337
338 _cleanup_free_ char *state_file = NULL;
339 int r;
340
341 assert(rfkill_fd >= 0);
342 assert(udev);
343 assert(event);
344
345 r = determine_state_file(udev, event, &state_file);
346 save_state_queue_remove(write_queue, event->idx, state_file);
347 if (r < 0)
348 return r;
349
350 return 0;
351 }
352
353 static int save_state_write(struct write_queue_item **write_queue) {
354 struct write_queue_item *item, *tmp;
355 int result = 0;
356 bool error_logged = false;
357 int r;
358
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);
361 if (r < 0) {
362 result = r;
363 if (!error_logged) {
364 log_error_errno(r, "Failed to write state file %s: %m", item->file);
365 error_logged = true;
366 } else
367 log_warning_errno(r, "Failed to write state file %s: %m", item->file);
368 } else
369 log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
370
371 LIST_REMOVE(queue, *write_queue, item);
372 write_queue_item_free(item);
373 }
374 return result;
375 }
376
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;
381 bool ready = false;
382 int r, n;
383
384 if (argc > 1) {
385 log_error("This program requires no arguments.");
386 return EXIT_FAILURE;
387 }
388
389 LIST_HEAD_INIT(write_queue);
390
391 log_set_target(LOG_TARGET_AUTO);
392 log_parse_environment();
393 log_open();
394
395 umask(0022);
396
397 udev = udev_new();
398 if (!udev) {
399 r = log_oom();
400 goto finish;
401 }
402
403 r = mkdir_p("/var/lib/systemd/rfkill", 0755);
404 if (r < 0) {
405 log_error_errno(r, "Failed to create rfkill directory: %m");
406 goto finish;
407 }
408
409 n = sd_listen_fds(false);
410 if (n < 0) {
411 r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
412 goto finish;
413 }
414 if (n > 1) {
415 log_error("Got too many file descriptors.");
416 r = -EINVAL;
417 goto finish;
418 }
419
420 if (n == 0) {
421 rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
422 if (rfkill_fd < 0) {
423 if (errno == ENOENT) {
424 log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
425 r = 0;
426 goto finish;
427 }
428
429 r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
430 goto finish;
431 }
432 } else {
433 rfkill_fd = SD_LISTEN_FDS_START;
434
435 r = fd_nonblock(rfkill_fd, 1);
436 if (r < 0) {
437 log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
438 goto finish;
439 }
440 }
441
442 for (;;) {
443 struct rfkill_event event;
444 const char *type;
445 ssize_t l;
446
447 l = read(rfkill_fd, &event, sizeof(event));
448 if (l < 0) {
449 if (errno == EAGAIN) {
450
451 if (!ready) {
452 /* Notify manager that we are
453 * now finished with
454 * processing whatever was
455 * queued */
456 (void) sd_notify(false, "READY=1");
457 ready = true;
458 }
459
460 /* Hang around for a bit, maybe there's more coming */
461
462 r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
463 if (r == -EINTR)
464 continue;
465 if (r < 0) {
466 log_error_errno(r, "Failed to poll() on device: %m");
467 goto finish;
468 }
469 if (r > 0)
470 continue;
471
472 log_debug("All events read and idle, exiting.");
473 break;
474 }
475
476 log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
477 }
478
479 if (l != RFKILL_EVENT_SIZE_V1) {
480 log_error("Read event structure of invalid size.");
481 r = -EIO;
482 goto finish;
483 }
484
485 type = rfkill_type_to_string(event.type);
486 if (!type) {
487 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
488 continue;
489 }
490
491 switch (event.op) {
492
493 case RFKILL_OP_ADD:
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);
496 break;
497
498 case RFKILL_OP_DEL:
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);
501 break;
502
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);
506 break;
507
508 default:
509 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
510 break;
511 }
512 }
513
514 r = 0;
515
516 finish:
517 (void) save_state_write(&write_queue);
518
519 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
520 }