]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <poll.h> | |
4 | ||
5 | #include "libudev.h" | |
6 | #include "sd-device.h" | |
7 | ||
8 | #include "alloc-util.h" | |
9 | #include "device-monitor-private.h" | |
10 | #include "errno-util.h" | |
11 | #include "io-util.h" | |
12 | #include "libudev-device-internal.h" | |
13 | #include "string-util.h" | |
14 | ||
15 | /** | |
16 | * SECTION:libudev-monitor | |
17 | * @short_description: device event source | |
18 | * | |
19 | * Connects to a device event source. | |
20 | */ | |
21 | ||
22 | /** | |
23 | * udev_monitor: | |
24 | * | |
25 | * Opaque object handling an event source. | |
26 | */ | |
27 | struct udev_monitor { | |
28 | struct udev *udev; | |
29 | unsigned n_ref; | |
30 | sd_device_monitor *monitor; | |
31 | }; | |
32 | ||
33 | static MonitorNetlinkGroup monitor_netlink_group_from_string(const char *name) { | |
34 | if (!name) | |
35 | return MONITOR_GROUP_NONE; | |
36 | if (streq(name, "udev")) | |
37 | return MONITOR_GROUP_UDEV; | |
38 | if (streq(name, "kernel")) | |
39 | return MONITOR_GROUP_KERNEL; | |
40 | return _MONITOR_NETLINK_GROUP_INVALID; | |
41 | } | |
42 | ||
43 | /** | |
44 | * udev_monitor_new_from_netlink: | |
45 | * @udev: udev library context | |
46 | * @name: name of event source | |
47 | * | |
48 | * Create new udev monitor and connect to a specified event | |
49 | * source. Valid sources identifiers are "udev" and "kernel". | |
50 | * | |
51 | * Applications should usually not connect directly to the | |
52 | * "kernel" events, because the devices might not be usable | |
53 | * at that time, before udev has configured them, and created | |
54 | * device nodes. Accessing devices at the same time as udev, | |
55 | * might result in unpredictable behavior. The "udev" events | |
56 | * are sent out after udev has finished its event processing, | |
57 | * all rules have been processed, and needed device nodes are | |
58 | * created. | |
59 | * | |
60 | * The initial refcount is 1, and needs to be decremented to | |
61 | * release the resources of the udev monitor. | |
62 | * | |
63 | * Returns: a new udev monitor, or #NULL, in case of an error | |
64 | **/ | |
65 | _public_ struct udev_monitor* udev_monitor_new_from_netlink(struct udev *udev, const char *name) { | |
66 | _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; | |
67 | struct udev_monitor *udev_monitor; | |
68 | MonitorNetlinkGroup g; | |
69 | int r; | |
70 | ||
71 | g = monitor_netlink_group_from_string(name); | |
72 | if (g < 0) | |
73 | return_with_errno(NULL, EINVAL); | |
74 | ||
75 | r = device_monitor_new_full(&m, g, -EBADF); | |
76 | if (r < 0) | |
77 | return_with_errno(NULL, r); | |
78 | ||
79 | udev_monitor = new(struct udev_monitor, 1); | |
80 | if (!udev_monitor) | |
81 | return_with_errno(NULL, ENOMEM); | |
82 | ||
83 | *udev_monitor = (struct udev_monitor) { | |
84 | .udev = udev, | |
85 | .n_ref = 1, | |
86 | .monitor = TAKE_PTR(m), | |
87 | }; | |
88 | ||
89 | return udev_monitor; | |
90 | } | |
91 | ||
92 | /** | |
93 | * udev_monitor_filter_update: | |
94 | * @udev_monitor: monitor | |
95 | * | |
96 | * Update the installed socket filter. This is only needed, | |
97 | * if the filter was removed or changed. | |
98 | * | |
99 | * Returns: 0 on success, otherwise a negative error value. | |
100 | */ | |
101 | _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) { | |
102 | assert_return(udev_monitor, -EINVAL); | |
103 | ||
104 | return sd_device_monitor_filter_update(udev_monitor->monitor); | |
105 | } | |
106 | ||
107 | /** | |
108 | * udev_monitor_enable_receiving: | |
109 | * @udev_monitor: the monitor which should receive events | |
110 | * | |
111 | * Deprecated, and alias of udev_monitor_filter_update(). | |
112 | * | |
113 | * Returns: 0 on success, otherwise a negative error value. | |
114 | */ | |
115 | _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { | |
116 | return udev_monitor_filter_update(udev_monitor); | |
117 | } | |
118 | ||
119 | /** | |
120 | * udev_monitor_set_receive_buffer_size: | |
121 | * @udev_monitor: the monitor which should receive events | |
122 | * @size: the size in bytes | |
123 | * | |
124 | * Set the size of the kernel socket buffer. This call needs the | |
125 | * appropriate privileges to succeed. | |
126 | * | |
127 | * Returns: 0 on success, otherwise -1 on error. | |
128 | */ | |
129 | _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) { | |
130 | assert_return(udev_monitor, -EINVAL); | |
131 | ||
132 | return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size); | |
133 | } | |
134 | ||
135 | static struct udev_monitor* udev_monitor_free(struct udev_monitor *udev_monitor) { | |
136 | assert(udev_monitor); | |
137 | ||
138 | sd_device_monitor_unref(udev_monitor->monitor); | |
139 | return mfree(udev_monitor); | |
140 | } | |
141 | ||
142 | /** | |
143 | * udev_monitor_ref: | |
144 | * @udev_monitor: udev monitor | |
145 | * | |
146 | * Take a reference of a udev monitor. | |
147 | * | |
148 | * Returns: the passed udev monitor | |
149 | **/ | |
150 | ||
151 | /** | |
152 | * udev_monitor_unref: | |
153 | * @udev_monitor: udev monitor | |
154 | * | |
155 | * Drop a reference of a udev monitor. If the refcount reaches zero, | |
156 | * the bound socket will be closed, and the resources of the monitor | |
157 | * will be released. | |
158 | * | |
159 | * Returns: #NULL | |
160 | **/ | |
161 | DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free); | |
162 | ||
163 | /** | |
164 | * udev_monitor_get_udev: | |
165 | * @udev_monitor: udev monitor | |
166 | * | |
167 | * Retrieve the udev library context the monitor was created with. | |
168 | * | |
169 | * Returns: the udev library context | |
170 | **/ | |
171 | _public_ struct udev* udev_monitor_get_udev(struct udev_monitor *udev_monitor) { | |
172 | assert_return(udev_monitor, NULL); | |
173 | ||
174 | return udev_monitor->udev; | |
175 | } | |
176 | ||
177 | /** | |
178 | * udev_monitor_get_fd: | |
179 | * @udev_monitor: udev monitor | |
180 | * | |
181 | * Retrieve the socket file descriptor associated with the monitor. | |
182 | * | |
183 | * Returns: the socket file descriptor | |
184 | **/ | |
185 | _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { | |
186 | assert_return(udev_monitor, -EINVAL); | |
187 | ||
188 | return sd_device_monitor_get_fd(udev_monitor->monitor); | |
189 | } | |
190 | ||
191 | static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) { | |
192 | int r; | |
193 | ||
194 | assert(udev_monitor); | |
195 | assert(ret); | |
196 | ||
197 | for (;;) { | |
198 | /* r == 0 means a device is received but it does not pass the current filter. */ | |
199 | r = sd_device_monitor_receive(udev_monitor->monitor, ret); | |
200 | if (r != 0) | |
201 | return r; | |
202 | ||
203 | for (;;) { | |
204 | /* Wait for next message */ | |
205 | r = fd_wait_for_event(sd_device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0); | |
206 | if (r == -EINTR) | |
207 | continue; | |
208 | if (r < 0) | |
209 | return r; | |
210 | if (r == 0) | |
211 | return -EAGAIN; | |
212 | ||
213 | /* Receive next message */ | |
214 | break; | |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | /** | |
220 | * udev_monitor_receive_device: | |
221 | * @udev_monitor: udev monitor | |
222 | * | |
223 | * Receive data from the udev monitor socket, allocate a new udev | |
224 | * device, fill in the received data, and return the device. | |
225 | * | |
226 | * Only socket connections with uid=0 are accepted. | |
227 | * | |
228 | * The monitor socket is by default set to NONBLOCK. A variant of poll() on | |
229 | * the file descriptor returned by udev_monitor_get_fd() should to be used to | |
230 | * wake up when new devices arrive, or alternatively the file descriptor | |
231 | * switched into blocking mode. | |
232 | * | |
233 | * The initial refcount is 1, and needs to be decremented to | |
234 | * release the resources of the udev device. | |
235 | * | |
236 | * Returns: a new udev device, or #NULL, in case of an error | |
237 | **/ | |
238 | _public_ struct udev_device* udev_monitor_receive_device(struct udev_monitor *udev_monitor) { | |
239 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; | |
240 | int r; | |
241 | ||
242 | assert_return(udev_monitor, NULL); | |
243 | ||
244 | r = udev_monitor_receive_sd_device(udev_monitor, &device); | |
245 | if (r < 0) | |
246 | return_with_errno(NULL, r); | |
247 | ||
248 | return udev_device_new(udev_monitor->udev, device); | |
249 | } | |
250 | ||
251 | /** | |
252 | * udev_monitor_filter_add_match_subsystem_devtype: | |
253 | * @udev_monitor: the monitor | |
254 | * @subsystem: the subsystem value to match the incoming devices against | |
255 | * @devtype: the devtype value to match the incoming devices against | |
256 | * | |
257 | * This filter is efficiently executed inside the kernel, and libudev subscribers | |
258 | * will usually not be woken up for devices which do not match. | |
259 | * | |
260 | * The filter must be installed before the monitor is switched to listening mode. | |
261 | * | |
262 | * Returns: 0 on success, otherwise a negative error value. | |
263 | */ | |
264 | _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) { | |
265 | int r; | |
266 | ||
267 | assert_return(udev_monitor, -EINVAL); | |
268 | ||
269 | r = sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype); | |
270 | return r < 0 ? r : 0; | |
271 | } | |
272 | ||
273 | /** | |
274 | * udev_monitor_filter_add_match_tag: | |
275 | * @udev_monitor: the monitor | |
276 | * @tag: the name of a tag | |
277 | * | |
278 | * This filter is efficiently executed inside the kernel, and libudev subscribers | |
279 | * will usually not be woken up for devices which do not match. | |
280 | * | |
281 | * The filter must be installed before the monitor is switched to listening mode. | |
282 | * | |
283 | * Returns: 0 on success, otherwise a negative error value. | |
284 | */ | |
285 | _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) { | |
286 | int r; | |
287 | ||
288 | assert_return(udev_monitor, -EINVAL); | |
289 | ||
290 | r = sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag); | |
291 | return r < 0 ? r : 0; | |
292 | } | |
293 | ||
294 | /** | |
295 | * udev_monitor_filter_remove: | |
296 | * @udev_monitor: monitor | |
297 | * | |
298 | * Remove all filters from monitor. | |
299 | * | |
300 | * Returns: 0 on success, otherwise a negative error value. | |
301 | */ | |
302 | _public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { | |
303 | assert_return(udev_monitor, -EINVAL); | |
304 | ||
305 | return sd_device_monitor_filter_remove(udev_monitor->monitor); | |
306 | } |