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