]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
b237a168 | 2 | |
152d0efa | 3 | #include <errno.h> |
b237a168 | 4 | |
152d0efa | 5 | #include "alloc-util.h" |
f822c5d5 | 6 | #include "device-util.h" |
686d13b9 | 7 | #include "env-file.h" |
b237a168 | 8 | #include "log.h" |
4b3ca79e | 9 | #include "parse-util.h" |
e2099267 | 10 | #include "signal-util.h" |
bc768f04 | 11 | #include "string-table.h" |
b237a168 ZJS |
12 | #include "string-util.h" |
13 | #include "udev-util.h" | |
14 | ||
bc768f04 ZJS |
15 | static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = { |
16 | [RESOLVE_NAME_NEVER] = "never", | |
17 | [RESOLVE_NAME_LATE] = "late", | |
18 | [RESOLVE_NAME_EARLY] = "early", | |
19 | }; | |
20 | ||
21 | DEFINE_STRING_TABLE_LOOKUP(resolve_name_timing, ResolveNameTiming); | |
22 | ||
4b3ca79e ZJS |
23 | int udev_parse_config_full( |
24 | unsigned *ret_children_max, | |
25 | usec_t *ret_exec_delay_usec, | |
a14e7af1 | 26 | usec_t *ret_event_timeout_usec, |
e2099267 MS |
27 | ResolveNameTiming *ret_resolve_name_timing, |
28 | int *ret_timeout_signal) { | |
4b3ca79e | 29 | |
e2099267 | 30 | _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL, *resolve_names = NULL, *timeout_signal = NULL; |
b237a168 ZJS |
31 | int r; |
32 | ||
aa8fbc74 | 33 | r = parse_env_file(NULL, "/etc/udev/udev.conf", |
4b3ca79e ZJS |
34 | "udev_log", &log_val, |
35 | "children_max", &children_max, | |
36 | "exec_delay", &exec_delay, | |
9b2934cb | 37 | "event_timeout", &event_timeout, |
e2099267 MS |
38 | "resolve_names", &resolve_names, |
39 | "timeout_signal", &timeout_signal); | |
4b3ca79e | 40 | if (r == -ENOENT) |
b237a168 ZJS |
41 | return 0; |
42 | if (r < 0) | |
43 | return r; | |
44 | ||
4b3ca79e ZJS |
45 | if (log_val) { |
46 | const char *log; | |
47 | size_t n; | |
48 | ||
49 | /* unquote */ | |
50 | n = strlen(log_val); | |
51 | if (n >= 2 && | |
52 | ((log_val[0] == '"' && log_val[n-1] == '"') || | |
53 | (log_val[0] == '\'' && log_val[n-1] == '\''))) { | |
54 | log_val[n - 1] = '\0'; | |
55 | log = log_val + 1; | |
56 | } else | |
57 | log = log_val; | |
58 | ||
59 | /* we set the udev log level here explicitly, this is supposed | |
60 | * to regulate the code in libudev/ and udev/. */ | |
61 | r = log_set_max_level_from_string_realm(LOG_REALM_UDEV, log); | |
62 | if (r < 0) | |
d7921114 ZJS |
63 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, |
64 | "failed to set udev log level '%s', ignoring: %m", log); | |
4b3ca79e ZJS |
65 | } |
66 | ||
67 | if (ret_children_max && children_max) { | |
68 | r = safe_atou(children_max, ret_children_max); | |
69 | if (r < 0) | |
d7921114 | 70 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, |
e2099267 | 71 | "failed to parse children_max=%s, ignoring: %m", children_max); |
4b3ca79e ZJS |
72 | } |
73 | ||
74 | if (ret_exec_delay_usec && exec_delay) { | |
75 | r = parse_sec(exec_delay, ret_exec_delay_usec); | |
76 | if (r < 0) | |
d7921114 | 77 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, |
e2099267 | 78 | "failed to parse exec_delay=%s, ignoring: %m", exec_delay); |
4b3ca79e ZJS |
79 | } |
80 | ||
81 | if (ret_event_timeout_usec && event_timeout) { | |
82 | r = parse_sec(event_timeout, ret_event_timeout_usec); | |
83 | if (r < 0) | |
d7921114 | 84 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, |
e2099267 | 85 | "failed to parse event_timeout=%s, ignoring: %m", event_timeout); |
4b3ca79e | 86 | } |
b237a168 | 87 | |
a14e7af1 ZJS |
88 | if (ret_resolve_name_timing && resolve_names) { |
89 | ResolveNameTiming t; | |
90 | ||
91 | t = resolve_name_timing_from_string(resolve_names); | |
92 | if (t < 0) | |
d7921114 | 93 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, |
e2099267 | 94 | "failed to parse resolve_names=%s, ignoring.", resolve_names); |
a14e7af1 ZJS |
95 | else |
96 | *ret_resolve_name_timing = t; | |
97 | } | |
e2099267 MS |
98 | |
99 | if (ret_timeout_signal && timeout_signal) { | |
100 | r = signal_from_string(timeout_signal); | |
101 | if (r < 0) | |
102 | log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, | |
103 | "failed to parse timeout_signal=%s, ignoring: %m", timeout_signal); | |
104 | else | |
105 | *ret_timeout_signal = r; | |
106 | } | |
a14e7af1 | 107 | |
b237a168 ZJS |
108 | return 0; |
109 | } | |
ed435031 ZJS |
110 | |
111 | struct DeviceMonitorData { | |
112 | const char *sysname; | |
113 | sd_device *device; | |
114 | }; | |
115 | ||
116 | static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) { | |
117 | struct DeviceMonitorData *data = userdata; | |
118 | const char *sysname; | |
119 | ||
120 | assert(device); | |
121 | assert(data); | |
122 | assert(data->sysname); | |
123 | assert(!data->device); | |
124 | ||
125 | if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) { | |
126 | data->device = sd_device_ref(device); | |
127 | return sd_event_exit(sd_device_monitor_get_event(monitor), 0); | |
128 | } | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
1b47436e YW |
133 | static int device_timeout_handler(sd_event_source *s, uint64_t usec, void *userdata) { |
134 | return sd_event_exit(sd_event_source_get_event(s), -ETIMEDOUT); | |
135 | } | |
136 | ||
137 | int device_wait_for_initialization(sd_device *device, const char *subsystem, usec_t timeout, sd_device **ret) { | |
ed435031 | 138 | _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; |
1b47436e | 139 | _cleanup_(sd_event_source_unrefp) sd_event_source *timeout_source = NULL; |
ed435031 ZJS |
140 | _cleanup_(sd_event_unrefp) sd_event *event = NULL; |
141 | struct DeviceMonitorData data = {}; | |
142 | int r; | |
143 | ||
144 | assert(device); | |
ed435031 ZJS |
145 | |
146 | if (sd_device_get_is_initialized(device) > 0) { | |
147 | if (ret) | |
148 | *ret = sd_device_ref(device); | |
149 | return 0; | |
150 | } | |
151 | ||
152 | assert_se(sd_device_get_sysname(device, &data.sysname) >= 0); | |
153 | ||
154 | /* Wait until the device is initialized, so that we can get access to the ID_PATH property */ | |
155 | ||
fc40bfa7 | 156 | r = sd_event_new(&event); |
ed435031 ZJS |
157 | if (r < 0) |
158 | return log_error_errno(r, "Failed to get default event: %m"); | |
159 | ||
160 | r = sd_device_monitor_new(&monitor); | |
161 | if (r < 0) | |
162 | return log_error_errno(r, "Failed to acquire monitor: %m"); | |
163 | ||
f822c5d5 YW |
164 | if (!subsystem) { |
165 | r = sd_device_get_subsystem(device, &subsystem); | |
166 | if (r < 0 && r != -ENOENT) | |
167 | return log_device_error_errno(device, r, "Failed to get subsystem: %m"); | |
168 | } | |
169 | ||
170 | if (subsystem) { | |
171 | r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, NULL); | |
172 | if (r < 0) | |
173 | return log_error_errno(r, "Failed to add %s subsystem match to monitor: %m", subsystem); | |
174 | } | |
ed435031 ZJS |
175 | |
176 | r = sd_device_monitor_attach_event(monitor, event); | |
177 | if (r < 0) | |
178 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); | |
179 | ||
180 | r = sd_device_monitor_start(monitor, device_monitor_handler, &data); | |
181 | if (r < 0) | |
182 | return log_error_errno(r, "Failed to start device monitor: %m"); | |
183 | ||
1b47436e YW |
184 | if (timeout != USEC_INFINITY) { |
185 | r = sd_event_add_time(event, &timeout_source, | |
186 | CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + timeout, 0, | |
187 | device_timeout_handler, NULL); | |
188 | if (r < 0) | |
189 | return log_error_errno(r, "Failed to add timeout event source: %m"); | |
190 | } | |
191 | ||
ed435031 ZJS |
192 | /* Check again, maybe things changed. Udev will re-read the db if the device wasn't initialized |
193 | * yet. */ | |
194 | if (sd_device_get_is_initialized(device) > 0) { | |
195 | if (ret) | |
196 | *ret = sd_device_ref(device); | |
197 | return 0; | |
198 | } | |
199 | ||
200 | r = sd_event_loop(event); | |
201 | if (r < 0) | |
1b47436e | 202 | return log_error_errno(r, "Failed to wait for device to be initialized: %m"); |
ed435031 ZJS |
203 | |
204 | if (ret) | |
205 | *ret = TAKE_PTR(data.device); | |
206 | return 0; | |
207 | } | |
90ba130f YW |
208 | |
209 | int device_is_renaming(sd_device *dev) { | |
210 | int r; | |
211 | ||
212 | assert(dev); | |
213 | ||
214 | r = sd_device_get_property_value(dev, "ID_RENAMING", NULL); | |
215 | if (r < 0 && r != -ENOENT) | |
216 | return r; | |
217 | ||
218 | return r >= 0; | |
219 | } | |
a707c65b YW |
220 | |
221 | bool device_for_action(sd_device *dev, DeviceAction action) { | |
222 | DeviceAction a; | |
223 | ||
224 | assert(dev); | |
225 | ||
226 | if (device_get_action(dev, &a) < 0) | |
227 | return false; | |
228 | ||
229 | return a == action; | |
230 | } |