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