1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <fcntl.h>
4 #include <linux/rfkill.h>
5 #include <poll.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 
10 #include "sd-daemon.h"
11 #include "sd-device.h"
12 
13 #include "alloc-util.h"
14 #include "device-util.h"
15 #include "escape.h"
16 #include "fd-util.h"
17 #include "fileio.h"
18 #include "io-util.h"
19 #include "list.h"
20 #include "main-func.h"
21 #include "mkdir.h"
22 #include "parse-util.h"
23 #include "reboot-util.h"
24 #include "string-table.h"
25 #include "string-util.h"
26 #include "udev-util.h"
27 #include "util.h"
28 
29 /* Note that any write is delayed until exit and the rfkill state will not be
30  * stored for rfkill indices that disappear after a change. */
31 #define EXIT_USEC (5 * USEC_PER_SEC)
32 
33 typedef struct write_queue_item {
34         LIST_FIELDS(struct write_queue_item, queue);
35         int rfkill_idx;
36         char *file;
37         int state;
38 } write_queue_item;
39 
40 typedef struct Context {
41         LIST_HEAD(write_queue_item, write_queue);
42         int rfkill_fd;
43 } Context;
44 
write_queue_item_free(struct write_queue_item * item)45 static struct write_queue_item* write_queue_item_free(struct write_queue_item *item) {
46         if (!item)
47                 return NULL;
48 
49         free(item->file);
50         return mfree(item);
51 }
52 
53 static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
54         [RFKILL_TYPE_ALL] = "all",
55         [RFKILL_TYPE_WLAN] = "wlan",
56         [RFKILL_TYPE_BLUETOOTH] = "bluetooth",
57         [RFKILL_TYPE_UWB] = "uwb",
58         [RFKILL_TYPE_WIMAX] = "wimax",
59         [RFKILL_TYPE_WWAN] = "wwan",
60         [RFKILL_TYPE_GPS] = "gps",
61         [RFKILL_TYPE_FM] = "fm",
62         [RFKILL_TYPE_NFC] = "nfc",
63 };
64 
65 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
66 
find_device(const struct rfkill_event * event,sd_device ** ret)67 static int find_device(
68                 const struct rfkill_event *event,
69                 sd_device **ret) {
70         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
71         _cleanup_free_ char *sysname = NULL;
72         const char *name;
73         int r;
74 
75         assert(event);
76         assert(ret);
77 
78         if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
79                 return log_oom();
80 
81         r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname);
82         if (r < 0)
83                 return log_full_errno(ERRNO_IS_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_ERR, r,
84                                       "Failed to open device '%s': %m", sysname);
85 
86         r = sd_device_get_sysattr_value(device, "name", &name);
87         if (r < 0)
88                 return log_device_debug_errno(device, r, "Device has no name, ignoring: %m");
89 
90         log_device_debug(device, "Operating on rfkill device '%s'.", name);
91 
92         *ret = TAKE_PTR(device);
93         return 0;
94 }
95 
determine_state_file(const struct rfkill_event * event,char ** ret)96 static int determine_state_file(
97                 const struct rfkill_event *event,
98                 char **ret) {
99 
100         _cleanup_(sd_device_unrefp) sd_device *d = NULL, *device = NULL;
101         const char *path_id, *type;
102         char *state_file;
103         int r;
104 
105         assert(event);
106         assert(ret);
107 
108         r = find_device(event, &d);
109         if (r < 0)
110                 return r;
111 
112         r = device_wait_for_initialization(d, "rfkill", USEC_INFINITY, &device);
113         if (r < 0)
114                 return r;
115 
116         assert_se(type = rfkill_type_to_string(event->type));
117 
118         if (sd_device_get_property_value(device, "ID_PATH", &path_id) >= 0) {
119                 _cleanup_free_ char *escaped_path_id = NULL;
120 
121                 escaped_path_id = cescape(path_id);
122                 if (!escaped_path_id)
123                         return log_oom();
124 
125                 state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type);
126         } else
127                 state_file = strjoin("/var/lib/systemd/rfkill/", type);
128 
129         if (!state_file)
130                 return log_oom();
131 
132         *ret = state_file;
133         return 0;
134 }
135 
load_state(Context * c,const struct rfkill_event * event)136 static int load_state(Context *c, const struct rfkill_event *event) {
137         _cleanup_free_ char *state_file = NULL, *value = NULL;
138         int b, r;
139 
140         assert(c);
141         assert(c->rfkill_fd >= 0);
142         assert(event);
143 
144         if (shall_restore_state() == 0)
145                 return 0;
146 
147         r = determine_state_file(event, &state_file);
148         if (r < 0)
149                 return r;
150 
151         r = read_one_line_file(state_file, &value);
152         if (IN_SET(r, -ENOENT, 0)) {
153                 /* No state file or it's truncated? Then save the current state */
154 
155                 r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755);
156                 if (r < 0)
157                         return log_error_errno(r, "Failed to write state file %s: %m", state_file);
158 
159                 log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
160                 return 0;
161         }
162         if (r < 0)
163                 return log_error_errno(r, "Failed to read state file %s: %m", state_file);
164 
165         b = parse_boolean(value);
166         if (b < 0)
167                 return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
168 
169         struct rfkill_event we = {
170                 .idx = event->idx,
171                 .op = RFKILL_OP_CHANGE,
172                 .soft = b,
173         };
174         assert_cc(offsetof(struct rfkill_event, op) < RFKILL_EVENT_SIZE_V1);
175         assert_cc(offsetof(struct rfkill_event, soft) < RFKILL_EVENT_SIZE_V1);
176 
177         ssize_t l = write(c->rfkill_fd, &we, sizeof we);
178         if (l < 0)
179                 return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx);
180         if ((size_t)l < RFKILL_EVENT_SIZE_V1) /* l cannot be < 0 here. Cast to fix -Werror=sign-compare */
181                 return log_error_errno(SYNTHETIC_ERRNO(EIO),
182                                        "Couldn't write rfkill event structure, too short (wrote %zd of %zu bytes).",
183                                        l, sizeof we);
184         log_debug("Writing struct rfkill_event successful (%zd of %zu bytes).", l, sizeof we);
185 
186         log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
187         return 0;
188 }
189 
save_state_queue_remove(Context * c,int idx,const char * state_file)190 static void save_state_queue_remove(Context *c, int idx, const char *state_file) {
191         assert(c);
192 
193         LIST_FOREACH(queue, item, c->write_queue)
194                 if ((state_file && streq(item->file, state_file)) || idx == item->rfkill_idx) {
195                         log_debug("Canceled previous save state of '%s' to %s.", one_zero(item->state), item->file);
196                         LIST_REMOVE(queue, c->write_queue, item);
197                         write_queue_item_free(item);
198                 }
199 }
200 
save_state_queue(Context * c,const struct rfkill_event * event)201 static int save_state_queue(Context *c, const struct rfkill_event *event) {
202         _cleanup_free_ char *state_file = NULL;
203         struct write_queue_item *item;
204         int r;
205 
206         assert(c);
207         assert(c->rfkill_fd >= 0);
208         assert(event);
209 
210         r = determine_state_file(event, &state_file);
211         if (r < 0)
212                 return r;
213 
214         save_state_queue_remove(c, event->idx, state_file);
215 
216         item = new0(struct write_queue_item, 1);
217         if (!item)
218                 return -ENOMEM;
219 
220         item->file = TAKE_PTR(state_file);
221         item->rfkill_idx = event->idx;
222         item->state = event->soft;
223 
224         LIST_APPEND(queue, c->write_queue, item);
225 
226         return 0;
227 }
228 
save_state_cancel(Context * c,const struct rfkill_event * event)229 static int save_state_cancel(Context *c, const struct rfkill_event *event) {
230         _cleanup_free_ char *state_file = NULL;
231         int r;
232 
233         assert(c);
234         assert(c->rfkill_fd >= 0);
235         assert(event);
236 
237         r = determine_state_file(event, &state_file);
238         save_state_queue_remove(c, event->idx, state_file);
239         if (r < 0)
240                 return r;
241 
242         return 0;
243 }
244 
save_state_write_one(struct write_queue_item * item)245 static int save_state_write_one(struct write_queue_item *item) {
246         int r;
247 
248         r = write_string_file(item->file, one_zero(item->state), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755);
249         if (r < 0)
250                 return log_error_errno(r, "Failed to write state file %s: %m", item->file);
251 
252         log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
253         return 0;
254 }
255 
context_save_and_clear(Context * c)256 static void context_save_and_clear(Context *c) {
257         struct write_queue_item *i;
258 
259         assert(c);
260 
261         while ((i = c->write_queue)) {
262                 LIST_REMOVE(queue, c->write_queue, i);
263                 (void) save_state_write_one(i);
264                 write_queue_item_free(i);
265         }
266 
267         safe_close(c->rfkill_fd);
268 }
269 
run(int argc,char * argv[])270 static int run(int argc, char *argv[]) {
271         _cleanup_(context_save_and_clear) Context c = { .rfkill_fd = -1 };
272         bool ready = false;
273         int r, n;
274 
275         if (argc > 1)
276                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires no arguments.");
277 
278         log_setup();
279 
280         umask(0022);
281 
282         n = sd_listen_fds(false);
283         if (n < 0)
284                 return log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
285         if (n > 1)
286                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got too many file descriptors.");
287 
288         if (n == 0) {
289                 c.rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
290                 if (c.rfkill_fd < 0) {
291                         if (errno == ENOENT) {
292                                 log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
293                                 return 0;
294                         }
295 
296                         return log_error_errno(errno, "Failed to open /dev/rfkill: %m");
297                 }
298         } else {
299                 c.rfkill_fd = SD_LISTEN_FDS_START;
300 
301                 r = fd_nonblock(c.rfkill_fd, 1);
302                 if (r < 0)
303                         return log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
304         }
305 
306         for (;;) {
307                 struct rfkill_event event = {};
308 
309                 ssize_t l = read(c.rfkill_fd, &event, sizeof event);
310                 if (l < 0) {
311                         if (errno != EAGAIN)
312                                 return log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
313 
314                         if (!ready) {
315                                 /* Notify manager that we are now finished with processing whatever was
316                                  * queued */
317                                 r = sd_notify(false, "READY=1");
318                                 if (r < 0)
319                                         log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
320 
321                                 ready = true;
322                         }
323 
324                         /* Hang around for a bit, maybe there's more coming */
325 
326                         r = fd_wait_for_event(c.rfkill_fd, POLLIN, EXIT_USEC);
327                         if (r == -EINTR)
328                                 continue;
329                         if (r < 0)
330                                 return log_error_errno(r, "Failed to poll() on device: %m");
331                         if (r > 0)
332                                 continue;
333 
334                         log_debug("All events read and idle, exiting.");
335                         break;
336                 }
337 
338                 if ((size_t)l < RFKILL_EVENT_SIZE_V1) /* l cannot be < 0 here. Cast to fix -Werror=sign-compare */
339                         return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read of struct rfkill_event: (%zd < %zu)",
340                                                l, (size_t) RFKILL_EVENT_SIZE_V1); /* Casting necessary to make compiling with different kernel versions happy */
341                 log_debug("Reading struct rfkill_event: got %zd bytes.", l);
342 
343                 /* The event structure has more fields. We only care about the first few, so it's OK if we
344                  * don't read the full structure. */
345                 assert_cc(offsetof(struct rfkill_event, op) < RFKILL_EVENT_SIZE_V1);
346                 assert_cc(offsetof(struct rfkill_event, type) < RFKILL_EVENT_SIZE_V1);
347 
348                 const char *type = rfkill_type_to_string(event.type);
349                 if (!type) {
350                         log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
351                         continue;
352                 }
353 
354                 switch (event.op) {
355 
356                 case RFKILL_OP_ADD:
357                         log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type);
358                         (void) load_state(&c, &event);
359                         break;
360 
361                 case RFKILL_OP_DEL:
362                         log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
363                         (void) save_state_cancel(&c, &event);
364                         break;
365 
366                 case RFKILL_OP_CHANGE:
367                         log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type);
368                         (void) save_state_queue(&c, &event);
369                         break;
370 
371                 default:
372                         log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
373                         break;
374                 }
375         }
376 
377         return 0;
378 }
379 
380 DEFINE_MAIN_FUNCTION(run);
381