]>
Commit | Line | Data |
---|---|---|
e7145211 | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
bd284db1 | 2 | /* |
810adae9 LP |
3 | * Copyright © 2009 Canonical Ltd. |
4 | * Copyright © 2009 Scott James Remnant <scott@netsplit.com> | |
bd284db1 SJR |
5 | */ |
6 | ||
bd284db1 | 7 | #include <sys/inotify.h> |
cf0fbc49 | 8 | #include <unistd.h> |
bd284db1 | 9 | |
e7aa9512 | 10 | #include "alloc-util.h" |
70068602 | 11 | #include "device-private.h" |
4d04259d | 12 | #include "device-util.h" |
8fb3f009 | 13 | #include "dirent-util.h" |
e7aa9512 | 14 | #include "fs-util.h" |
70068602 | 15 | #include "mkdir.h" |
d054f0a4 | 16 | #include "stdio-util.h" |
70068602 | 17 | #include "udev-watch.h" |
bd284db1 | 18 | |
1e03b754 | 19 | static int inotify_fd = -1; |
bd284db1 SJR |
20 | |
21 | /* inotify descriptor, will be shared with rules directory; | |
22 | * set to cloexec since we need our children to be able to add | |
70068602 | 23 | * watches for us. */ |
2024ed61 | 24 | int udev_watch_init(void) { |
912541b0 KS |
25 | inotify_fd = inotify_init1(IN_CLOEXEC); |
26 | if (inotify_fd < 0) | |
b7759e04 | 27 | return -errno; |
70068602 | 28 | |
912541b0 | 29 | return inotify_fd; |
bd284db1 SJR |
30 | } |
31 | ||
70068602 YW |
32 | /* Move any old watches directory out of the way, and then restore the watches. */ |
33 | int udev_watch_restore(void) { | |
34 | struct dirent *ent; | |
35 | DIR *dir; | |
36 | int r; | |
912541b0 | 37 | |
70068602 | 38 | if (inotify_fd < 0) |
886cf317 ZJS |
39 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
40 | "Invalid inotify descriptor."); | |
912541b0 | 41 | |
70068602 YW |
42 | if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) { |
43 | if (errno != ENOENT) | |
cc0bf5e1 | 44 | return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m"); |
912541b0 | 45 | |
70068602 YW |
46 | return 0; |
47 | } | |
912541b0 | 48 | |
70068602 YW |
49 | dir = opendir("/run/udev/watch.old"); |
50 | if (!dir) | |
cc0bf5e1 | 51 | return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m"); |
70068602 YW |
52 | |
53 | FOREACH_DIRENT_ALL(ent, dir, break) { | |
54 | _cleanup_(sd_device_unrefp) sd_device *dev = NULL; | |
e7aa9512 | 55 | _cleanup_free_ char *device = NULL; |
70068602 YW |
56 | |
57 | if (ent->d_name[0] == '.') | |
58 | continue; | |
59 | ||
e7aa9512 YW |
60 | r = readlinkat_malloc(dirfd(dir), ent->d_name, &device); |
61 | if (r < 0) { | |
cc0bf5e1 | 62 | log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name); |
70068602 YW |
63 | goto unlink; |
64 | } | |
912541b0 | 65 | |
70068602 YW |
66 | r = sd_device_new_from_device_id(&dev, device); |
67 | if (r < 0) { | |
cc0bf5e1 | 68 | log_debug_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device); |
70068602 YW |
69 | goto unlink; |
70 | } | |
912541b0 | 71 | |
4d04259d | 72 | log_device_debug(dev, "Restoring old watch"); |
70068602 YW |
73 | (void) udev_watch_begin(dev); |
74 | unlink: | |
75 | (void) unlinkat(dirfd(dir), ent->d_name, 0); | |
76 | } | |
bd284db1 | 77 | |
70068602 YW |
78 | (void) closedir(dir); |
79 | (void) rmdir("/run/udev/watch.old"); | |
bd284db1 | 80 | |
70068602 | 81 | return 0; |
bd284db1 SJR |
82 | } |
83 | ||
70068602 YW |
84 | int udev_watch_begin(sd_device *dev) { |
85 | char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; | |
86 | const char *devnode, *id_filename; | |
87 | int wd, r; | |
912541b0 KS |
88 | |
89 | if (inotify_fd < 0) | |
886cf317 ZJS |
90 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
91 | "Invalid inotify descriptor."); | |
70068602 YW |
92 | |
93 | r = sd_device_get_devname(dev, &devnode); | |
94 | if (r < 0) | |
4d04259d | 95 | return log_device_error_errno(dev, r, "Failed to get device name: %m"); |
70068602 | 96 | |
4d04259d | 97 | log_device_debug(dev, "Adding watch on '%s'", devnode); |
70068602 YW |
98 | wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE); |
99 | if (wd < 0) | |
7fe0d0d5 ZJS |
100 | return log_device_full(dev, |
101 | errno == ENOENT ? LOG_DEBUG : LOG_ERR, | |
102 | errno, | |
103 | "Failed to add device '%s' to watch: %m", devnode); | |
70068602 YW |
104 | |
105 | device_set_watch_handle(dev, wd); | |
912541b0 | 106 | |
d054f0a4 | 107 | xsprintf(filename, "/run/udev/watch/%d", wd); |
70068602 | 108 | r = mkdir_parents(filename, 0755); |
6bb2f0a0 | 109 | if (r < 0) |
4d04259d | 110 | return log_device_error_errno(dev, r, "Failed to create parent directory of '%s': %m", filename); |
70068602 YW |
111 | (void) unlink(filename); |
112 | ||
113 | r = device_get_id_filename(dev, &id_filename); | |
114 | if (r < 0) | |
4d04259d | 115 | return log_device_error_errno(dev, r, "Failed to get device id-filename: %m"); |
70068602 YW |
116 | |
117 | if (symlink(id_filename, filename) < 0) | |
4d04259d | 118 | return log_device_error_errno(dev, errno, "Failed to create symlink %s: %m", filename); |
912541b0 | 119 | |
70068602 | 120 | return 0; |
bd284db1 SJR |
121 | } |
122 | ||
70068602 YW |
123 | int udev_watch_end(sd_device *dev) { |
124 | char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; | |
70068602 | 125 | int wd, r; |
bd284db1 | 126 | |
912541b0 | 127 | if (inotify_fd < 0) |
d6d4961b | 128 | return 0; /* Nothing to do. */ |
03e0170d | 129 | |
70068602 YW |
130 | r = device_get_watch_handle(dev, &wd); |
131 | if (r == -ENOENT) | |
132 | return 0; | |
133 | if (r < 0) | |
cc0bf5e1 | 134 | return log_device_debug_errno(dev, r, "Failed to get watch handle, ignoring: %m"); |
70068602 | 135 | |
4d04259d | 136 | log_device_debug(dev, "Removing watch"); |
70068602 | 137 | (void) inotify_rm_watch(inotify_fd, wd); |
bd284db1 | 138 | |
d054f0a4 | 139 | xsprintf(filename, "/run/udev/watch/%d", wd); |
70068602 | 140 | (void) unlink(filename); |
047f88bc | 141 | |
70068602 YW |
142 | device_set_watch_handle(dev, -1); |
143 | ||
144 | return 0; | |
bd284db1 SJR |
145 | } |
146 | ||
70068602 | 147 | int udev_watch_lookup(int wd, sd_device **ret) { |
e7aa9512 YW |
148 | char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; |
149 | _cleanup_free_ char *device = NULL; | |
70068602 YW |
150 | int r; |
151 | ||
152 | assert(ret); | |
153 | ||
154 | if (inotify_fd < 0) | |
886cf317 ZJS |
155 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
156 | "Invalid inotify descriptor."); | |
912541b0 | 157 | |
70068602 | 158 | if (wd < 0) |
886cf317 ZJS |
159 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
160 | "Invalid watch handle."); | |
912541b0 | 161 | |
d054f0a4 | 162 | xsprintf(filename, "/run/udev/watch/%d", wd); |
e7aa9512 | 163 | r = readlink_malloc(filename, &device); |
7fe3324c | 164 | if (r == -ENOENT) |
70068602 | 165 | return 0; |
7fe3324c YW |
166 | if (r < 0) |
167 | return log_debug_errno(r, "Failed to read link '%s': %m", filename); | |
912541b0 | 168 | |
70068602 | 169 | r = sd_device_new_from_device_id(ret, device); |
7fe3324c YW |
170 | if (r == -ENODEV) |
171 | return 0; | |
70068602 | 172 | if (r < 0) |
7fe3324c | 173 | return log_debug_errno(r, "Failed to create sd_device object for '%s': %m", device); |
70068602 | 174 | |
7fe3324c | 175 | return 1; |
bd284db1 | 176 | } |