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 "string-util.h"
32 #include "udev-util.h"
35 #define EXIT_USEC (5 * USEC_PER_SEC)
37 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
38 [RFKILL_TYPE_ALL
] = "all",
39 [RFKILL_TYPE_WLAN
] = "wlan",
40 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
41 [RFKILL_TYPE_UWB
] = "uwb",
42 [RFKILL_TYPE_WIMAX
] = "wimax",
43 [RFKILL_TYPE_WWAN
] = "wwan",
44 [RFKILL_TYPE_GPS
] = "gps",
45 [RFKILL_TYPE_FM
] = "fm",
46 [RFKILL_TYPE_NFC
] = "nfc",
49 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
51 static int find_device(
53 const struct rfkill_event
*event
,
54 struct udev_device
**ret
) {
56 _cleanup_free_
char *sysname
= NULL
;
57 struct udev_device
*device
;
64 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
67 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
69 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
71 name
= udev_device_get_sysattr_value(device
, "name");
73 log_debug("Device has no name, ignoring.");
74 udev_device_unref(device
);
78 log_debug("Operating on rfkill device '%s'.", name
);
84 static int wait_for_initialized(
86 struct udev_device
*device
,
87 struct udev_device
**ret
) {
89 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
90 struct udev_device
*d
;
98 if (udev_device_get_is_initialized(device
) != 0) {
99 *ret
= udev_device_ref(device
);
103 assert_se(sysname
= udev_device_get_sysname(device
));
105 /* Wait until the device is initialized, so that we can get
106 * access to the ID_PATH property */
108 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
110 return log_error_errno(errno
, "Failed to acquire monitor: %m");
112 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
114 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
116 r
= udev_monitor_enable_receiving(monitor
);
118 return log_error_errno(r
, "Failed to enable udev receiving: %m");
120 watch_fd
= udev_monitor_get_fd(monitor
);
122 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
124 /* Check again, maybe things changed */
125 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
127 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
129 if (udev_device_get_is_initialized(d
) != 0) {
135 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
137 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
141 return log_error_errno(r
, "Failed to watch udev monitor: %m");
143 t
= udev_monitor_receive_device(monitor
);
147 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
148 *ret
= udev_device_ref(t
);
154 static int determine_state_file(
156 const struct rfkill_event
*event
,
157 struct udev_device
*d
,
160 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
161 const char *path_id
, *type
;
169 r
= wait_for_initialized(udev
, d
, &device
);
173 assert_se(type
= rfkill_type_to_string(event
->type
));
175 path_id
= udev_device_get_property_value(device
, "ID_PATH");
177 _cleanup_free_
char *escaped_path_id
= NULL
;
179 escaped_path_id
= cescape(path_id
);
180 if (!escaped_path_id
)
183 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
185 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
194 static int load_state(
197 const struct rfkill_event
*event
) {
199 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
200 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
201 struct rfkill_event we
;
205 assert(rfkill_fd
>= 0);
209 if (!shall_restore_state())
212 r
= find_device(udev
, event
, &device
);
216 r
= determine_state_file(udev
, event
, device
, &state_file
);
220 r
= read_one_line_file(state_file
, &value
);
222 /* No state file? Then save the current state */
224 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
226 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
228 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
232 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
234 b
= parse_boolean(value
);
236 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
238 we
= (struct rfkill_event
) {
239 .op
= RFKILL_OP_CHANGE
,
244 l
= write(rfkill_fd
, &we
, sizeof(we
));
246 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
247 if (l
!= sizeof(we
)) {
248 log_error("Couldn't write rfkill event structure, too short.");
252 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
256 static int save_state(
259 const struct rfkill_event
*event
) {
261 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
262 _cleanup_free_
char *state_file
= NULL
;
265 assert(rfkill_fd
>= 0);
269 r
= find_device(udev
, event
, &device
);
273 r
= determine_state_file(udev
, event
, device
, &state_file
);
277 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
279 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
281 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
285 int main(int argc
, char *argv
[]) {
286 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
287 _cleanup_close_
int rfkill_fd
= -1;
292 log_error("This program requires no arguments.");
296 log_set_target(LOG_TARGET_AUTO
);
297 log_parse_environment();
308 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
310 log_error_errno(r
, "Failed to create rfkill directory: %m");
314 n
= sd_listen_fds(false);
316 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
320 log_error("Got too many file descriptors.");
326 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
328 if (errno
== ENOENT
) {
329 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
334 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
338 rfkill_fd
= SD_LISTEN_FDS_START
;
340 r
= fd_nonblock(rfkill_fd
, 1);
342 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
348 struct rfkill_event event
;
352 l
= read(rfkill_fd
, &event
, sizeof(event
));
354 if (errno
== EAGAIN
) {
357 /* Notify manager that we are
359 * processing whatever was
361 (void) sd_notify(false, "READY=1");
365 /* Hang around for a bit, maybe there's more coming */
367 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
371 log_error_errno(r
, "Failed to poll() on device: %m");
377 log_debug("All events read and idle, exiting.");
381 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
384 if (l
!= RFKILL_EVENT_SIZE_V1
) {
385 log_error("Read event structure of invalid size.");
390 type
= rfkill_type_to_string(event
.type
);
392 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
399 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
400 (void) load_state(rfkill_fd
, udev
, &event
);
404 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
407 case RFKILL_OP_CHANGE
:
408 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
409 (void) save_state(rfkill_fd
, udev
, &event
);
413 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
421 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;