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"
30 #include "udev-util.h"
33 #define EXIT_USEC (5 * USEC_PER_SEC)
35 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
36 [RFKILL_TYPE_ALL
] = "all",
37 [RFKILL_TYPE_WLAN
] = "wlan",
38 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
39 [RFKILL_TYPE_UWB
] = "uwb",
40 [RFKILL_TYPE_WIMAX
] = "wimax",
41 [RFKILL_TYPE_WWAN
] = "wwan",
42 [RFKILL_TYPE_GPS
] = "gps",
43 [RFKILL_TYPE_FM
] "fm",
44 [RFKILL_TYPE_NFC
] "nfc",
47 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
49 static int find_device(
51 const struct rfkill_event
*event
,
52 struct udev_device
**ret
) {
54 _cleanup_free_
char *sysname
= NULL
;
55 struct udev_device
*device
;
62 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
65 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
67 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
69 name
= udev_device_get_sysattr_value(device
, "name");
71 log_debug("Device has no name, ignoring.");
72 udev_device_unref(device
);
76 log_debug("Operating on rfkill device '%s'.", name
);
82 static int wait_for_initialized(
84 struct udev_device
*device
,
85 struct udev_device
**ret
) {
87 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
88 struct udev_device
*d
;
96 if (udev_device_get_is_initialized(device
) != 0) {
97 *ret
= udev_device_ref(device
);
101 assert_se(sysname
= udev_device_get_sysname(device
));
103 /* Wait until the device is initialized, so that we can get
104 * access to the ID_PATH property */
106 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
108 return log_error_errno(errno
, "Failed to acquire monitor: %m");
110 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
112 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
114 r
= udev_monitor_enable_receiving(monitor
);
116 return log_error_errno(r
, "Failed to enable udev receiving: %m");
118 watch_fd
= udev_monitor_get_fd(monitor
);
120 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
122 /* Check again, maybe things changed */
123 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
125 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
127 if (udev_device_get_is_initialized(d
) != 0) {
133 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
135 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
139 return log_error_errno(r
, "Failed to watch udev monitor: %m");
141 t
= udev_monitor_receive_device(monitor
);
145 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
146 *ret
= udev_device_ref(t
);
152 static int determine_state_file(
154 const struct rfkill_event
*event
,
155 struct udev_device
*d
,
158 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
159 const char *path_id
, *type
;
167 r
= wait_for_initialized(udev
, d
, &device
);
171 assert_se(type
= rfkill_type_to_string(event
->type
));
173 path_id
= udev_device_get_property_value(device
, "ID_PATH");
175 _cleanup_free_
char *escaped_path_id
= NULL
;
177 escaped_path_id
= cescape(path_id
);
178 if (!escaped_path_id
)
181 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
183 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
192 static int load_state(
195 const struct rfkill_event
*event
) {
197 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
198 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
199 struct rfkill_event we
;
203 assert(rfkill_fd
>= 0);
207 if (!shall_restore_state())
210 r
= find_device(udev
, event
, &device
);
214 r
= determine_state_file(udev
, event
, device
, &state_file
);
218 r
= read_one_line_file(state_file
, &value
);
220 /* No state file? Then save the current state */
222 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
224 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
226 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
230 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
232 b
= parse_boolean(value
);
234 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
236 we
= (struct rfkill_event
) {
237 .op
= RFKILL_OP_CHANGE
,
242 l
= write(rfkill_fd
, &we
, sizeof(we
));
244 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
245 if (l
!= sizeof(we
)) {
246 log_error("Couldn't write rfkill event structure, too short.");
250 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
254 static int save_state(
257 const struct rfkill_event
*event
) {
259 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
260 _cleanup_free_
char *state_file
= NULL
;
263 assert(rfkill_fd
>= 0);
267 r
= find_device(udev
, event
, &device
);
271 r
= determine_state_file(udev
, event
, device
, &state_file
);
275 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
277 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
279 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
283 int main(int argc
, char *argv
[]) {
284 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
285 _cleanup_close_
int rfkill_fd
= -1;
290 log_error("This program requires no arguments.");
294 log_set_target(LOG_TARGET_AUTO
);
295 log_parse_environment();
306 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
308 log_error_errno(r
, "Failed to create rfkill directory: %m");
312 n
= sd_listen_fds(false);
314 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
318 log_error("Got too many file descriptors.");
324 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
326 if (errno
== ENOENT
) {
327 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
332 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
336 rfkill_fd
= SD_LISTEN_FDS_START
;
338 r
= fd_nonblock(rfkill_fd
, 1);
340 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
346 struct rfkill_event event
;
350 l
= read(rfkill_fd
, &event
, sizeof(event
));
352 if (errno
== EAGAIN
) {
355 /* Notify manager that we are
357 * processing whatever was
359 (void) sd_notify(false, "READY=1");
363 /* Hang around for a bit, maybe there's more coming */
365 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
369 log_error_errno(r
, "Failed to poll() on device: %m");
375 log_debug("All events read and idle, exiting.");
379 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
382 if (l
!= RFKILL_EVENT_SIZE_V1
) {
383 log_error("Read event structure of invalid size.");
388 type
= rfkill_type_to_string(event
.type
);
390 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
397 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
398 (void) load_state(rfkill_fd
, udev
, &event
);
402 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
405 case RFKILL_OP_CHANGE
:
406 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
407 (void) save_state(rfkill_fd
, udev
, &event
);
411 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
419 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;