1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #include <linux/rfkill.h>
26 #include "sd-daemon.h"
33 #include "parse-util.h"
34 #include "string-util.h"
35 #include "udev-util.h"
38 #define EXIT_USEC (5 * USEC_PER_SEC)
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",
52 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
54 static int find_device(
56 const struct rfkill_event
*event
,
57 struct udev_device
**ret
) {
59 _cleanup_free_
char *sysname
= NULL
;
60 struct udev_device
*device
;
67 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
70 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
72 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
74 name
= udev_device_get_sysattr_value(device
, "name");
76 log_debug("Device has no name, ignoring.");
77 udev_device_unref(device
);
81 log_debug("Operating on rfkill device '%s'.", name
);
87 static int wait_for_initialized(
89 struct udev_device
*device
,
90 struct udev_device
**ret
) {
92 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
93 struct udev_device
*d
;
101 if (udev_device_get_is_initialized(device
) != 0) {
102 *ret
= udev_device_ref(device
);
106 assert_se(sysname
= udev_device_get_sysname(device
));
108 /* Wait until the device is initialized, so that we can get
109 * access to the ID_PATH property */
111 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
113 return log_error_errno(errno
, "Failed to acquire monitor: %m");
115 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
117 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
119 r
= udev_monitor_enable_receiving(monitor
);
121 return log_error_errno(r
, "Failed to enable udev receiving: %m");
123 watch_fd
= udev_monitor_get_fd(monitor
);
125 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
127 /* Check again, maybe things changed */
128 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
130 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
132 if (udev_device_get_is_initialized(d
) != 0) {
138 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
140 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
144 return log_error_errno(r
, "Failed to watch udev monitor: %m");
146 t
= udev_monitor_receive_device(monitor
);
150 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
151 *ret
= udev_device_ref(t
);
157 static int determine_state_file(
159 const struct rfkill_event
*event
,
160 struct udev_device
*d
,
163 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
164 const char *path_id
, *type
;
172 r
= wait_for_initialized(udev
, d
, &device
);
176 assert_se(type
= rfkill_type_to_string(event
->type
));
178 path_id
= udev_device_get_property_value(device
, "ID_PATH");
180 _cleanup_free_
char *escaped_path_id
= NULL
;
182 escaped_path_id
= cescape(path_id
);
183 if (!escaped_path_id
)
186 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
188 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
197 static int load_state(
200 const struct rfkill_event
*event
) {
202 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
203 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
204 struct rfkill_event we
;
208 assert(rfkill_fd
>= 0);
212 if (!shall_restore_state())
215 r
= find_device(udev
, event
, &device
);
219 r
= determine_state_file(udev
, event
, device
, &state_file
);
223 r
= read_one_line_file(state_file
, &value
);
225 /* No state file? Then save the current state */
227 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
229 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
231 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
235 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
237 b
= parse_boolean(value
);
239 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
241 we
= (struct rfkill_event
) {
242 .op
= RFKILL_OP_CHANGE
,
247 l
= write(rfkill_fd
, &we
, sizeof(we
));
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.");
255 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
259 static int save_state(
262 const struct rfkill_event
*event
) {
264 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
265 _cleanup_free_
char *state_file
= NULL
;
268 assert(rfkill_fd
>= 0);
272 r
= find_device(udev
, event
, &device
);
276 r
= determine_state_file(udev
, event
, device
, &state_file
);
280 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
282 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
284 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
288 int main(int argc
, char *argv
[]) {
289 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
290 _cleanup_close_
int rfkill_fd
= -1;
295 log_error("This program requires no arguments.");
299 log_set_target(LOG_TARGET_AUTO
);
300 log_parse_environment();
311 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
313 log_error_errno(r
, "Failed to create rfkill directory: %m");
317 n
= sd_listen_fds(false);
319 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
323 log_error("Got too many file descriptors.");
329 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
331 if (errno
== ENOENT
) {
332 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
337 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
341 rfkill_fd
= SD_LISTEN_FDS_START
;
343 r
= fd_nonblock(rfkill_fd
, 1);
345 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
351 struct rfkill_event event
;
355 l
= read(rfkill_fd
, &event
, sizeof(event
));
357 if (errno
== EAGAIN
) {
360 /* Notify manager that we are
362 * processing whatever was
364 (void) sd_notify(false, "READY=1");
368 /* Hang around for a bit, maybe there's more coming */
370 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
374 log_error_errno(r
, "Failed to poll() on device: %m");
380 log_debug("All events read and idle, exiting.");
384 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
387 if (l
!= RFKILL_EVENT_SIZE_V1
) {
388 log_error("Read event structure of invalid size.");
393 type
= rfkill_type_to_string(event
.type
);
395 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
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
);
407 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
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
);
416 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
424 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;