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 "string-util.h"
34 #include "udev-util.h"
37 #define EXIT_USEC (5 * USEC_PER_SEC)
39 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
40 [RFKILL_TYPE_ALL
] = "all",
41 [RFKILL_TYPE_WLAN
] = "wlan",
42 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
43 [RFKILL_TYPE_UWB
] = "uwb",
44 [RFKILL_TYPE_WIMAX
] = "wimax",
45 [RFKILL_TYPE_WWAN
] = "wwan",
46 [RFKILL_TYPE_GPS
] = "gps",
47 [RFKILL_TYPE_FM
] = "fm",
48 [RFKILL_TYPE_NFC
] = "nfc",
51 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
53 static int find_device(
55 const struct rfkill_event
*event
,
56 struct udev_device
**ret
) {
58 _cleanup_free_
char *sysname
= NULL
;
59 struct udev_device
*device
;
66 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
69 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
71 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
73 name
= udev_device_get_sysattr_value(device
, "name");
75 log_debug("Device has no name, ignoring.");
76 udev_device_unref(device
);
80 log_debug("Operating on rfkill device '%s'.", name
);
86 static int wait_for_initialized(
88 struct udev_device
*device
,
89 struct udev_device
**ret
) {
91 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
92 struct udev_device
*d
;
100 if (udev_device_get_is_initialized(device
) != 0) {
101 *ret
= udev_device_ref(device
);
105 assert_se(sysname
= udev_device_get_sysname(device
));
107 /* Wait until the device is initialized, so that we can get
108 * access to the ID_PATH property */
110 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
112 return log_error_errno(errno
, "Failed to acquire monitor: %m");
114 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
116 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
118 r
= udev_monitor_enable_receiving(monitor
);
120 return log_error_errno(r
, "Failed to enable udev receiving: %m");
122 watch_fd
= udev_monitor_get_fd(monitor
);
124 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
126 /* Check again, maybe things changed */
127 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
129 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
131 if (udev_device_get_is_initialized(d
) != 0) {
137 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
139 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
143 return log_error_errno(r
, "Failed to watch udev monitor: %m");
145 t
= udev_monitor_receive_device(monitor
);
149 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
150 *ret
= udev_device_ref(t
);
156 static int determine_state_file(
158 const struct rfkill_event
*event
,
159 struct udev_device
*d
,
162 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
163 const char *path_id
, *type
;
171 r
= wait_for_initialized(udev
, d
, &device
);
175 assert_se(type
= rfkill_type_to_string(event
->type
));
177 path_id
= udev_device_get_property_value(device
, "ID_PATH");
179 _cleanup_free_
char *escaped_path_id
= NULL
;
181 escaped_path_id
= cescape(path_id
);
182 if (!escaped_path_id
)
185 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
187 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
196 static int load_state(
199 const struct rfkill_event
*event
) {
201 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
202 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
203 struct rfkill_event we
;
207 assert(rfkill_fd
>= 0);
211 if (!shall_restore_state())
214 r
= find_device(udev
, event
, &device
);
218 r
= determine_state_file(udev
, event
, device
, &state_file
);
222 r
= read_one_line_file(state_file
, &value
);
224 /* No state file? Then save the current state */
226 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
228 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
230 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
234 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
236 b
= parse_boolean(value
);
238 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
240 we
= (struct rfkill_event
) {
241 .op
= RFKILL_OP_CHANGE
,
246 l
= write(rfkill_fd
, &we
, sizeof(we
));
248 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
249 if (l
!= sizeof(we
)) {
250 log_error("Couldn't write rfkill event structure, too short.");
254 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
258 static int save_state(
261 const struct rfkill_event
*event
) {
263 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
264 _cleanup_free_
char *state_file
= NULL
;
267 assert(rfkill_fd
>= 0);
271 r
= find_device(udev
, event
, &device
);
275 r
= determine_state_file(udev
, event
, device
, &state_file
);
279 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
281 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
283 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
287 int main(int argc
, char *argv
[]) {
288 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
289 _cleanup_close_
int rfkill_fd
= -1;
294 log_error("This program requires no arguments.");
298 log_set_target(LOG_TARGET_AUTO
);
299 log_parse_environment();
310 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
312 log_error_errno(r
, "Failed to create rfkill directory: %m");
316 n
= sd_listen_fds(false);
318 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
322 log_error("Got too many file descriptors.");
328 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
330 if (errno
== ENOENT
) {
331 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
336 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
340 rfkill_fd
= SD_LISTEN_FDS_START
;
342 r
= fd_nonblock(rfkill_fd
, 1);
344 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
350 struct rfkill_event event
;
354 l
= read(rfkill_fd
, &event
, sizeof(event
));
356 if (errno
== EAGAIN
) {
359 /* Notify manager that we are
361 * processing whatever was
363 (void) sd_notify(false, "READY=1");
367 /* Hang around for a bit, maybe there's more coming */
369 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
373 log_error_errno(r
, "Failed to poll() on device: %m");
379 log_debug("All events read and idle, exiting.");
383 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
386 if (l
!= RFKILL_EVENT_SIZE_V1
) {
387 log_error("Read event structure of invalid size.");
392 type
= rfkill_type_to_string(event
.type
);
394 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
401 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
402 (void) load_state(rfkill_fd
, udev
, &event
);
406 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
409 case RFKILL_OP_CHANGE
:
410 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
411 (void) save_state(rfkill_fd
, udev
, &event
);
415 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
423 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;