Coverage Report

Created: 2025-06-24 06:40

/src/systemd/src/udev/udev-watch.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-2.0-or-later */
2
/*
3
 * Copyright © 2009 Canonical Ltd.
4
 * Copyright © 2009 Scott James Remnant <scott@netsplit.com>
5
 */
6
7
#include <sys/signalfd.h>
8
#include <sys/wait.h>
9
10
#include "alloc-util.h"
11
#include "blockdev-util.h"
12
#include "daemon-util.h"
13
#include "device-util.h"
14
#include "dirent-util.h"
15
#include "errno-util.h"
16
#include "event-util.h"
17
#include "fd-util.h"
18
#include "format-util.h"
19
#include "fs-util.h"
20
#include "inotify-util.h"
21
#include "parse-util.h"
22
#include "pidref.h"
23
#include "process-util.h"
24
#include "rm-rf.h"
25
#include "set.h"
26
#include "signal-util.h"
27
#include "stdio-util.h"
28
#include "string-util.h"
29
#include "udev-manager.h"
30
#include "udev-trace.h"
31
#include "udev-util.h"
32
#include "udev-watch.h"
33
#include "udev-worker.h"
34
35
static int udev_watch_clear_by_wd(sd_device *dev, int dirfd, int wd);
36
37
0
static int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) {
38
0
        char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
39
0
        _cleanup_free_ char *id = NULL;
40
0
        int r;
41
42
0
        assert(ret);
43
44
0
        if (wd < 0)
45
0
                return -EBADF;
46
47
0
        if (dirfd >= 0) {
48
0
                xsprintf(path_wd, "%d", wd);
49
0
                r = readlinkat_malloc(dirfd, path_wd, &id);
50
0
        } else {
51
0
                xsprintf(path_wd, "/run/udev/watch/%d", wd);
52
0
                r = readlink_malloc(path_wd, &id);
53
0
        }
54
0
        if (r < 0)
55
0
                return r;
56
57
0
        return sd_device_new_from_device_id(ret, id);
58
0
}
59
60
0
void udev_watch_dump(void) {
61
0
        int r;
62
63
0
        _cleanup_closedir_ DIR *dir = opendir("/run/udev/watch/");
64
0
        if (!dir)
65
0
                return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
66
0
                                             "Failed to open old watches directory '/run/udev/watch/': %m");
67
68
0
        _cleanup_set_free_ Set *pending_wds = NULL, *verified_wds = NULL;
69
0
        FOREACH_DIRENT(de, dir, break) {
70
0
                if (safe_atoi(de->d_name, NULL) >= 0) {
71
                        /* This should be wd -> ID symlink */
72
73
0
                        if (set_contains(verified_wds, de->d_name))
74
0
                                continue;
75
76
0
                        r = set_put_strdup(&pending_wds, de->d_name);
77
0
                        if (r < 0)
78
0
                                log_warning_errno(r, "Failed to store pending watch handle %s, ignoring: %m", de->d_name);
79
0
                        continue;
80
0
                }
81
82
0
                _cleanup_free_ char *wd = NULL;
83
0
                r = readlinkat_malloc(dirfd(dir), de->d_name, &wd);
84
0
                if (r < 0) {
85
0
                        log_warning_errno(r, "Found broken inotify watch, failed to read symlink %s, ignoring: %m", de->d_name);
86
0
                        continue;
87
0
                }
88
89
0
                const char *devnode = NULL;
90
0
                _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
91
0
                if (sd_device_new_from_device_id(&dev, de->d_name) >= 0)
92
0
                        (void) sd_device_get_devname(dev, &devnode);
93
94
0
                _cleanup_free_ char *id = NULL;
95
0
                r = readlinkat_malloc(dirfd(dir), wd, &id);
96
0
                if (r < 0) {
97
0
                        log_warning_errno(r, "Found broken inotify watch %s on %s (%s), failed to read symlink %s, ignoring: %m",
98
0
                                          wd, strna(devnode), de->d_name, wd);
99
0
                        continue;
100
0
                }
101
102
0
                if (!streq(de->d_name, id)) {
103
0
                        log_warning("Found broken inotify watch %s on %s (%s), broken symlink chain: %s → %s → %s",
104
0
                                    wd, strna(devnode), de->d_name, de->d_name, wd, id);
105
0
                        continue;
106
0
                }
107
108
0
                log_debug("Found inotify watch %s on %s (%s).", wd, strna(devnode), de->d_name);
109
110
0
                free(set_remove(pending_wds, wd));
111
112
0
                r = set_ensure_put(&verified_wds, &string_hash_ops_free, wd);
113
0
                if (r < 0) {
114
0
                        log_warning_errno(r, "Failed to store verified watch handle %s, ignoring: %m", wd);
115
0
                        continue;
116
0
                }
117
0
                TAKE_PTR(wd);
118
0
        }
119
120
0
        const char *w;
121
0
        SET_FOREACH(w, pending_wds) {
122
0
                _cleanup_free_ char *id = NULL;
123
0
                r = readlinkat_malloc(dirfd(dir), w, &id);
124
0
                if (r < 0) {
125
0
                        log_warning_errno(r, "Found broken inotify watch %s, failed to read symlink %s, ignoring: %m", w, w);
126
0
                        continue;
127
0
                }
128
129
0
                const char *devnode = NULL;
130
0
                _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
131
0
                if (sd_device_new_from_device_id(&dev, id) >= 0)
132
0
                        (void) sd_device_get_devname(dev, &devnode);
133
134
0
                _cleanup_free_ char *wd = NULL;
135
0
                (void) readlinkat_malloc(dirfd(dir), id, &wd);
136
137
0
                log_warning("Found broken inotify watch %s on %s (%s), broken symlink chain: %s → %s → %s",
138
0
                            wd, strna(devnode), id, w, id, wd);
139
0
        }
140
0
}
141
142
0
static int synthesize_change_one(sd_device *dev, sd_device *target) {
143
0
        int r;
144
145
0
        assert(dev);
146
0
        assert(target);
147
148
0
        if (DEBUG_LOGGING) {
149
0
                const char *syspath = NULL;
150
0
                (void) sd_device_get_syspath(target, &syspath);
151
0
                log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath));
152
0
        }
153
154
0
        r = sd_device_trigger(target, SD_DEVICE_CHANGE);
155
0
        if (r < 0)
156
0
                return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m");
157
158
0
        DEVICE_TRACE_POINT(synthetic_change_event, dev);
159
160
0
        return 0;
161
0
}
162
163
0
static int synthesize_change_all(sd_device *dev) {
164
0
        int r;
165
166
0
        assert(dev);
167
168
0
        r = blockdev_reread_partition_table(dev);
169
0
        if (r < 0)
170
0
                log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m");
171
0
        bool part_table_read = r >= 0;
172
173
        /* search for partitions */
174
0
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
175
0
        r = partition_enumerator_new(dev, &e);
176
0
        if (r < 0)
177
0
                return log_device_debug_errno(dev, r, "Failed to initialize partition enumerator, ignoring: %m");
178
179
        /* We have partitions and re-read the table, the kernel already sent out a "change"
180
         * event for the disk, and "remove/add" for all partitions. */
181
0
        if (part_table_read && sd_device_enumerator_get_device_first(e))
182
0
                return 0;
183
184
        /* We have partitions but re-reading the partition table did not work, synthesize
185
         * "change" for the disk and all partitions. */
186
0
        r = synthesize_change_one(dev, dev);
187
0
        FOREACH_DEVICE(e, d)
188
0
                RET_GATHER(r, synthesize_change_one(dev, d));
189
190
0
        return r;
191
0
}
192
193
0
static int synthesize_change_child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
194
0
        Manager *manager = ASSERT_PTR(userdata);
195
0
        assert(s);
196
197
0
        sd_event_source_unref(set_remove(manager->synthesize_change_child_event_sources, s));
198
0
        return 0;
199
0
}
200
201
0
static int synthesize_change(Manager *manager, sd_device *dev) {
202
0
        int r;
203
204
0
        assert(manager);
205
0
        assert(dev);
206
207
0
        r = device_sysname_startswith(dev, "dm-");
208
0
        if (r < 0)
209
0
                return r;
210
0
        if (r > 0)
211
0
                return synthesize_change_one(dev, dev);
212
213
0
        r = block_device_is_whole_disk(dev);
214
0
        if (r < 0)
215
0
                return r;
216
0
        if (r == 0)
217
0
                return synthesize_change_one(dev, dev);
218
219
0
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
220
0
        r = pidref_safe_fork(
221
0
                        "(udev-synth)",
222
0
                        FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
223
0
                        &pidref);
224
0
        if (r < 0)
225
0
                return r;
226
0
        if (r == 0) {
227
                /* child */
228
0
                (void) synthesize_change_all(dev);
229
0
                _exit(EXIT_SUCCESS);
230
0
        }
231
232
0
        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
233
0
        r = event_add_child_pidref(manager->event, &s, &pidref, WEXITED, synthesize_change_child_handler, manager);
234
0
        if (r < 0) {
235
0
                log_debug_errno(r, "Failed to add child event source for "PID_FMT", ignoring: %m", pidref.pid);
236
0
                return 0;
237
0
        }
238
239
0
        r = sd_event_source_set_child_pidfd_own(s, true);
240
0
        if (r < 0)
241
0
                return r;
242
0
        TAKE_PIDREF(pidref);
243
244
0
        r = set_ensure_put(&manager->synthesize_change_child_event_sources, &event_source_hash_ops, s);
245
0
        if (r < 0)
246
0
                return r;
247
0
        TAKE_PTR(s);
248
249
0
        return 0;
250
0
}
251
252
0
static int manager_process_inotify(Manager *manager, const struct inotify_event *e) {
253
0
        int r;
254
255
0
        assert(manager);
256
0
        assert(e);
257
258
0
        if (FLAGS_SET(e->mask, IN_IGNORED)) {
259
0
                log_debug("Received inotify event about removal of watch handle %i.", e->wd);
260
261
0
                r = udev_watch_clear_by_wd(/* dev = */ NULL, /* dirfd = */ -EBADF, e->wd);
262
0
                if (r < 0)
263
0
                        log_warning_errno(r, "Failed to remove saved symlink(s) for watch handle %i, ignoring: %m", e->wd);
264
265
0
                return 0;
266
0
        }
267
268
0
        if (!FLAGS_SET(e->mask, IN_CLOSE_WRITE))
269
0
                return 0;
270
271
0
        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
272
0
        r = device_new_from_watch_handle_at(&dev, -EBADF, e->wd);
273
0
        if (r < 0) /* Device may be removed just after closed. */
274
0
                return log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m");
275
276
0
        log_device_debug(dev, "Received inotify event of watch handle %i.", e->wd);
277
278
0
        (void) manager_requeue_locked_events_by_device(manager, dev);
279
0
        (void) synthesize_change(manager, dev);
280
0
        return 0;
281
0
}
282
283
0
static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
284
0
        Manager *manager = ASSERT_PTR(userdata);
285
286
0
        assert(fd >= 0);
287
288
0
        union inotify_event_buffer buffer;
289
0
        ssize_t l = read(fd, &buffer, sizeof(buffer));
290
0
        if (l < 0) {
291
0
                if (ERRNO_IS_TRANSIENT(errno))
292
0
                        return 0;
293
294
0
                return log_error_errno(errno, "Failed to read inotify fd: %m");
295
0
        }
296
297
0
        FOREACH_INOTIFY_EVENT_WARN(e, buffer, l)
298
0
                (void) manager_process_inotify(manager, e);
299
300
0
        return 0;
301
0
}
302
303
0
static int udev_watch_restore(Manager *manager) {
304
0
        _cleanup_(rm_rf_safep) const char *old = "/run/udev/watch.old/";
305
0
        int r;
306
307
        /* Move any old watches directory out of the way, and then restore the watches. */
308
309
0
        assert(manager);
310
311
0
        rm_rf_safe(old);
312
0
        if (rename("/run/udev/watch/", old) < 0) {
313
0
                if (errno == ENOENT)
314
0
                        return 0;
315
316
0
                return log_warning_errno(errno, "Failed to move watches directory '/run/udev/watch/': %m");
317
0
        }
318
319
0
        _cleanup_closedir_ DIR *dir = opendir(old);
320
0
        if (!dir)
321
0
                return log_warning_errno(errno, "Failed to open old watches directory '%s': %m", old);
322
323
0
        FOREACH_DIRENT(de, dir, break) {
324
325
                /* For backward compatibility, read symlink from watch handle to device ID. This is necessary
326
                 * when udevd is restarted after upgrading from v248 or older. The new format (ID -> wd) was
327
                 * introduced by e7f781e473f5119bf9246208a6de9f6b76a39c5d (v249). */
328
329
0
                int wd;
330
0
                if (safe_atoi(de->d_name, &wd) < 0)
331
0
                        continue; /* This should be ID -> wd symlink. Skipping. */
332
333
0
                _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
334
0
                r = device_new_from_watch_handle_at(&dev, dirfd(dir), wd);
335
0
                if (r < 0) {
336
0
                        log_full_errno(ERRNO_IS_NEG_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_WARNING, r,
337
0
                                       "Failed to create sd_device object from saved watch handle '%i', ignoring: %m",
338
0
                                       wd);
339
0
                        continue;
340
0
                }
341
342
0
                (void) manager_add_watch(manager, dev);
343
0
        }
344
345
0
        return 0;
346
0
}
347
348
0
int manager_init_inotify(Manager *manager, int fd) {
349
0
        int r;
350
351
0
        assert(manager);
352
353
        /* This takes passed file descriptor on success. */
354
355
0
        if (fd >= 0) {
356
0
                if (manager->inotify_fd >= 0)
357
0
                        return log_warning_errno(SYNTHETIC_ERRNO(EALREADY), "Received multiple inotify fd (%i), ignoring.", fd);
358
359
0
                log_debug("Received inotify fd (%i) from service manager.", fd);
360
0
                manager->inotify_fd = fd;
361
0
                return 0;
362
0
        }
363
364
0
        if (manager->inotify_fd >= 0)
365
0
                return 0;
366
367
0
        fd = inotify_init1(IN_CLOEXEC);
368
0
        if (fd < 0)
369
0
                return log_error_errno(errno, "Failed to create inotify descriptor: %m");
370
371
0
        log_debug("Initialized new inotify instance, restoring inotify watches of previous invocation.");
372
0
        manager->inotify_fd = fd;
373
0
        (void) udev_watch_restore(manager);
374
375
0
        r = notify_push_fd(manager->inotify_fd, "inotify");
376
0
        if (r < 0)
377
0
                log_warning_errno(r, "Failed to push inotify fd to service manager, ignoring: %m");
378
0
        else
379
0
                log_debug("Pushed inotify fd to service manager.");
380
381
0
        return 0;
382
0
}
383
384
0
int manager_start_inotify(Manager *manager) {
385
0
        int r;
386
387
0
        assert(manager);
388
0
        assert(manager->event);
389
390
0
        r = manager_init_inotify(manager, -EBADF);
391
0
        if (r < 0)
392
0
                return r;
393
394
0
        udev_watch_dump();
395
396
0
        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
397
0
        r = sd_event_add_io(manager->event, &s, manager->inotify_fd, EPOLLIN, on_inotify, manager);
398
0
        if (r < 0)
399
0
                return log_error_errno(r, "Failed to create inotify event source: %m");
400
401
0
        r = sd_event_source_set_priority(s, EVENT_PRIORITY_INOTIFY_WATCH);
402
0
        if (r < 0)
403
0
                return log_error_errno(r, "Failed to set priority to inotify event source: %m");
404
405
0
        (void) sd_event_source_set_description(s, "manager-inotify");
406
407
0
        manager->inotify_event = TAKE_PTR(s);
408
0
        return 0;
409
0
}
410
411
0
static int udev_watch_clear_by_wd(sd_device *dev, int dirfd, int wd) {
412
0
        int r;
413
414
0
        _cleanup_close_ int dirfd_close = -EBADF;
415
0
        if (dirfd < 0) {
416
0
                dirfd_close = RET_NERRNO(open("/run/udev/watch/", O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW | O_RDONLY));
417
0
                if (dirfd_close < 0)
418
0
                        return log_device_debug_errno(dev, dirfd_close, "Failed to open %s: %m", "/run/udev/watch/");
419
420
0
                dirfd = dirfd_close;
421
0
        }
422
423
0
        char wd_str[DECIMAL_STR_MAX(int)];
424
0
        xsprintf(wd_str, "%d", wd);
425
426
0
        _cleanup_free_ char *id = NULL, *wd_alloc = NULL;
427
0
        r = readlinkat_malloc(dirfd, wd_str, &id);
428
0
        if (r == -ENOENT)
429
0
                return 0;
430
0
        if (r < 0) {
431
0
                log_device_debug_errno(dev, r, "Failed to read '/run/udev/watch/%s': %m", wd_str);
432
0
                goto finalize;
433
0
        }
434
435
0
        r = readlinkat_malloc(dirfd, id, &wd_alloc);
436
0
        if (r < 0) {
437
0
                log_device_debug_errno(dev, r, "Failed to read '/run/udev/watch/%s': %m", id);
438
0
                goto finalize;
439
0
        }
440
441
0
        if (!streq(wd_str, wd_alloc)) {
442
0
                r = log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE), "Unmatching watch handle found: %s -> %s -> %s", wd_str, id, wd_alloc);
443
0
                goto finalize;
444
0
        }
445
446
0
        if (unlinkat(dirfd, id, 0) < 0 && errno != ENOENT)
447
0
                r = log_device_debug_errno(dev, errno, "Failed to remove '/run/udev/watch/%s': %m", id);
448
449
0
finalize:
450
0
        if (unlinkat(dirfd, wd_str, 0) < 0 && errno != ENOENT)
451
0
                RET_GATHER(r, log_device_debug_errno(dev, errno, "Failed to remove '/run/udev/watch/%s': %m", wd_str));
452
453
0
        return r;
454
0
}
455
456
0
static int udev_watch_clear(sd_device *dev, int dirfd, int *ret_wd) {
457
0
        _cleanup_free_ char *wd_str = NULL, *buf = NULL;
458
0
        const char *id;
459
0
        int wd = -1, r;
460
461
0
        assert(dev);
462
0
        assert(dirfd >= 0);
463
464
0
        r = sd_device_get_device_id(dev, &id);
465
0
        if (r < 0)
466
0
                return log_device_debug_errno(dev, r, "Failed to get device ID: %m");
467
468
        /* 1. read symlink ID -> wd */
469
0
        r = readlinkat_malloc(dirfd, id, &wd_str);
470
0
        if (r == -ENOENT) {
471
0
                if (ret_wd)
472
0
                        *ret_wd = -1;
473
0
                return 0;
474
0
        }
475
0
        if (r < 0) {
476
0
                log_device_debug_errno(dev, r, "Failed to read symlink '/run/udev/watch/%s': %m", id);
477
0
                goto finalize;
478
0
        }
479
480
0
        r = safe_atoi(wd_str, &wd);
481
0
        if (r < 0) {
482
0
                log_device_debug_errno(dev, r, "Failed to parse watch handle from symlink '/run/udev/watch/%s': %m", id);
483
0
                goto finalize;
484
0
        }
485
486
0
        if (wd < 0) {
487
0
                r = log_device_debug_errno(dev, SYNTHETIC_ERRNO(EBADF), "Invalid watch handle %i.", wd);
488
0
                goto finalize;
489
0
        }
490
491
        /* 2. read symlink wd -> ID */
492
0
        r = readlinkat_malloc(dirfd, wd_str, &buf);
493
0
        if (r < 0) {
494
0
                log_device_debug_errno(dev, r, "Failed to read symlink '/run/udev/watch/%s': %m", wd_str);
495
0
                goto finalize;
496
0
        }
497
498
        /* 3. check if the symlink wd -> ID is owned by the device. */
499
0
        if (!streq(buf, id)) {
500
0
                r = log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENOENT),
501
0
                                           "Symlink '/run/udev/watch/%s' is owned by another device '%s'.", wd_str, buf);
502
0
                goto finalize;
503
0
        }
504
505
        /* 4. remove symlink wd -> ID.
506
         * In the above, we already confirmed that the symlink is owned by us. Hence, no other workers remove
507
         * the symlink and cannot create a new symlink with the same filename but to a different ID. Hence,
508
         * the removal below is safe even the steps in this function are not atomic. */
509
0
        if (unlinkat(dirfd, wd_str, 0) < 0 && errno != ENOENT)
510
0
                log_device_debug_errno(dev, errno, "Failed to remove '/run/udev/watch/%s', ignoring: %m", wd_str);
511
512
0
        if (ret_wd)
513
0
                *ret_wd = wd;
514
0
        r = 1;
515
516
0
finalize:
517
        /* 5. remove symlink ID -> wd.
518
         * The file is always owned by the device. Hence, it is safe to remove it unconditionally. */
519
0
        if (unlinkat(dirfd, id, 0) < 0 && errno != ENOENT)
520
0
                log_device_debug_errno(dev, errno, "Failed to remove '/run/udev/watch/%s', ignoring: %m", id);
521
522
0
        return r;
523
0
}
524
525
0
int manager_add_watch(Manager *manager, sd_device *dev) {
526
0
        char wd_str[DECIMAL_STR_MAX(int)];
527
0
        _cleanup_close_ int dirfd = -EBADF;
528
0
        const char *devnode, *id;
529
0
        int wd, r;
530
531
0
        assert(manager);
532
0
        assert(dev);
533
534
        /* Ignore the request of watching the device node on remove event, as the device node specified by
535
         * DEVNAME= has already been removed, and may already be assigned to another device. Consider the
536
         * case e.g. a USB stick memory was unplugged and then another one is plugged. */
537
0
        if (device_for_action(dev, SD_DEVICE_REMOVE))
538
0
                return 0;
539
540
0
        r = sd_device_get_devname(dev, &devnode);
541
0
        if (r < 0)
542
0
                return log_device_debug_errno(dev, r, "Failed to get device node: %m");
543
544
0
        r = sd_device_get_device_id(dev, &id);
545
0
        if (r < 0)
546
0
                return log_device_debug_errno(dev, r, "Failed to get device ID: %m");
547
548
0
        r = dirfd = open_mkdir("/run/udev/watch", O_CLOEXEC | O_RDONLY, 0755);
549
0
        if (r < 0)
550
0
                return log_device_debug_errno(dev, r, "Failed to create and open '/run/udev/watch/': %m");
551
552
        /* 1. Clear old symlinks */
553
0
        (void) udev_watch_clear(dev, dirfd, NULL);
554
555
        /* 2. Add inotify watch */
556
0
        log_device_debug(dev, "Adding watch on '%s'", devnode);
557
0
        wd = inotify_add_watch(manager->inotify_fd, devnode, IN_CLOSE_WRITE);
558
0
        if (wd < 0)
559
0
                return log_device_debug_errno(dev, errno, "Failed to watch device node '%s': %m", devnode);
560
561
        /* 3. Clear old symlinks by the newly acquired watch handle, for the case that the watch handle is reused. */
562
0
        (void) udev_watch_clear_by_wd(dev, dirfd, wd);
563
564
0
        xsprintf(wd_str, "%d", wd);
565
566
        /* 4. Create new symlinks */
567
0
        if (symlinkat(wd_str, dirfd, id) < 0) {
568
0
                r = log_device_debug_errno(dev, errno, "Failed to create symlink '/run/udev/watch/%s' to '%s': %m", id, wd_str);
569
0
                goto on_failure;
570
0
        }
571
572
0
        if (symlinkat(id, dirfd, wd_str) < 0) {
573
                /* Possibly, the watch handle is previously assigned to another device, and udev_watch_end()
574
                 * is not called for the device yet. */
575
0
                r = log_device_debug_errno(dev, errno, "Failed to create symlink '/run/udev/watch/%s' to '%s': %m", wd_str, id);
576
0
                goto on_failure;
577
0
        }
578
579
0
        return 0;
580
581
0
on_failure:
582
0
        (void) unlinkat(dirfd, id, 0);
583
0
        (void) inotify_rm_watch(manager->inotify_fd, wd);
584
0
        return r;
585
0
}
586
587
0
int manager_remove_watch(Manager *manager, sd_device *dev) {
588
0
        _cleanup_close_ int dirfd = -EBADF;
589
0
        int wd, r;
590
591
0
        assert(manager);
592
0
        assert(dev);
593
594
0
        dirfd = RET_NERRNO(open("/run/udev/watch", O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW | O_RDONLY));
595
0
        if (dirfd == -ENOENT)
596
0
                return 0;
597
0
        if (dirfd < 0)
598
0
                return log_device_debug_errno(dev, dirfd, "Failed to open %s: %m", "/run/udev/watch/");
599
600
        /* First, clear symlinks. */
601
0
        r = udev_watch_clear(dev, dirfd, &wd);
602
0
        if (r <= 0)
603
0
                return r;
604
605
        /* Then, remove inotify watch. */
606
0
        log_device_debug(dev, "Removing watch handle %i.", wd);
607
0
        (void) inotify_rm_watch(manager->inotify_fd, wd);
608
609
0
        return 0;
610
0
}
611
612
0
static int on_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
613
0
        UdevWorker *worker = ASSERT_PTR(userdata);
614
615
0
        if (!si_code_from_process(si->ssi_code)) {
616
0
                log_debug("Received SIGUSR1 with unexpected .si_code %i, ignoring.", si->ssi_code);
617
0
                return 0;
618
0
        }
619
620
0
        if ((pid_t) si->ssi_pid != worker->manager_pid) {
621
0
                log_debug("Received SIGUSR1 from unexpected process [%"PRIu32"], ignoring.", si->ssi_pid);
622
0
                return 0;
623
0
        }
624
625
0
        return sd_event_exit(sd_event_source_get_event(s), 0);
626
0
}
627
628
0
static int notify_and_wait_signal(UdevWorker *worker, sd_device *dev, const char *msg) {
629
0
        int r;
630
631
0
        assert(worker);
632
0
        assert(dev);
633
0
        assert(msg);
634
635
0
        if (sd_device_get_devname(dev, NULL) < 0)
636
0
                return 0;
637
638
0
        _cleanup_(sd_event_unrefp) sd_event *e = NULL;
639
0
        r = sd_event_new(&e);
640
0
        if (r < 0)
641
0
                return r;
642
643
0
        r = sd_event_add_signal(e, /* ret = */ NULL, SIGUSR1 | SD_EVENT_SIGNAL_PROCMASK, on_sigusr1, worker);
644
0
        if (r < 0)
645
0
                return r;
646
647
0
        r = sd_notify(/* unset_environment = */ false, msg);
648
0
        if (r <= 0)
649
0
                return r;
650
651
0
        return sd_event_loop(e);
652
0
}
653
654
0
int udev_watch_begin(UdevWorker *worker, sd_device *dev) {
655
0
        assert(worker);
656
0
        assert(dev);
657
658
0
        if (device_for_action(dev, SD_DEVICE_REMOVE))
659
0
                return 0;
660
661
0
        return notify_and_wait_signal(worker, dev, "INOTIFY_WATCH_ADD=1");
662
0
}
663
664
0
int udev_watch_end(UdevWorker *worker, sd_device *dev) {
665
0
        assert(worker);
666
0
        assert(dev);
667
668
0
        return notify_and_wait_signal(worker, dev, "INOTIFY_WATCH_REMOVE=1");
669
0
}