]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/rfkill/rfkill.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / rfkill / rfkill.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <linux/rfkill.h>
4 #include <poll.h>
5
6 #include "sd-daemon.h"
7 #include "sd-device.h"
8
9 #include "alloc-util.h"
10 #include "device-util.h"
11 #include "escape.h"
12 #include "fd-util.h"
13 #include "fileio.h"
14 #include "io-util.h"
15 #include "mkdir.h"
16 #include "parse-util.h"
17 #include "proc-cmdline.h"
18 #include "string-table.h"
19 #include "string-util.h"
20 #include "util.h"
21 #include "list.h"
22
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)
26
27 typedef struct write_queue_item {
28 LIST_FIELDS(struct write_queue_item, queue);
29 int rfkill_idx;
30 char *file;
31 int state;
32 } write_queue_item;
33
34 static struct write_queue_item* write_queue_item_free(struct write_queue_item *item) {
35 if (!item)
36 return NULL;
37
38 free(item->file);
39 return mfree(item);
40 }
41
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",
52 };
53
54 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
55
56 static int find_device(
57 const struct rfkill_event *event,
58 sd_device **ret) {
59 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
60 _cleanup_free_ char *sysname = NULL;
61 const char *name;
62 int r;
63
64 assert(event);
65 assert(ret);
66
67 if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
68 return log_oom();
69
70 r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname);
71 if (r < 0)
72 return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r,
73 "Failed to open device '%s': %m", sysname);
74
75 r = sd_device_get_sysattr_value(device, "name", &name);
76 if (r < 0)
77 return log_device_debug_errno(device, r, "Device has no name, ignoring: %m");
78
79 log_device_debug(device, "Operating on rfkill device '%s'.", name);
80
81 *ret = TAKE_PTR(device);
82 return 0;
83 }
84
85 struct DeviceMonitorData {
86 const char *sysname;
87 sd_device *device;
88 };
89
90 static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
91 struct DeviceMonitorData *data = userdata;
92 const char *sysname;
93
94 assert(device);
95 assert(data);
96 assert(data->sysname);
97
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);
101 }
102
103 return 0;
104 }
105
106 static int wait_for_initialized(
107 sd_device *device,
108 sd_device **ret) {
109
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 = {};
114 int r;
115
116 assert(device);
117 assert(ret);
118
119 if (sd_device_get_is_initialized(device) > 0) {
120 *ret = sd_device_ref(device);
121 return 0;
122 }
123
124 assert_se(sd_device_get_sysname(device, &data.sysname) >= 0);
125
126 /* Wait until the device is initialized, so that we can get
127 * access to the ID_PATH property */
128
129 r = sd_event_default(&event);
130 if (r < 0)
131 return log_error_errno(r, "Failed to get default event: %m");
132
133 r = sd_device_monitor_new(&monitor);
134 if (r < 0)
135 return log_error_errno(r, "Failed to acquire monitor: %m");
136
137 r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
138 if (r < 0)
139 return log_error_errno(r, "Failed to add rfkill device match to monitor: %m");
140
141 r = sd_device_monitor_attach_event(monitor, event);
142 if (r < 0)
143 return log_error_errno(r, "Failed to attach event to device monitor: %m");
144
145 r = sd_device_monitor_start(monitor, device_monitor_handler, &data);
146 if (r < 0)
147 return log_error_errno(r, "Failed to start device monitor: %m");
148
149 /* Check again, maybe things changed */
150 r = sd_device_new_from_subsystem_sysname(&d, "rfkill", data.sysname);
151 if (r < 0)
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);
154
155 if (sd_device_get_is_initialized(d) > 0) {
156 *ret = TAKE_PTR(d);
157 return 0;
158 }
159
160 r = sd_event_loop(event);
161 if (r < 0)
162 return log_error_errno(r, "Event loop failed: %m");
163
164 *ret = TAKE_PTR(data.device);
165 return 0;
166 }
167
168 static int determine_state_file(
169 const struct rfkill_event *event,
170 char **ret) {
171
172 _cleanup_(sd_device_unrefp) sd_device *d = NULL, *device = NULL;
173 const char *path_id, *type;
174 char *state_file;
175 int r;
176
177 assert(event);
178 assert(ret);
179
180 r = find_device(event, &d);
181 if (r < 0)
182 return r;
183
184 r = wait_for_initialized(d, &device);
185 if (r < 0)
186 return r;
187
188 assert_se(type = rfkill_type_to_string(event->type));
189
190 if (sd_device_get_property_value(device, "ID_PATH", &path_id) >= 0) {
191 _cleanup_free_ char *escaped_path_id = NULL;
192
193 escaped_path_id = cescape(path_id);
194 if (!escaped_path_id)
195 return log_oom();
196
197 state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type);
198 } else
199 state_file = strjoin("/var/lib/systemd/rfkill/", type);
200
201 if (!state_file)
202 return log_oom();
203
204 *ret = state_file;
205 return 0;
206 }
207
208 static int load_state(
209 int rfkill_fd,
210 const struct rfkill_event *event) {
211
212 _cleanup_free_ char *state_file = NULL, *value = NULL;
213 struct rfkill_event we;
214 ssize_t l;
215 int b, r;
216
217 assert(rfkill_fd >= 0);
218 assert(event);
219
220 if (shall_restore_state() == 0)
221 return 0;
222
223 r = determine_state_file(event, &state_file);
224 if (r < 0)
225 return r;
226
227 r = read_one_line_file(state_file, &value);
228 if (r == -ENOENT) {
229 /* No state file? Then save the current state */
230
231 r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
232 if (r < 0)
233 return log_error_errno(r, "Failed to write state file %s: %m", state_file);
234
235 log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
236 return 0;
237 }
238 if (r < 0)
239 return log_error_errno(r, "Failed to read state file %s: %m", state_file);
240
241 b = parse_boolean(value);
242 if (b < 0)
243 return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
244
245 we = (struct rfkill_event) {
246 .op = RFKILL_OP_CHANGE,
247 .idx = event->idx,
248 .soft = b,
249 };
250
251 l = write(rfkill_fd, &we, sizeof(we));
252 if (l < 0)
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.");
256 return -EIO;
257 }
258
259 log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
260 return 0;
261 }
262
263 static void save_state_queue_remove(
264 struct write_queue_item **write_queue,
265 int idx,
266 char *state_file) {
267
268 struct write_queue_item *item, *tmp;
269
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);
275 }
276 }
277 }
278
279 static int save_state_queue(
280 struct write_queue_item **write_queue,
281 int rfkill_fd,
282 const struct rfkill_event *event) {
283
284 _cleanup_free_ char *state_file = NULL;
285 struct write_queue_item *item;
286 int r;
287
288 assert(rfkill_fd >= 0);
289 assert(event);
290
291 r = determine_state_file(event, &state_file);
292 if (r < 0)
293 return r;
294
295 save_state_queue_remove(write_queue, event->idx, state_file);
296
297 item = new0(struct write_queue_item, 1);
298 if (!item)
299 return -ENOMEM;
300
301 item->file = TAKE_PTR(state_file);
302 item->rfkill_idx = event->idx;
303 item->state = event->soft;
304
305 LIST_APPEND(queue, *write_queue, item);
306
307 return 0;
308 }
309
310 static int save_state_cancel(
311 struct write_queue_item **write_queue,
312 int rfkill_fd,
313 const struct rfkill_event *event) {
314
315 _cleanup_free_ char *state_file = NULL;
316 int r;
317
318 assert(rfkill_fd >= 0);
319 assert(event);
320
321 r = determine_state_file(event, &state_file);
322 save_state_queue_remove(write_queue, event->idx, state_file);
323 if (r < 0)
324 return r;
325
326 return 0;
327 }
328
329 static int save_state_write(struct write_queue_item **write_queue) {
330 struct write_queue_item *item, *tmp;
331 int result = 0;
332 bool error_logged = false;
333 int r;
334
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);
337 if (r < 0) {
338 result = r;
339 if (!error_logged) {
340 log_error_errno(r, "Failed to write state file %s: %m", item->file);
341 error_logged = true;
342 } else
343 log_warning_errno(r, "Failed to write state file %s: %m", item->file);
344 } else
345 log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
346
347 LIST_REMOVE(queue, *write_queue, item);
348 write_queue_item_free(item);
349 }
350 return result;
351 }
352
353 int main(int argc, char *argv[]) {
354 LIST_HEAD(write_queue_item, write_queue);
355 _cleanup_close_ int rfkill_fd = -1;
356 bool ready = false;
357 int r, n;
358
359 if (argc > 1) {
360 log_error("This program requires no arguments.");
361 return EXIT_FAILURE;
362 }
363
364 LIST_HEAD_INIT(write_queue);
365
366 log_set_target(LOG_TARGET_AUTO);
367 log_parse_environment();
368 log_open();
369
370 umask(0022);
371
372 r = mkdir_p("/var/lib/systemd/rfkill", 0755);
373 if (r < 0) {
374 log_error_errno(r, "Failed to create rfkill directory: %m");
375 goto finish;
376 }
377
378 n = sd_listen_fds(false);
379 if (n < 0) {
380 r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
381 goto finish;
382 }
383 if (n > 1) {
384 log_error("Got too many file descriptors.");
385 r = -EINVAL;
386 goto finish;
387 }
388
389 if (n == 0) {
390 rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
391 if (rfkill_fd < 0) {
392 if (errno == ENOENT) {
393 log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
394 r = 0;
395 goto finish;
396 }
397
398 r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
399 goto finish;
400 }
401 } else {
402 rfkill_fd = SD_LISTEN_FDS_START;
403
404 r = fd_nonblock(rfkill_fd, 1);
405 if (r < 0) {
406 log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
407 goto finish;
408 }
409 }
410
411 for (;;) {
412 struct rfkill_event event;
413 const char *type;
414 ssize_t l;
415
416 l = read(rfkill_fd, &event, sizeof(event));
417 if (l < 0) {
418 if (errno == EAGAIN) {
419
420 if (!ready) {
421 /* Notify manager that we are
422 * now finished with
423 * processing whatever was
424 * queued */
425 (void) sd_notify(false, "READY=1");
426 ready = true;
427 }
428
429 /* Hang around for a bit, maybe there's more coming */
430
431 r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
432 if (r == -EINTR)
433 continue;
434 if (r < 0) {
435 log_error_errno(r, "Failed to poll() on device: %m");
436 goto finish;
437 }
438 if (r > 0)
439 continue;
440
441 log_debug("All events read and idle, exiting.");
442 break;
443 }
444
445 log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
446 }
447
448 if (l != RFKILL_EVENT_SIZE_V1) {
449 log_error("Read event structure of invalid size.");
450 r = -EIO;
451 goto finish;
452 }
453
454 type = rfkill_type_to_string(event.type);
455 if (!type) {
456 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
457 continue;
458 }
459
460 switch (event.op) {
461
462 case RFKILL_OP_ADD:
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);
465 break;
466
467 case RFKILL_OP_DEL:
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);
470 break;
471
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);
475 break;
476
477 default:
478 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
479 break;
480 }
481 }
482
483 r = 0;
484
485 finish:
486 (void) save_state_write(&write_queue);
487
488 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
489 }