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"
28 #include "alloc-util.h"
34 #include "parse-util.h"
35 #include "proc-cmdline.h"
36 #include "string-table.h"
37 #include "string-util.h"
38 #include "udev-util.h"
41 #define EXIT_USEC (5 * USEC_PER_SEC)
43 static const char* const rfkill_type_table
[NUM_RFKILL_TYPES
] = {
44 [RFKILL_TYPE_ALL
] = "all",
45 [RFKILL_TYPE_WLAN
] = "wlan",
46 [RFKILL_TYPE_BLUETOOTH
] = "bluetooth",
47 [RFKILL_TYPE_UWB
] = "uwb",
48 [RFKILL_TYPE_WIMAX
] = "wimax",
49 [RFKILL_TYPE_WWAN
] = "wwan",
50 [RFKILL_TYPE_GPS
] = "gps",
51 [RFKILL_TYPE_FM
] = "fm",
52 [RFKILL_TYPE_NFC
] = "nfc",
55 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type
, int);
57 static int find_device(
59 const struct rfkill_event
*event
,
60 struct udev_device
**ret
) {
62 _cleanup_free_
char *sysname
= NULL
;
63 struct udev_device
*device
;
70 if (asprintf(&sysname
, "rfkill%i", event
->idx
) < 0)
73 device
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
75 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
77 name
= udev_device_get_sysattr_value(device
, "name");
79 log_debug("Device has no name, ignoring.");
80 udev_device_unref(device
);
84 log_debug("Operating on rfkill device '%s'.", name
);
90 static int wait_for_initialized(
92 struct udev_device
*device
,
93 struct udev_device
**ret
) {
95 _cleanup_udev_monitor_unref_
struct udev_monitor
*monitor
= NULL
;
96 struct udev_device
*d
;
104 if (udev_device_get_is_initialized(device
) != 0) {
105 *ret
= udev_device_ref(device
);
109 assert_se(sysname
= udev_device_get_sysname(device
));
111 /* Wait until the device is initialized, so that we can get
112 * access to the ID_PATH property */
114 monitor
= udev_monitor_new_from_netlink(udev
, "udev");
116 return log_error_errno(errno
, "Failed to acquire monitor: %m");
118 r
= udev_monitor_filter_add_match_subsystem_devtype(monitor
, "rfkill", NULL
);
120 return log_error_errno(r
, "Failed to add rfkill udev match to monitor: %m");
122 r
= udev_monitor_enable_receiving(monitor
);
124 return log_error_errno(r
, "Failed to enable udev receiving: %m");
126 watch_fd
= udev_monitor_get_fd(monitor
);
128 return log_error_errno(watch_fd
, "Failed to get watch fd: %m");
130 /* Check again, maybe things changed */
131 d
= udev_device_new_from_subsystem_sysname(udev
, "rfkill", sysname
);
133 return log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open device: %m");
135 if (udev_device_get_is_initialized(d
) != 0) {
141 _cleanup_udev_device_unref_
struct udev_device
*t
= NULL
;
143 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
147 return log_error_errno(r
, "Failed to watch udev monitor: %m");
149 t
= udev_monitor_receive_device(monitor
);
153 if (streq_ptr(udev_device_get_sysname(device
), sysname
)) {
154 *ret
= udev_device_ref(t
);
160 static int determine_state_file(
162 const struct rfkill_event
*event
,
163 struct udev_device
*d
,
166 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
167 const char *path_id
, *type
;
175 r
= wait_for_initialized(udev
, d
, &device
);
179 assert_se(type
= rfkill_type_to_string(event
->type
));
181 path_id
= udev_device_get_property_value(device
, "ID_PATH");
183 _cleanup_free_
char *escaped_path_id
= NULL
;
185 escaped_path_id
= cescape(path_id
);
186 if (!escaped_path_id
)
189 state_file
= strjoin("/var/lib/systemd/rfkill/", escaped_path_id
, ":", type
, NULL
);
191 state_file
= strjoin("/var/lib/systemd/rfkill/", type
, NULL
);
200 static int load_state(
203 const struct rfkill_event
*event
) {
205 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
206 _cleanup_free_
char *state_file
= NULL
, *value
= NULL
;
207 struct rfkill_event we
;
211 assert(rfkill_fd
>= 0);
215 if (shall_restore_state() == 0)
218 r
= find_device(udev
, event
, &device
);
222 r
= determine_state_file(udev
, event
, device
, &state_file
);
226 r
= read_one_line_file(state_file
, &value
);
228 /* No state file? Then save the current state */
230 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
232 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
234 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
238 return log_error_errno(r
, "Failed to read state file %s: %m", state_file
);
240 b
= parse_boolean(value
);
242 return log_error_errno(b
, "Failed to parse state file %s: %m", state_file
);
244 we
= (struct rfkill_event
) {
245 .op
= RFKILL_OP_CHANGE
,
250 l
= write(rfkill_fd
, &we
, sizeof(we
));
252 return log_error_errno(errno
, "Failed to restore rfkill state for %i: %m", event
->idx
);
253 if (l
!= sizeof(we
)) {
254 log_error("Couldn't write rfkill event structure, too short.");
258 log_debug("Loaded state '%s' from %s.", one_zero(b
), state_file
);
262 static int save_state(
265 const struct rfkill_event
*event
) {
267 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
268 _cleanup_free_
char *state_file
= NULL
;
271 assert(rfkill_fd
>= 0);
275 r
= find_device(udev
, event
, &device
);
279 r
= determine_state_file(udev
, event
, device
, &state_file
);
283 r
= write_string_file(state_file
, one_zero(event
->soft
), WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
285 return log_error_errno(r
, "Failed to write state file %s: %m", state_file
);
287 log_debug("Saved state '%s' to %s.", one_zero(event
->soft
), state_file
);
291 int main(int argc
, char *argv
[]) {
292 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
293 _cleanup_close_
int rfkill_fd
= -1;
298 log_error("This program requires no arguments.");
302 log_set_target(LOG_TARGET_AUTO
);
303 log_parse_environment();
314 r
= mkdir_p("/var/lib/systemd/rfkill", 0755);
316 log_error_errno(r
, "Failed to create rfkill directory: %m");
320 n
= sd_listen_fds(false);
322 r
= log_error_errno(n
, "Failed to determine whether we got any file descriptors passed: %m");
326 log_error("Got too many file descriptors.");
332 rfkill_fd
= open("/dev/rfkill", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
334 if (errno
== ENOENT
) {
335 log_debug_errno(errno
, "Missing rfkill subsystem, or no device present, exiting.");
340 r
= log_error_errno(errno
, "Failed to open /dev/rfkill: %m");
344 rfkill_fd
= SD_LISTEN_FDS_START
;
346 r
= fd_nonblock(rfkill_fd
, 1);
348 log_error_errno(r
, "Failed to make /dev/rfkill socket non-blocking: %m");
354 struct rfkill_event event
;
358 l
= read(rfkill_fd
, &event
, sizeof(event
));
360 if (errno
== EAGAIN
) {
363 /* Notify manager that we are
365 * processing whatever was
367 (void) sd_notify(false, "READY=1");
371 /* Hang around for a bit, maybe there's more coming */
373 r
= fd_wait_for_event(rfkill_fd
, POLLIN
, EXIT_USEC
);
377 log_error_errno(r
, "Failed to poll() on device: %m");
383 log_debug("All events read and idle, exiting.");
387 log_error_errno(errno
, "Failed to read from /dev/rfkill: %m");
390 if (l
!= RFKILL_EVENT_SIZE_V1
) {
391 log_error("Read event structure of invalid size.");
396 type
= rfkill_type_to_string(event
.type
);
398 log_debug("An rfkill device of unknown type %i discovered, ignoring.", event
.type
);
405 log_debug("A new rfkill device has been added with index %i and type %s.", event
.idx
, type
);
406 (void) load_state(rfkill_fd
, udev
, &event
);
410 log_debug("An rfkill device has been removed with index %i and type %s", event
.idx
, type
);
413 case RFKILL_OP_CHANGE
:
414 log_debug("An rfkill device has changed state with index %i and type %s", event
.idx
, type
);
415 (void) save_state(rfkill_fd
, udev
, &event
);
419 log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event
.op
, event
.idx
, type
);
427 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;