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