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"
32 #include "string-util.h"
33 #include "udev-util.h"
36 #define EXIT_USEC (5 * USEC_PER_SEC)
38 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
39 [RFKILL_TYPE_ALL
] = "all",
40 [RFKILL_TYPE_WLAN
] = "wlan",
41 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
42 [RFKILL_TYPE_UWB
] = "uwb",
43 [RFKILL_TYPE_WIMAX
] = "wimax",
44 [RFKILL_TYPE_WWAN
] = "wwan",
45 [RFKILL_TYPE_GPS
] = "gps",
46 [RFKILL_TYPE_FM
] = "fm",
47 [RFKILL_TYPE_NFC
] = "nfc",
50 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
52 static int find_device(
54 const struct rfkill_event
*event
,
55 struct udev_device
**ret
) {
57 _cleanup_free_
char *sysname
= NULL
;
58 struct udev_device
*device
;
65 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
68 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
70 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
72 name
= udev_device_get_sysattr_value(device
, "name");
74 log_debug("Device has no name, ignoring.");
75 udev_device_unref(device
);
79 log_debug("Operating on rfkill device '%s'.", name
);
85 static int wait_for_initialized(
87 struct udev_device
*device
,
88 struct udev_device
**ret
) {
90 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
91 struct udev_device
*d
;
99 if (udev_device_get_is_initialized(device
) != 0) {
100 *ret
= udev_device_ref(device
);
104 assert_se(sysname
= udev_device_get_sysname(device
));
106 /* Wait until the device is initialized, so that we can get
107 * access to the ID_PATH property */
109 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
111 return log_error_errno(errno
, "Failed to acquire monitor: %m");
113 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
115 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
117 r
= udev_monitor_enable_receiving(monitor
);
119 return log_error_errno(r
, "Failed to enable udev receiving: %m");
121 watch_fd
= udev_monitor_get_fd(monitor
);
123 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
125 /* Check again, maybe things changed */
126 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
128 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
130 if (udev_device_get_is_initialized(d
) != 0) {
136 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
138 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
142 return log_error_errno(r
, "Failed to watch udev monitor: %m");
144 t
= udev_monitor_receive_device(monitor
);
148 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
149 *ret
= udev_device_ref(t
);
155 static int determine_state_file(
157 const struct rfkill_event
*event
,
158 struct udev_device
*d
,
161 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
162 const char *path_id
, *type
;
170 r
= wait_for_initialized(udev
, d
, &device
);
174 assert_se(type
= rfkill_type_to_string(event
->type
));
176 path_id
= udev_device_get_property_value(device
, "ID_PATH");
178 _cleanup_free_
char *escaped_path_id
= NULL
;
180 escaped_path_id
= cescape(path_id
);
181 if (!escaped_path_id
)
184 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
186 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
195 static int load_state(
198 const struct rfkill_event
*event
) {
200 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
201 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
202 struct rfkill_event we
;
206 assert(rfkill_fd
>= 0);
210 if (!shall_restore_state())
213 r
= find_device(udev
, event
, &device
);
217 r
= determine_state_file(udev
, event
, device
, &state_file
);
221 r
= read_one_line_file(state_file
, &value
);
223 /* No state file? Then save the current state */
225 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
227 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
229 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
233 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
235 b
= parse_boolean(value
);
237 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
239 we
= (struct rfkill_event
) {
240 .op
= RFKILL_OP_CHANGE
,
245 l
= write(rfkill_fd
, &we
, sizeof(we
));
247 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
248 if (l
!= sizeof(we
)) {
249 log_error("Couldn't write rfkill event structure, too short.");
253 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
257 static int save_state(
260 const struct rfkill_event
*event
) {
262 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
263 _cleanup_free_
char *state_file
= NULL
;
266 assert(rfkill_fd
>= 0);
270 r
= find_device(udev
, event
, &device
);
274 r
= determine_state_file(udev
, event
, device
, &state_file
);
278 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
280 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
282 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
286 int main(int argc
, char *argv
[]) {
287 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
288 _cleanup_close_
int rfkill_fd
= -1;
293 log_error("This program requires no arguments.");
297 log_set_target(LOG_TARGET_AUTO
);
298 log_parse_environment();
309 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
311 log_error_errno(r
, "Failed to create rfkill directory: %m");
315 n
= sd_listen_fds(false);
317 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
321 log_error("Got too many file descriptors.");
327 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
329 if (errno
== ENOENT
) {
330 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
335 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
339 rfkill_fd
= SD_LISTEN_FDS_START
;
341 r
= fd_nonblock(rfkill_fd
, 1);
343 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
349 struct rfkill_event event
;
353 l
= read(rfkill_fd
, &event
, sizeof(event
));
355 if (errno
== EAGAIN
) {
358 /* Notify manager that we are
360 * processing whatever was
362 (void) sd_notify(false, "READY=1");
366 /* Hang around for a bit, maybe there's more coming */
368 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
372 log_error_errno(r
, "Failed to poll() on device: %m");
378 log_debug("All events read and idle, exiting.");
382 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
385 if (l
!= RFKILL_EVENT_SIZE_V1
) {
386 log_error("Read event structure of invalid size.");
391 type
= rfkill_type_to_string(event
.type
);
393 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
400 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
401 (void) load_state(rfkill_fd
, udev
, &event
);
405 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
408 case RFKILL_OP_CHANGE
:
409 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
410 (void) save_state(rfkill_fd
, udev
, &event
);
414 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
422 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;