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