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"
31 #include "udev-util.h"
34 #define EXIT_USEC (5 * USEC_PER_SEC)
36 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
37 [RFKILL_TYPE_ALL
] = "all",
38 [RFKILL_TYPE_WLAN
] = "wlan",
39 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
40 [RFKILL_TYPE_UWB
] = "uwb",
41 [RFKILL_TYPE_WIMAX
] = "wimax",
42 [RFKILL_TYPE_WWAN
] = "wwan",
43 [RFKILL_TYPE_GPS
] = "gps",
44 [RFKILL_TYPE_FM
] = "fm",
45 [RFKILL_TYPE_NFC
] = "nfc",
48 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
50 static int find_device(
52 const struct rfkill_event
*event
,
53 struct udev_device
**ret
) {
55 _cleanup_free_
char *sysname
= NULL
;
56 struct udev_device
*device
;
63 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
66 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
68 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
70 name
= udev_device_get_sysattr_value(device
, "name");
72 log_debug("Device has no name, ignoring.");
73 udev_device_unref(device
);
77 log_debug("Operating on rfkill device '%s'.", name
);
83 static int wait_for_initialized(
85 struct udev_device
*device
,
86 struct udev_device
**ret
) {
88 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
89 struct udev_device
*d
;
97 if (udev_device_get_is_initialized(device
) != 0) {
98 *ret
= udev_device_ref(device
);
102 assert_se(sysname
= udev_device_get_sysname(device
));
104 /* Wait until the device is initialized, so that we can get
105 * access to the ID_PATH property */
107 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
109 return log_error_errno(errno
, "Failed to acquire monitor: %m");
111 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
113 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
115 r
= udev_monitor_enable_receiving(monitor
);
117 return log_error_errno(r
, "Failed to enable udev receiving: %m");
119 watch_fd
= udev_monitor_get_fd(monitor
);
121 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
123 /* Check again, maybe things changed */
124 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
126 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
128 if (udev_device_get_is_initialized(d
) != 0) {
134 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
136 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
140 return log_error_errno(r
, "Failed to watch udev monitor: %m");
142 t
= udev_monitor_receive_device(monitor
);
146 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
147 *ret
= udev_device_ref(t
);
153 static int determine_state_file(
155 const struct rfkill_event
*event
,
156 struct udev_device
*d
,
159 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
160 const char *path_id
, *type
;
168 r
= wait_for_initialized(udev
, d
, &device
);
172 assert_se(type
= rfkill_type_to_string(event
->type
));
174 path_id
= udev_device_get_property_value(device
, "ID_PATH");
176 _cleanup_free_
char *escaped_path_id
= NULL
;
178 escaped_path_id
= cescape(path_id
);
179 if (!escaped_path_id
)
182 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
184 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
193 static int load_state(
196 const struct rfkill_event
*event
) {
198 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
199 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
200 struct rfkill_event we
;
204 assert(rfkill_fd
>= 0);
208 if (!shall_restore_state())
211 r
= find_device(udev
, event
, &device
);
215 r
= determine_state_file(udev
, event
, device
, &state_file
);
219 r
= read_one_line_file(state_file
, &value
);
221 /* No state file? Then save the current state */
223 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
225 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
227 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
231 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
233 b
= parse_boolean(value
);
235 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
237 we
= (struct rfkill_event
) {
238 .op
= RFKILL_OP_CHANGE
,
243 l
= write(rfkill_fd
, &we
, sizeof(we
));
245 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
246 if (l
!= sizeof(we
)) {
247 log_error("Couldn't write rfkill event structure, too short.");
251 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
255 static int save_state(
258 const struct rfkill_event
*event
) {
260 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
261 _cleanup_free_
char *state_file
= NULL
;
264 assert(rfkill_fd
>= 0);
268 r
= find_device(udev
, event
, &device
);
272 r
= determine_state_file(udev
, event
, device
, &state_file
);
276 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
278 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
280 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
284 int main(int argc
, char *argv
[]) {
285 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
286 _cleanup_close_
int rfkill_fd
= -1;
291 log_error("This program requires no arguments.");
295 log_set_target(LOG_TARGET_AUTO
);
296 log_parse_environment();
307 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
309 log_error_errno(r
, "Failed to create rfkill directory: %m");
313 n
= sd_listen_fds(false);
315 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
319 log_error("Got too many file descriptors.");
325 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
327 if (errno
== ENOENT
) {
328 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
333 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
337 rfkill_fd
= SD_LISTEN_FDS_START
;
339 r
= fd_nonblock(rfkill_fd
, 1);
341 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
347 struct rfkill_event event
;
351 l
= read(rfkill_fd
, &event
, sizeof(event
));
353 if (errno
== EAGAIN
) {
356 /* Notify manager that we are
358 * processing whatever was
360 (void) sd_notify(false, "READY=1");
364 /* Hang around for a bit, maybe there's more coming */
366 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
370 log_error_errno(r
, "Failed to poll() on device: %m");
376 log_debug("All events read and idle, exiting.");
380 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
383 if (l
!= RFKILL_EVENT_SIZE_V1
) {
384 log_error("Read event structure of invalid size.");
389 type
= rfkill_type_to_string(event
.type
);
391 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
398 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
399 (void) load_state(rfkill_fd
, udev
, &event
);
403 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
406 case RFKILL_OP_CHANGE
:
407 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
408 (void) save_state(rfkill_fd
, udev
, &event
);
412 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
420 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;