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 "parse-util.h"
34 #include "string-table.h"
35 #include "string-util.h"
36 #include "udev-util.h"
39 #define EXIT_USEC (5 * USEC_PER_SEC)
41 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
42 [RFKILL_TYPE_ALL
] = "all",
43 [RFKILL_TYPE_WLAN
] = "wlan",
44 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
45 [RFKILL_TYPE_UWB
] = "uwb",
46 [RFKILL_TYPE_WIMAX
] = "wimax",
47 [RFKILL_TYPE_WWAN
] = "wwan",
48 [RFKILL_TYPE_GPS
] = "gps",
49 [RFKILL_TYPE_FM
] = "fm",
50 [RFKILL_TYPE_NFC
] = "nfc",
53 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
55 static int find_device(
57 const struct rfkill_event
*event
,
58 struct udev_device
**ret
) {
60 _cleanup_free_
char *sysname
= NULL
;
61 struct udev_device
*device
;
68 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
71 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
73 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
75 name
= udev_device_get_sysattr_value(device
, "name");
77 log_debug("Device has no name, ignoring.");
78 udev_device_unref(device
);
82 log_debug("Operating on rfkill device '%s'.", name
);
88 static int wait_for_initialized(
90 struct udev_device
*device
,
91 struct udev_device
**ret
) {
93 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
94 struct udev_device
*d
;
102 if (udev_device_get_is_initialized(device
) != 0) {
103 *ret
= udev_device_ref(device
);
107 assert_se(sysname
= udev_device_get_sysname(device
));
109 /* Wait until the device is initialized, so that we can get
110 * access to the ID_PATH property */
112 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
114 return log_error_errno(errno
, "Failed to acquire monitor: %m");
116 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
118 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
120 r
= udev_monitor_enable_receiving(monitor
);
122 return log_error_errno(r
, "Failed to enable udev receiving: %m");
124 watch_fd
= udev_monitor_get_fd(monitor
);
126 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
128 /* Check again, maybe things changed */
129 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
131 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
133 if (udev_device_get_is_initialized(d
) != 0) {
139 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
141 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
145 return log_error_errno(r
, "Failed to watch udev monitor: %m");
147 t
= udev_monitor_receive_device(monitor
);
151 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
152 *ret
= udev_device_ref(t
);
158 static int determine_state_file(
160 const struct rfkill_event
*event
,
161 struct udev_device
*d
,
164 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
165 const char *path_id
, *type
;
173 r
= wait_for_initialized(udev
, d
, &device
);
177 assert_se(type
= rfkill_type_to_string(event
->type
));
179 path_id
= udev_device_get_property_value(device
, "ID_PATH");
181 _cleanup_free_
char *escaped_path_id
= NULL
;
183 escaped_path_id
= cescape(path_id
);
184 if (!escaped_path_id
)
187 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
189 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
198 static int load_state(
201 const struct rfkill_event
*event
) {
203 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
204 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
205 struct rfkill_event we
;
209 assert(rfkill_fd
>= 0);
213 if (!shall_restore_state())
216 r
= find_device(udev
, event
, &device
);
220 r
= determine_state_file(udev
, event
, device
, &state_file
);
224 r
= read_one_line_file(state_file
, &value
);
226 /* No state file? Then save the current state */
228 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
230 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
232 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
236 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
238 b
= parse_boolean(value
);
240 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
242 we
= (struct rfkill_event
) {
243 .op
= RFKILL_OP_CHANGE
,
248 l
= write(rfkill_fd
, &we
, sizeof(we
));
250 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
251 if (l
!= sizeof(we
)) {
252 log_error("Couldn't write rfkill event structure, too short.");
256 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
260 static int save_state(
263 const struct rfkill_event
*event
) {
265 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
266 _cleanup_free_
char *state_file
= NULL
;
269 assert(rfkill_fd
>= 0);
273 r
= find_device(udev
, event
, &device
);
277 r
= determine_state_file(udev
, event
, device
, &state_file
);
281 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
283 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
285 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
289 int main(int argc
, char *argv
[]) {
290 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
291 _cleanup_close_
int rfkill_fd
= -1;
296 log_error("This program requires no arguments.");
300 log_set_target(LOG_TARGET_AUTO
);
301 log_parse_environment();
312 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
314 log_error_errno(r
, "Failed to create rfkill directory: %m");
318 n
= sd_listen_fds(false);
320 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
324 log_error("Got too many file descriptors.");
330 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
332 if (errno
== ENOENT
) {
333 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
338 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
342 rfkill_fd
= SD_LISTEN_FDS_START
;
344 r
= fd_nonblock(rfkill_fd
, 1);
346 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
352 struct rfkill_event event
;
356 l
= read(rfkill_fd
, &event
, sizeof(event
));
358 if (errno
== EAGAIN
) {
361 /* Notify manager that we are
363 * processing whatever was
365 (void) sd_notify(false, "READY=1");
369 /* Hang around for a bit, maybe there's more coming */
371 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
375 log_error_errno(r
, "Failed to poll() on device: %m");
381 log_debug("All events read and idle, exiting.");
385 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
388 if (l
!= RFKILL_EVENT_SIZE_V1
) {
389 log_error("Read event structure of invalid size.");
394 type
= rfkill_type_to_string(event
.type
);
396 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
403 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
404 (void) load_state(rfkill_fd
, udev
, &event
);
408 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
411 case RFKILL_OP_CHANGE
:
412 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
413 (void) save_state(rfkill_fd
, udev
, &event
);
417 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
425 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;