]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udevadm-wait.c
device-util: Declare iterator variables inline
[thirdparty/systemd.git] / src / udev / udevadm-wait.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include <getopt.h>
4 #include <unistd.h>
5
6 #include "sd-event.h"
7
8 #include "alloc-util.h"
9 #include "chase.h"
10 #include "device-monitor-private.h"
11 #include "device-util.h"
12 #include "errno-util.h"
13 #include "event-util.h"
14 #include "fd-util.h"
15 #include "fs-util.h"
16 #include "inotify-util.h"
17 #include "parse-util.h"
18 #include "path-util.h"
19 #include "static-destruct.h"
20 #include "string-table.h"
21 #include "strv.h"
22 #include "udev-util.h"
23 #include "udevadm.h"
24
25 typedef enum WaitUntil {
26 WAIT_UNTIL_INITIALIZED,
27 WAIT_UNTIL_ADDED,
28 WAIT_UNTIL_REMOVED,
29 _WAIT_UNTIL_MAX,
30 _WAIT_UNTIL_INVALID = -EINVAL,
31 } WaitUntil;
32
33 static WaitUntil arg_wait_until = WAIT_UNTIL_INITIALIZED;
34 static usec_t arg_timeout_usec = USEC_INFINITY;
35 static bool arg_settle = false;
36 static char **arg_devices = NULL;
37
38 STATIC_DESTRUCTOR_REGISTER(arg_devices, strv_freep);
39
40 static const char * const wait_until_table[_WAIT_UNTIL_MAX] = {
41 [WAIT_UNTIL_INITIALIZED] = "initialized",
42 [WAIT_UNTIL_ADDED] = "added",
43 [WAIT_UNTIL_REMOVED] = "removed",
44 };
45
46 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wait_until, WaitUntil);
47
48 static int check_device(const char *path) {
49 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
50 int r;
51
52 assert(path);
53
54 if (arg_wait_until == WAIT_UNTIL_REMOVED) {
55 r = laccess(path, F_OK);
56 if (r == -ENOENT)
57 return true;
58 if (r < 0)
59 return r;
60 return false;
61 }
62
63 r = sd_device_new_from_path(&dev, path);
64 if (r == -ENODEV)
65 return false;
66 if (r < 0)
67 return r;
68
69 if (arg_wait_until == WAIT_UNTIL_INITIALIZED)
70 return sd_device_get_is_initialized(dev);
71
72 return true;
73 }
74
75 static bool check(void) {
76 int r;
77
78 if (arg_settle) {
79 r = udev_queue_is_empty();
80 if (r == 0)
81 return false;
82 if (r < 0)
83 log_warning_errno(r, "Failed to check if udev queue is empty, assuming empty: %m");
84 }
85
86 STRV_FOREACH(p, arg_devices) {
87 r = check_device(*p);
88 if (r <= 0) {
89 if (r < 0)
90 log_warning_errno(r, "Failed to check if device \"%s\" is %s, assuming not %s: %m",
91 *p,
92 wait_until_to_string(arg_wait_until),
93 wait_until_to_string(arg_wait_until));
94 return false;
95 }
96 }
97
98 return true;
99 }
100
101 static int check_and_exit(sd_event *event) {
102 int r;
103
104 assert(event);
105
106 if (check()) {
107 r = sd_event_exit(event, 0);
108 if (r < 0)
109 return r;
110
111 return 1;
112 }
113
114 return 0;
115 }
116
117 static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
118 const char *name;
119 int r;
120
121 assert(monitor);
122 assert(device);
123
124 if (device_for_action(device, SD_DEVICE_REMOVE) != (arg_wait_until == WAIT_UNTIL_REMOVED))
125 return 0;
126
127 if (arg_wait_until == WAIT_UNTIL_REMOVED)
128 /* On removed event, the received device may not contain enough information.
129 * Let's unconditionally check all requested devices are removed. */
130 return check_and_exit(sd_device_monitor_get_event(monitor));
131
132 /* For other events, at first check if the received device matches with the requested devices,
133 * to avoid calling check() so many times within a short time. */
134
135 r = sd_device_get_sysname(device, &name);
136 if (r < 0) {
137 log_device_warning_errno(device, r, "Failed to get sysname of received device, ignoring: %m");
138 return 0;
139 }
140
141 STRV_FOREACH(p, arg_devices) {
142 const char *s;
143
144 if (!path_startswith(*p, "/sys"))
145 continue;
146
147 r = path_find_last_component(*p, false, NULL, &s);
148 if (r < 0) {
149 log_warning_errno(r, "Failed to extract filename from \"%s\", ignoring: %m", *p);
150 continue;
151 }
152 if (r == 0)
153 continue;
154
155 if (strneq(s, name, r))
156 return check_and_exit(sd_device_monitor_get_event(monitor));
157 }
158
159 r = sd_device_get_devname(device, &name);
160 if (r < 0) {
161 if (r != -ENOENT)
162 log_device_warning_errno(device, r, "Failed to get devname of received device, ignoring: %m");
163 return 0;
164 }
165
166 if (path_strv_contains(arg_devices, name))
167 return check_and_exit(sd_device_monitor_get_event(monitor));
168
169 FOREACH_DEVICE_DEVLINK(device, link)
170 if (path_strv_contains(arg_devices, link))
171 return check_and_exit(sd_device_monitor_get_event(monitor));
172
173 return 0;
174 }
175
176 static int setup_monitor(sd_event *event, MonitorNetlinkGroup group, const char *description, sd_device_monitor **ret) {
177 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
178 int r;
179
180 assert(event);
181 assert(ret);
182
183 r = device_monitor_new_full(&monitor, group, /* fd = */ -1);
184 if (r < 0)
185 return r;
186
187 (void) sd_device_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
188
189 r = sd_device_monitor_attach_event(monitor, event);
190 if (r < 0)
191 return r;
192
193 r = sd_device_monitor_set_description(monitor, description);
194 if (r < 0)
195 return r;
196
197 r = sd_device_monitor_start(monitor, device_monitor_handler, NULL);
198 if (r < 0)
199 return r;
200
201 *ret = TAKE_PTR(monitor);
202 return 0;
203 }
204
205 static int on_inotify(sd_event_source *s, const struct inotify_event *event, void *userdata) {
206 return check_and_exit(sd_event_source_get_event(s));
207 }
208
209 static int setup_inotify(sd_event *event) {
210 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
211 int r;
212
213 assert(event);
214
215 if (!arg_settle)
216 return 0;
217
218 r = sd_event_add_inotify(event, &s, "/run/udev" , IN_CREATE | IN_DELETE, on_inotify, NULL);
219 if (r < 0)
220 return r;
221
222 r = sd_event_source_set_description(s, "inotify-event-source");
223 if (r < 0)
224 return r;
225
226 return sd_event_source_set_floating(s, true);
227 }
228
229 static int setup_timer(sd_event *event) {
230 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
231 int r;
232
233 assert(event);
234
235 if (arg_timeout_usec == USEC_INFINITY)
236 return 0;
237
238 r = sd_event_add_time_relative(event, &s, CLOCK_BOOTTIME, arg_timeout_usec, 0,
239 NULL, INT_TO_PTR(-ETIMEDOUT));
240 if (r < 0)
241 return r;
242
243 r = sd_event_source_set_description(s, "timeout-event-source");
244 if (r < 0)
245 return r;
246
247 return sd_event_source_set_floating(s, true);
248 }
249
250 static int reset_timer(sd_event *e, sd_event_source **s);
251
252 static int on_periodic_timer(sd_event_source *s, uint64_t usec, void *userdata) {
253 static unsigned counter = 0;
254 sd_event *e;
255 int r;
256
257 assert(s);
258
259 e = sd_event_source_get_event(s);
260
261 /* Even if all devices exists, we try to wait for uevents to be emitted from kernel. */
262 if (check())
263 counter++;
264 else
265 counter = 0;
266
267 if (counter >= 2) {
268 log_debug("All requested devices popped up without receiving kernel uevents.");
269 return sd_event_exit(e, 0);
270 }
271
272 r = reset_timer(e, &s);
273 if (r < 0)
274 log_warning_errno(r, "Failed to reset periodic timer event source, ignoring: %m");
275
276 return 0;
277 }
278
279 static int reset_timer(sd_event *e, sd_event_source **s) {
280 return event_reset_time_relative(e, s, CLOCK_BOOTTIME, 250 * USEC_PER_MSEC, 0,
281 on_periodic_timer, NULL, 0, "periodic-timer-event-source", false);
282 }
283
284 static int setup_periodic_timer(sd_event *event) {
285 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
286 int r;
287
288 assert(event);
289
290 r = reset_timer(event, &s);
291 if (r < 0)
292 return r;
293
294 /* Set the lower priority than device monitor, to make uevents always dispatched first. */
295 r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_NORMAL + 1);
296 if (r < 0)
297 return r;
298
299 return sd_event_source_set_floating(s, true);
300 }
301
302 static int help(void) {
303 printf("%s wait [OPTIONS] DEVICE [DEVICEā€¦]\n\n"
304 "Wait for devices or device symlinks being created.\n\n"
305 " -h --help Print this message\n"
306 " -V --version Print version of the program\n"
307 " -t --timeout=SEC Maximum time to wait for the device\n"
308 " --initialized=BOOL Wait for devices being initialized by systemd-udevd\n"
309 " --removed Wait for devices being removed\n"
310 " --settle Also wait for all queued events being processed\n",
311 program_invocation_short_name);
312
313 return 0;
314 }
315
316 static int parse_argv(int argc, char *argv[]) {
317 enum {
318 ARG_INITIALIZED = 0x100,
319 ARG_REMOVED,
320 ARG_SETTLE,
321 };
322
323 static const struct option options[] = {
324 { "timeout", required_argument, NULL, 't' },
325 { "initialized", required_argument, NULL, ARG_INITIALIZED },
326 { "removed", no_argument, NULL, ARG_REMOVED },
327 { "settle", no_argument, NULL, ARG_SETTLE },
328 { "help", no_argument, NULL, 'h' },
329 { "version", no_argument, NULL, 'V' },
330 {}
331 };
332
333 int c, r;
334
335 while ((c = getopt_long(argc, argv, "t:hV", options, NULL)) >= 0)
336 switch (c) {
337 case 't':
338 r = parse_sec(optarg, &arg_timeout_usec);
339 if (r < 0)
340 return log_error_errno(r, "Failed to parse -t/--timeout= parameter: %s", optarg);
341 break;
342
343 case ARG_INITIALIZED:
344 r = parse_boolean(optarg);
345 if (r < 0)
346 return log_error_errno(r, "Failed to parse --initialized= parameter: %s", optarg);
347 arg_wait_until = r ? WAIT_UNTIL_INITIALIZED : WAIT_UNTIL_ADDED;
348 break;
349
350 case ARG_REMOVED:
351 arg_wait_until = WAIT_UNTIL_REMOVED;
352 break;
353
354 case ARG_SETTLE:
355 arg_settle = true;
356 break;
357
358 case 'V':
359 return print_version();
360
361 case 'h':
362 return help();
363
364 case '?':
365 return -EINVAL;
366
367 default:
368 assert_not_reached();
369 }
370
371 if (optind >= argc)
372 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
373 "Too few arguments, expected at least one device path or device symlink.");
374
375 arg_devices = strv_copy(argv + optind);
376 if (!arg_devices)
377 return log_oom();
378
379 return 1; /* work to do */
380 }
381
382 int wait_main(int argc, char *argv[], void *userdata) {
383 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *udev_monitor = NULL, *kernel_monitor = NULL;
384 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
385 int r;
386
387 r = parse_argv(argc, argv);
388 if (r <= 0)
389 return r;
390
391 STRV_FOREACH(p, arg_devices) {
392 path_simplify(*p);
393
394 if (!path_is_safe(*p))
395 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
396 "Device path cannot contain \"..\".");
397
398 if (!is_device_path(*p))
399 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
400 "Specified path \"%s\" does not start with \"/dev/\" or \"/sys/\".", *p);
401 }
402
403 /* Check before configuring event sources, as devices may be already initialized. */
404 if (check())
405 return 0;
406
407 r = sd_event_default(&event);
408 if (r < 0)
409 return log_error_errno(r, "Failed to initialize sd-event: %m");
410
411 r = setup_timer(event);
412 if (r < 0)
413 return log_error_errno(r, "Failed to set up timeout: %m");
414
415 r = setup_inotify(event);
416 if (r < 0)
417 return log_error_errno(r, "Failed to set up inotify: %m");
418
419 r = setup_monitor(event, MONITOR_GROUP_UDEV, "udev-uevent-monitor-event-source", &udev_monitor);
420 if (r < 0)
421 return log_error_errno(r, "Failed to set up udev uevent monitor: %m");
422
423 if (arg_wait_until == WAIT_UNTIL_ADDED) {
424 /* If --initialized=no is specified, it is not necessary to wait uevents for the specified
425 * devices to be processed by udevd. Hence, let's listen on the kernel's uevent stream. Then,
426 * we may be able to finish this program earlier when udevd is very busy.
427 * Note, we still need to also setup udev monitor, as this may be invoked with a devlink
428 * (e.g. /dev/disk/by-id/foo). In that case, the devlink may not exist when we received a
429 * uevent from kernel, as the udevd may not finish to process the uevent yet. Hence, we need
430 * to wait until the event is processed by udevd. */
431 r = setup_monitor(event, MONITOR_GROUP_KERNEL, "kernel-uevent-monitor-event-source", &kernel_monitor);
432 if (r < 0)
433 return log_error_errno(r, "Failed to set up kernel uevent monitor: %m");
434
435 /* This is a workaround for issues #24360 and #24450.
436 * For some reasons, the kernel sometimes does not emit uevents for loop block device on
437 * attach. Hence, without the periodic timer, no event source for this program will be
438 * triggered, and this will be timed out.
439 * Theoretically, inotify watch may be better, but this program typically expected to run in
440 * a short time. Hence, let's use the simpler periodic timer event source here. */
441 r = setup_periodic_timer(event);
442 if (r < 0)
443 return log_error_errno(r, "Failed to set up periodic timer: %m");
444 }
445
446 /* Check before entering the event loop, as devices may be initialized during setting up event sources. */
447 if (check())
448 return 0;
449
450 r = sd_event_loop(event);
451 if (r == -ETIMEDOUT)
452 return log_error_errno(r, "Timed out for waiting devices being %s.",
453 wait_until_to_string(arg_wait_until));
454 if (r < 0)
455 return log_error_errno(r, "Event loop failed: %m");
456
457 return 0;
458 }