File: | build-scan/../src/libudev/libudev-monitor.c |
Warning: | line 149, column 45 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <linux1/filter.h> | |||
5 | #include <linux1/netlink.h> | |||
6 | #include <poll.h> | |||
7 | #include <stddef.h> | |||
8 | #include <stdio.h> | |||
9 | #include <stdlib.h> | |||
10 | #include <string.h> | |||
11 | #include <sys/socket.h> | |||
12 | #include <unistd.h> | |||
13 | ||||
14 | #include "libudev.h" | |||
15 | ||||
16 | #include "alloc-util.h" | |||
17 | #include "fd-util.h" | |||
18 | #include "fileio.h" | |||
19 | #include "format-util.h" | |||
20 | #include "libudev-private.h" | |||
21 | #include "missing.h" | |||
22 | #include "mount-util.h" | |||
23 | #include "socket-util.h" | |||
24 | #include "string-util.h" | |||
25 | ||||
26 | /** | |||
27 | * SECTION:libudev-monitor | |||
28 | * @short_description: device event source | |||
29 | * | |||
30 | * Connects to a device event source. | |||
31 | */ | |||
32 | ||||
33 | /** | |||
34 | * udev_monitor: | |||
35 | * | |||
36 | * Opaque object handling an event source. | |||
37 | */ | |||
38 | struct udev_monitor { | |||
39 | struct udev *udev; | |||
40 | int refcount; | |||
41 | int sock; | |||
42 | union sockaddr_union snl; | |||
43 | union sockaddr_union snl_trusted_sender; | |||
44 | union sockaddr_union snl_destination; | |||
45 | socklen_t addrlen; | |||
46 | struct udev_list filter_subsystem_list; | |||
47 | struct udev_list filter_tag_list; | |||
48 | bool_Bool bound; | |||
49 | }; | |||
50 | ||||
51 | enum udev_monitor_netlink_group { | |||
52 | UDEV_MONITOR_NONE, | |||
53 | UDEV_MONITOR_KERNEL, | |||
54 | UDEV_MONITOR_UDEV, | |||
55 | }; | |||
56 | ||||
57 | #define UDEV_MONITOR_MAGIC0xfeedcafe 0xfeedcafe | |||
58 | struct udev_monitor_netlink_header { | |||
59 | /* "libudev" prefix to distinguish libudev and kernel messages */ | |||
60 | char prefix[8]; | |||
61 | /* | |||
62 | * magic to protect against daemon <-> library message format mismatch | |||
63 | * used in the kernel from socket filter rules; needs to be stored in network order | |||
64 | */ | |||
65 | unsigned int magic; | |||
66 | /* total length of header structure known to the sender */ | |||
67 | unsigned int header_size; | |||
68 | /* properties string buffer */ | |||
69 | unsigned int properties_off; | |||
70 | unsigned int properties_len; | |||
71 | /* | |||
72 | * hashes of primary device properties strings, to let libudev subscribers | |||
73 | * use in-kernel socket filters; values need to be stored in network order | |||
74 | */ | |||
75 | unsigned int filter_subsystem_hash; | |||
76 | unsigned int filter_devtype_hash; | |||
77 | unsigned int filter_tag_bloom_hi; | |||
78 | unsigned int filter_tag_bloom_lo; | |||
79 | }; | |||
80 | ||||
81 | static struct udev_monitor *udev_monitor_new(struct udev *udev) { | |||
82 | struct udev_monitor *udev_monitor; | |||
83 | ||||
84 | udev_monitor = new0(struct udev_monitor, 1)((struct udev_monitor*) calloc((1), sizeof(struct udev_monitor ))); | |||
85 | if (udev_monitor == NULL((void*)0)) { | |||
86 | errno(*__errno_location ()) = ENOMEM12; | |||
87 | return NULL((void*)0); | |||
88 | } | |||
89 | udev_monitor->refcount = 1; | |||
90 | udev_monitor->udev = udev; | |||
91 | udev_list_init(udev, &udev_monitor->filter_subsystem_list, false0); | |||
92 | udev_list_init(udev, &udev_monitor->filter_tag_list, true1); | |||
93 | return udev_monitor; | |||
94 | } | |||
95 | ||||
96 | /* we consider udev running when /dev is on devtmpfs */ | |||
97 | static bool_Bool udev_has_devtmpfs(struct udev *udev) { | |||
98 | ||||
99 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
100 | char line[LINE_MAX2048], *e; | |||
101 | int mount_id, r; | |||
102 | ||||
103 | r = path_get_mnt_id("/dev", &mount_id); | |||
104 | if (r < 0) { | |||
105 | if (r != -EOPNOTSUPP95) | |||
106 | log_debug_errno(r, "name_to_handle_at on /dev: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 106, __func__, "name_to_handle_at on /dev: %m" ) : -abs(_e); }); | |||
107 | ||||
108 | return false0; | |||
109 | } | |||
110 | ||||
111 | f = fopen("/proc/self/mountinfo", "re"); | |||
112 | if (!f) | |||
113 | return false0; | |||
114 | ||||
115 | FOREACH_LINE(line, f, return false)for (;;) if (!fgets(line, sizeof(line), f)) { if (ferror(f)) { return 0; } break; } else { | |||
116 | int mid; | |||
117 | ||||
118 | if (sscanf(line, "%i", &mid) != 1) | |||
119 | continue; | |||
120 | ||||
121 | if (mid != mount_id) | |||
122 | continue; | |||
123 | ||||
124 | e = strstr(line, " - "); | |||
125 | if (!e) | |||
126 | continue; | |||
127 | ||||
128 | /* accept any name that starts with the currently expected type */ | |||
129 | if (startswith(e + 3, "devtmpfs")) | |||
130 | return true1; | |||
131 | } | |||
132 | ||||
133 | return false0; | |||
134 | } | |||
135 | ||||
136 | static void monitor_set_nl_address(struct udev_monitor *udev_monitor) { | |||
137 | union sockaddr_union snl; | |||
138 | socklen_t addrlen; | |||
139 | int r; | |||
140 | ||||
141 | assert(udev_monitor)do { if ((__builtin_expect(!!(!(udev_monitor)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("udev_monitor"), "../src/libudev/libudev-monitor.c" , 141, __PRETTY_FUNCTION__); } while (0); | |||
142 | ||||
143 | /* get the address the kernel has assigned us | |||
144 | * it is usually, but not necessarily the pid | |||
145 | */ | |||
146 | addrlen = sizeof(struct sockaddr_nl); | |||
147 | r = getsockname(udev_monitor->sock, &snl.sa, &addrlen); | |||
148 | if (r >= 0) | |||
149 | udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; | |||
| ||||
150 | } | |||
151 | ||||
152 | struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) { | |||
153 | struct udev_monitor *udev_monitor; | |||
154 | unsigned int group; | |||
155 | ||||
156 | if (udev == NULL((void*)0)) { | |||
157 | errno(*__errno_location ()) = EINVAL22; | |||
158 | return NULL((void*)0); | |||
159 | } | |||
160 | ||||
161 | if (name == NULL((void*)0)) | |||
162 | group = UDEV_MONITOR_NONE; | |||
163 | else if (streq(name, "udev")(strcmp((name),("udev")) == 0)) { | |||
164 | /* | |||
165 | * We do not support subscribing to uevents if no instance of | |||
166 | * udev is running. Uevents would otherwise broadcast the | |||
167 | * processing data of the host into containers, which is not | |||
168 | * desired. | |||
169 | * | |||
170 | * Containers will currently not get any udev uevents, until | |||
171 | * a supporting infrastructure is available. | |||
172 | * | |||
173 | * We do not set a netlink multicast group here, so the socket | |||
174 | * will not receive any messages. | |||
175 | */ | |||
176 | if (access("/run/udev/control", F_OK0) < 0 && !udev_has_devtmpfs(udev)) { | |||
177 | log_debug("the udev service seems not to be active, disable the monitor")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 177, __func__, "the udev service seems not to be active, disable the monitor" ) : -abs(_e); }); | |||
178 | group = UDEV_MONITOR_NONE; | |||
179 | } else | |||
180 | group = UDEV_MONITOR_UDEV; | |||
181 | } else if (streq(name, "kernel")(strcmp((name),("kernel")) == 0)) | |||
182 | group = UDEV_MONITOR_KERNEL; | |||
183 | else { | |||
184 | errno(*__errno_location ()) = EINVAL22; | |||
185 | return NULL((void*)0); | |||
186 | } | |||
187 | ||||
188 | udev_monitor = udev_monitor_new(udev); | |||
189 | if (udev_monitor == NULL((void*)0)) | |||
190 | return NULL((void*)0); | |||
191 | ||||
192 | if (fd < 0) { | |||
193 | udev_monitor->sock = socket(PF_NETLINK16, SOCK_RAWSOCK_RAW|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT15); | |||
194 | if (udev_monitor->sock < 0) { | |||
195 | log_debug_errno(errno, "error getting socket: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libudev/libudev-monitor.c", 195, __func__, "error getting socket: %m") : -abs(_e); }); | |||
196 | return mfree(udev_monitor); | |||
197 | } | |||
198 | } else { | |||
199 | udev_monitor->bound = true1; | |||
200 | udev_monitor->sock = fd; | |||
201 | monitor_set_nl_address(udev_monitor); | |||
202 | } | |||
203 | ||||
204 | udev_monitor->snl.nl.nl_family = AF_NETLINK16; | |||
205 | udev_monitor->snl.nl.nl_groups = group; | |||
206 | ||||
207 | /* default destination for sending */ | |||
208 | udev_monitor->snl_destination.nl.nl_family = AF_NETLINK16; | |||
209 | udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; | |||
210 | ||||
211 | return udev_monitor; | |||
212 | } | |||
213 | ||||
214 | /** | |||
215 | * udev_monitor_new_from_netlink: | |||
216 | * @udev: udev library context | |||
217 | * @name: name of event source | |||
218 | * | |||
219 | * Create new udev monitor and connect to a specified event | |||
220 | * source. Valid sources identifiers are "udev" and "kernel". | |||
221 | * | |||
222 | * Applications should usually not connect directly to the | |||
223 | * "kernel" events, because the devices might not be useable | |||
224 | * at that time, before udev has configured them, and created | |||
225 | * device nodes. Accessing devices at the same time as udev, | |||
226 | * might result in unpredictable behavior. The "udev" events | |||
227 | * are sent out after udev has finished its event processing, | |||
228 | * all rules have been processed, and needed device nodes are | |||
229 | * created. | |||
230 | * | |||
231 | * The initial refcount is 1, and needs to be decremented to | |||
232 | * release the resources of the udev monitor. | |||
233 | * | |||
234 | * Returns: a new udev monitor, or #NULL, in case of an error | |||
235 | **/ | |||
236 | _public___attribute__ ((visibility("default"))) struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) { | |||
237 | return udev_monitor_new_from_netlink_fd(udev, name, -1); | |||
238 | } | |||
239 | ||||
240 | static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, | |||
241 | unsigned short code, unsigned int data) | |||
242 | { | |||
243 | struct sock_filter *ins = &inss[*i]; | |||
244 | ||||
245 | ins->code = code; | |||
246 | ins->k = data; | |||
247 | (*i)++; | |||
248 | } | |||
249 | ||||
250 | static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, | |||
251 | unsigned short code, unsigned int data, | |||
252 | unsigned short jt, unsigned short jf) | |||
253 | { | |||
254 | struct sock_filter *ins = &inss[*i]; | |||
255 | ||||
256 | ins->code = code; | |||
257 | ins->jt = jt; | |||
258 | ins->jf = jf; | |||
259 | ins->k = data; | |||
260 | (*i)++; | |||
261 | } | |||
262 | ||||
263 | /** | |||
264 | * udev_monitor_filter_update: | |||
265 | * @udev_monitor: monitor | |||
266 | * | |||
267 | * Update the installed socket filter. This is only needed, | |||
268 | * if the filter was removed or changed. | |||
269 | * | |||
270 | * Returns: 0 on success, otherwise a negative error value. | |||
271 | */ | |||
272 | _public___attribute__ ((visibility("default"))) int udev_monitor_filter_update(struct udev_monitor *udev_monitor) | |||
273 | { | |||
274 | struct sock_filter ins[512]; | |||
275 | struct sock_fprog filter; | |||
276 | unsigned int i; | |||
277 | struct udev_list_entry *list_entry; | |||
278 | int err; | |||
279 | ||||
280 | if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL((void*)0) && | |||
281 | udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL((void*)0)) | |||
282 | return 0; | |||
283 | ||||
284 | memzero(ins, sizeof(ins))({ size_t _l_ = (sizeof(ins)); void *_x_ = (ins); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }); | |||
285 | i = 0; | |||
286 | ||||
287 | /* load magic in A */ | |||
288 | bpf_stmt(ins, &i, BPF_LD0x00|BPF_W0x00|BPF_ABS0x20, offsetof(struct udev_monitor_netlink_header, magic)__builtin_offsetof(struct udev_monitor_netlink_header, magic)); | |||
289 | /* jump if magic matches */ | |||
290 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, UDEV_MONITOR_MAGIC0xfeedcafe, 1, 0); | |||
291 | /* wrong magic, pass packet */ | |||
292 | bpf_stmt(ins, &i, BPF_RET0x06|BPF_K0x00, 0xffffffff); | |||
293 | ||||
294 | if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL((void*)0)) { | |||
295 | int tag_matches; | |||
296 | ||||
297 | /* count tag matches, to calculate end of tag match block */ | |||
298 | tag_matches = 0; | |||
299 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))for (list_entry = udev_list_get_entry(&udev_monitor->filter_tag_list ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) | |||
300 | tag_matches++; | |||
301 | ||||
302 | /* add all tags matches */ | |||
303 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))for (list_entry = udev_list_get_entry(&udev_monitor->filter_tag_list ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) { | |||
304 | uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry)); | |||
305 | uint32_t tag_bloom_hi = tag_bloom_bits >> 32; | |||
306 | uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; | |||
307 | ||||
308 | /* load device bloom bits in A */ | |||
309 | bpf_stmt(ins, &i, BPF_LD0x00|BPF_W0x00|BPF_ABS0x20, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi)__builtin_offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi )); | |||
310 | /* clear bits (tag bits & bloom bits) */ | |||
311 | bpf_stmt(ins, &i, BPF_ALU0x04|BPF_AND0x50|BPF_K0x00, tag_bloom_hi); | |||
312 | /* jump to next tag if it does not match */ | |||
313 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, tag_bloom_hi, 0, 3); | |||
314 | ||||
315 | /* load device bloom bits in A */ | |||
316 | bpf_stmt(ins, &i, BPF_LD0x00|BPF_W0x00|BPF_ABS0x20, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo)__builtin_offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo )); | |||
317 | /* clear bits (tag bits & bloom bits) */ | |||
318 | bpf_stmt(ins, &i, BPF_ALU0x04|BPF_AND0x50|BPF_K0x00, tag_bloom_lo); | |||
319 | /* jump behind end of tag match block if tag matches */ | |||
320 | tag_matches--; | |||
321 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, tag_bloom_lo, 1 + (tag_matches * 6), 0); | |||
322 | } | |||
323 | ||||
324 | /* nothing matched, drop packet */ | |||
325 | bpf_stmt(ins, &i, BPF_RET0x06|BPF_K0x00, 0); | |||
326 | } | |||
327 | ||||
328 | /* add all subsystem matches */ | |||
329 | if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL((void*)0)) { | |||
330 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list))for (list_entry = udev_list_get_entry(&udev_monitor->filter_subsystem_list ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) { | |||
331 | unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry)); | |||
332 | ||||
333 | /* load device subsystem value in A */ | |||
334 | bpf_stmt(ins, &i, BPF_LD0x00|BPF_W0x00|BPF_ABS0x20, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash)__builtin_offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash )); | |||
335 | if (udev_list_entry_get_value(list_entry) == NULL((void*)0)) { | |||
336 | /* jump if subsystem does not match */ | |||
337 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, hash, 0, 1); | |||
338 | } else { | |||
339 | /* jump if subsystem does not match */ | |||
340 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, hash, 0, 3); | |||
341 | ||||
342 | /* load device devtype value in A */ | |||
343 | bpf_stmt(ins, &i, BPF_LD0x00|BPF_W0x00|BPF_ABS0x20, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash)__builtin_offsetof(struct udev_monitor_netlink_header, filter_devtype_hash )); | |||
344 | /* jump if value does not match */ | |||
345 | hash = util_string_hash32(udev_list_entry_get_value(list_entry)); | |||
346 | bpf_jmp(ins, &i, BPF_JMP0x05|BPF_JEQ0x10|BPF_K0x00, hash, 0, 1); | |||
347 | } | |||
348 | ||||
349 | /* matched, pass packet */ | |||
350 | bpf_stmt(ins, &i, BPF_RET0x06|BPF_K0x00, 0xffffffff); | |||
351 | ||||
352 | if (i+1 >= ELEMENTSOF(ins)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(ins), typeof(&*(ins))), sizeof(ins)/sizeof((ins)[ 0]), ((void)0)))) | |||
353 | return -E2BIG7; | |||
354 | } | |||
355 | ||||
356 | /* nothing matched, drop packet */ | |||
357 | bpf_stmt(ins, &i, BPF_RET0x06|BPF_K0x00, 0); | |||
358 | } | |||
359 | ||||
360 | /* matched, pass packet */ | |||
361 | bpf_stmt(ins, &i, BPF_RET0x06|BPF_K0x00, 0xffffffff); | |||
362 | ||||
363 | /* install filter */ | |||
364 | memzero(&filter, sizeof(filter))({ size_t _l_ = (sizeof(filter)); void *_x_ = (&filter); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }); | |||
365 | filter.len = i; | |||
366 | filter.filter = ins; | |||
367 | err = setsockopt(udev_monitor->sock, SOL_SOCKET1, SO_ATTACH_FILTER26, &filter, sizeof(filter)); | |||
368 | return err < 0 ? -errno(*__errno_location ()) : 0; | |||
369 | } | |||
370 | ||||
371 | int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) | |||
372 | { | |||
373 | udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; | |||
374 | return 0; | |||
375 | } | |||
376 | ||||
377 | /** | |||
378 | * udev_monitor_enable_receiving: | |||
379 | * @udev_monitor: the monitor which should receive events | |||
380 | * | |||
381 | * Binds the @udev_monitor socket to the event source. | |||
382 | * | |||
383 | * Returns: 0 on success, otherwise a negative error value. | |||
384 | */ | |||
385 | _public___attribute__ ((visibility("default"))) int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) | |||
386 | { | |||
387 | int err = 0; | |||
388 | const int on = 1; | |||
389 | ||||
390 | udev_monitor_filter_update(udev_monitor); | |||
391 | ||||
392 | if (!udev_monitor->bound) { | |||
| ||||
393 | err = bind(udev_monitor->sock, | |||
394 | &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)); | |||
395 | if (err == 0) | |||
396 | udev_monitor->bound = true1; | |||
397 | } | |||
398 | ||||
399 | if (err
| |||
400 | monitor_set_nl_address(udev_monitor); | |||
401 | else | |||
402 | return log_debug_errno(errno, "bind failed: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libudev/libudev-monitor.c", 402, __func__, "bind failed: %m") : -abs(_e); }); | |||
403 | ||||
404 | /* enable receiving of sender credentials */ | |||
405 | err = setsockopt(udev_monitor->sock, SOL_SOCKET1, SO_PASSCRED16, &on, sizeof(on)); | |||
406 | if (err < 0) | |||
407 | log_debug_errno(errno, "setting SO_PASSCRED failed: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libudev/libudev-monitor.c", 407, __func__, "setting SO_PASSCRED failed: %m") : -abs(_e); }); | |||
408 | ||||
409 | return 0; | |||
410 | } | |||
411 | ||||
412 | /** | |||
413 | * udev_monitor_set_receive_buffer_size: | |||
414 | * @udev_monitor: the monitor which should receive events | |||
415 | * @size: the size in bytes | |||
416 | * | |||
417 | * Set the size of the kernel socket buffer. This call needs the | |||
418 | * appropriate privileges to succeed. | |||
419 | * | |||
420 | * Returns: 0 on success, otherwise -1 on error. | |||
421 | */ | |||
422 | _public___attribute__ ((visibility("default"))) int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) | |||
423 | { | |||
424 | if (udev_monitor == NULL((void*)0)) | |||
425 | return -EINVAL22; | |||
426 | if (setsockopt(udev_monitor->sock, SOL_SOCKET1, SO_RCVBUFFORCE33, &size, sizeof(size)) < 0) | |||
427 | return -errno(*__errno_location ()); | |||
428 | ||||
429 | return 0; | |||
430 | } | |||
431 | ||||
432 | int udev_monitor_disconnect(struct udev_monitor *udev_monitor) | |||
433 | { | |||
434 | int err; | |||
435 | ||||
436 | err = close(udev_monitor->sock); | |||
437 | udev_monitor->sock = -1; | |||
438 | return err < 0 ? -errno(*__errno_location ()) : 0; | |||
439 | } | |||
440 | ||||
441 | /** | |||
442 | * udev_monitor_ref: | |||
443 | * @udev_monitor: udev monitor | |||
444 | * | |||
445 | * Take a reference of a udev monitor. | |||
446 | * | |||
447 | * Returns: the passed udev monitor | |||
448 | **/ | |||
449 | _public___attribute__ ((visibility("default"))) struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) | |||
450 | { | |||
451 | if (udev_monitor == NULL((void*)0)) | |||
452 | return NULL((void*)0); | |||
453 | udev_monitor->refcount++; | |||
454 | return udev_monitor; | |||
455 | } | |||
456 | ||||
457 | /** | |||
458 | * udev_monitor_unref: | |||
459 | * @udev_monitor: udev monitor | |||
460 | * | |||
461 | * Drop a reference of a udev monitor. If the refcount reaches zero, | |||
462 | * the bound socket will be closed, and the resources of the monitor | |||
463 | * will be released. | |||
464 | * | |||
465 | * Returns: #NULL | |||
466 | **/ | |||
467 | _public___attribute__ ((visibility("default"))) struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) | |||
468 | { | |||
469 | if (udev_monitor == NULL((void*)0)) | |||
470 | return NULL((void*)0); | |||
471 | udev_monitor->refcount--; | |||
472 | if (udev_monitor->refcount > 0) | |||
473 | return NULL((void*)0); | |||
474 | if (udev_monitor->sock >= 0) | |||
475 | close(udev_monitor->sock); | |||
476 | udev_list_cleanup(&udev_monitor->filter_subsystem_list); | |||
477 | udev_list_cleanup(&udev_monitor->filter_tag_list); | |||
478 | return mfree(udev_monitor); | |||
479 | } | |||
480 | ||||
481 | /** | |||
482 | * udev_monitor_get_udev: | |||
483 | * @udev_monitor: udev monitor | |||
484 | * | |||
485 | * Retrieve the udev library context the monitor was created with. | |||
486 | * | |||
487 | * Returns: the udev library context | |||
488 | **/ | |||
489 | _public___attribute__ ((visibility("default"))) struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) | |||
490 | { | |||
491 | if (udev_monitor == NULL((void*)0)) | |||
492 | return NULL((void*)0); | |||
493 | return udev_monitor->udev; | |||
494 | } | |||
495 | ||||
496 | /** | |||
497 | * udev_monitor_get_fd: | |||
498 | * @udev_monitor: udev monitor | |||
499 | * | |||
500 | * Retrieve the socket file descriptor associated with the monitor. | |||
501 | * | |||
502 | * Returns: the socket file descriptor | |||
503 | **/ | |||
504 | _public___attribute__ ((visibility("default"))) int udev_monitor_get_fd(struct udev_monitor *udev_monitor) | |||
505 | { | |||
506 | if (udev_monitor == NULL((void*)0)) | |||
507 | return -EINVAL22; | |||
508 | return udev_monitor->sock; | |||
509 | } | |||
510 | ||||
511 | static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) | |||
512 | { | |||
513 | struct udev_list_entry *list_entry; | |||
514 | ||||
515 | if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL((void*)0)) | |||
516 | goto tag; | |||
517 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list))for (list_entry = udev_list_get_entry(&udev_monitor->filter_subsystem_list ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) { | |||
518 | const char *subsys = udev_list_entry_get_name(list_entry); | |||
519 | const char *dsubsys = udev_device_get_subsystem(udev_device); | |||
520 | const char *devtype; | |||
521 | const char *ddevtype; | |||
522 | ||||
523 | if (!streq(dsubsys, subsys)(strcmp((dsubsys),(subsys)) == 0)) | |||
524 | continue; | |||
525 | ||||
526 | devtype = udev_list_entry_get_value(list_entry); | |||
527 | if (devtype == NULL((void*)0)) | |||
528 | goto tag; | |||
529 | ddevtype = udev_device_get_devtype(udev_device); | |||
530 | if (ddevtype == NULL((void*)0)) | |||
531 | continue; | |||
532 | if (streq(ddevtype, devtype)(strcmp((ddevtype),(devtype)) == 0)) | |||
533 | goto tag; | |||
534 | } | |||
535 | return 0; | |||
536 | ||||
537 | tag: | |||
538 | if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL((void*)0)) | |||
539 | return 1; | |||
540 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))for (list_entry = udev_list_get_entry(&udev_monitor->filter_tag_list ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) { | |||
541 | const char *tag = udev_list_entry_get_name(list_entry); | |||
542 | ||||
543 | if (udev_device_has_tag(udev_device, tag)) | |||
544 | return 1; | |||
545 | } | |||
546 | return 0; | |||
547 | } | |||
548 | ||||
549 | /** | |||
550 | * udev_monitor_receive_device: | |||
551 | * @udev_monitor: udev monitor | |||
552 | * | |||
553 | * Receive data from the udev monitor socket, allocate a new udev | |||
554 | * device, fill in the received data, and return the device. | |||
555 | * | |||
556 | * Only socket connections with uid=0 are accepted. | |||
557 | * | |||
558 | * The monitor socket is by default set to NONBLOCK. A variant of poll() on | |||
559 | * the file descriptor returned by udev_monitor_get_fd() should to be used to | |||
560 | * wake up when new devices arrive, or alternatively the file descriptor | |||
561 | * switched into blocking mode. | |||
562 | * | |||
563 | * The initial refcount is 1, and needs to be decremented to | |||
564 | * release the resources of the udev device. | |||
565 | * | |||
566 | * Returns: a new udev device, or #NULL, in case of an error | |||
567 | **/ | |||
568 | _public___attribute__ ((visibility("default"))) struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) | |||
569 | { | |||
570 | struct udev_device *udev_device; | |||
571 | struct msghdr smsg; | |||
572 | struct iovec iov; | |||
573 | char cred_msg[CMSG_SPACE(sizeof(struct ucred))((((sizeof(struct ucred)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))]; | |||
574 | struct cmsghdr *cmsg; | |||
575 | union sockaddr_union snl; | |||
576 | struct ucred *cred; | |||
577 | union { | |||
578 | struct udev_monitor_netlink_header nlh; | |||
579 | char raw[8192]; | |||
580 | } buf; | |||
581 | ssize_t buflen; | |||
582 | ssize_t bufpos; | |||
583 | bool_Bool is_initialized = false0; | |||
584 | ||||
585 | retry: | |||
586 | if (udev_monitor == NULL((void*)0)) { | |||
587 | errno(*__errno_location ()) = EINVAL22; | |||
588 | return NULL((void*)0); | |||
589 | } | |||
590 | iov.iov_base = &buf; | |||
591 | iov.iov_len = sizeof(buf); | |||
592 | memzero(&smsg, sizeof(struct msghdr))({ size_t _l_ = (sizeof(struct msghdr)); void *_x_ = (&smsg ); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }); | |||
593 | smsg.msg_iov = &iov; | |||
594 | smsg.msg_iovlen = 1; | |||
595 | smsg.msg_control = cred_msg; | |||
596 | smsg.msg_controllen = sizeof(cred_msg); | |||
597 | smsg.msg_name = &snl; | |||
598 | smsg.msg_namelen = sizeof(snl); | |||
599 | ||||
600 | buflen = recvmsg(udev_monitor->sock, &smsg, 0); | |||
601 | if (buflen < 0) { | |||
602 | if (errno(*__errno_location ()) != EINTR4) | |||
603 | log_debug("unable to receive message")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 603, __func__, "unable to receive message" ) : -abs(_e); }); | |||
604 | return NULL((void*)0); | |||
605 | } | |||
606 | ||||
607 | if (buflen < 32 || (smsg.msg_flags & MSG_TRUNCMSG_TRUNC)) { | |||
608 | log_debug("invalid message length")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 608, __func__, "invalid message length" ) : -abs(_e); }); | |||
609 | errno(*__errno_location ()) = EINVAL22; | |||
610 | return NULL((void*)0); | |||
611 | } | |||
612 | ||||
613 | if (snl.nl.nl_groups == 0) { | |||
614 | /* unicast message, check if we trust the sender */ | |||
615 | if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || | |||
616 | snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) { | |||
617 | log_debug("unicast netlink message ignored")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 617, __func__, "unicast netlink message ignored" ) : -abs(_e); }); | |||
618 | errno(*__errno_location ()) = EAGAIN11; | |||
619 | return NULL((void*)0); | |||
620 | } | |||
621 | } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { | |||
622 | if (snl.nl.nl_pid > 0) { | |||
623 | log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 624, __func__, "multicast kernel netlink message from PID %" "u"" ignored", snl.nl.nl_pid) : -abs(_e); }) | |||
624 | snl.nl.nl_pid)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 624, __func__, "multicast kernel netlink message from PID %" "u"" ignored", snl.nl.nl_pid) : -abs(_e); }); | |||
625 | errno(*__errno_location ()) = EAGAIN11; | |||
626 | return NULL((void*)0); | |||
627 | } | |||
628 | } | |||
629 | ||||
630 | cmsg = CMSG_FIRSTHDR(&smsg)((size_t) (&smsg)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (&smsg)->msg_control : ( struct cmsghdr *) 0); | |||
631 | if (cmsg == NULL((void*)0) || cmsg->cmsg_type != SCM_CREDENTIALSSCM_CREDENTIALS) { | |||
632 | log_debug("no sender credentials received, message ignored")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 632, __func__, "no sender credentials received, message ignored" ) : -abs(_e); }); | |||
633 | errno(*__errno_location ()) = EAGAIN11; | |||
634 | return NULL((void*)0); | |||
635 | } | |||
636 | ||||
637 | cred = (struct ucred *)CMSG_DATA(cmsg)((cmsg)->__cmsg_data); | |||
638 | if (cred->uid != 0) { | |||
639 | log_debug("sender uid="UID_FMT", message ignored", cred->uid)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 639, __func__, "sender uid=" "%" "u"", message ignored", cred->uid) : -abs(_e); }); | |||
640 | errno(*__errno_location ()) = EAGAIN11; | |||
641 | return NULL((void*)0); | |||
642 | } | |||
643 | ||||
644 | if (memcmp(buf.raw, "libudev", 8) == 0) { | |||
645 | /* udev message needs proper version magic */ | |||
646 | if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)__bswap_32 (0xfeedcafe)) { | |||
647 | log_debug("unrecognized message signature (%x != %x)",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 648, __func__, "unrecognized message signature (%x != %x)" , buf.nlh.magic, __bswap_32 (0xfeedcafe)) : -abs(_e); }) | |||
648 | buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 648, __func__, "unrecognized message signature (%x != %x)" , buf.nlh.magic, __bswap_32 (0xfeedcafe)) : -abs(_e); }); | |||
649 | errno(*__errno_location ()) = EAGAIN11; | |||
650 | return NULL((void*)0); | |||
651 | } | |||
652 | if (buf.nlh.properties_off+32 > (size_t)buflen) { | |||
653 | log_debug("message smaller than expected (%u > %zd)",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 654, __func__, "message smaller than expected (%u > %zd)" , buf.nlh.properties_off+32, buflen) : -abs(_e); }) | |||
654 | buf.nlh.properties_off+32, buflen)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 654, __func__, "message smaller than expected (%u > %zd)" , buf.nlh.properties_off+32, buflen) : -abs(_e); }); | |||
655 | errno(*__errno_location ()) = EAGAIN11; | |||
656 | return NULL((void*)0); | |||
657 | } | |||
658 | ||||
659 | bufpos = buf.nlh.properties_off; | |||
660 | ||||
661 | /* devices received from udev are always initialized */ | |||
662 | is_initialized = true1; | |||
663 | } else { | |||
664 | /* kernel message with header */ | |||
665 | bufpos = strlen(buf.raw) + 1; | |||
666 | if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) { | |||
667 | log_debug("invalid message length")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 667, __func__, "invalid message length" ) : -abs(_e); }); | |||
668 | errno(*__errno_location ()) = EAGAIN11; | |||
669 | return NULL((void*)0); | |||
670 | } | |||
671 | ||||
672 | /* check message header */ | |||
673 | if (strstr(buf.raw, "@/") == NULL((void*)0)) { | |||
674 | log_debug("unrecognized message header")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 674, __func__, "unrecognized message header" ) : -abs(_e); }); | |||
675 | errno(*__errno_location ()) = EAGAIN11; | |||
676 | return NULL((void*)0); | |||
677 | } | |||
678 | } | |||
679 | ||||
680 | udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos); | |||
681 | if (!udev_device) { | |||
682 | log_debug_errno(errno, "could not create device: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libudev/libudev-monitor.c", 682, __func__, "could not create device: %m") : -abs(_e); }); | |||
683 | return NULL((void*)0); | |||
684 | } | |||
685 | ||||
686 | if (is_initialized) | |||
687 | udev_device_set_is_initialized(udev_device); | |||
688 | ||||
689 | /* skip device, if it does not pass the current filter */ | |||
690 | if (!passes_filter(udev_monitor, udev_device)) { | |||
691 | struct pollfd pfd[1]; | |||
692 | int rc; | |||
693 | ||||
694 | udev_device_unref(udev_device); | |||
695 | ||||
696 | /* if something is queued, get next device */ | |||
697 | pfd[0].fd = udev_monitor->sock; | |||
698 | pfd[0].events = POLLIN0x001; | |||
699 | rc = poll(pfd, 1, 0); | |||
700 | if (rc > 0) | |||
701 | goto retry; | |||
702 | ||||
703 | errno(*__errno_location ()) = EAGAIN11; | |||
704 | return NULL((void*)0); | |||
705 | } | |||
706 | ||||
707 | return udev_device; | |||
708 | } | |||
709 | ||||
710 | int udev_monitor_send_device(struct udev_monitor *udev_monitor, | |||
711 | struct udev_monitor *destination, struct udev_device *udev_device) | |||
712 | { | |||
713 | const char *buf, *val; | |||
714 | ssize_t blen, count; | |||
715 | struct udev_monitor_netlink_header nlh = { | |||
716 | .prefix = "libudev", | |||
717 | .magic = htobe32(UDEV_MONITOR_MAGIC)__bswap_32 (0xfeedcafe), | |||
718 | .header_size = sizeof nlh, | |||
719 | }; | |||
720 | struct iovec iov[2] = { | |||
721 | { .iov_base = &nlh, .iov_len = sizeof nlh }, | |||
722 | }; | |||
723 | struct msghdr smsg = { | |||
724 | .msg_iov = iov, | |||
725 | .msg_iovlen = 2, | |||
726 | }; | |||
727 | struct udev_list_entry *list_entry; | |||
728 | uint64_t tag_bloom_bits; | |||
729 | ||||
730 | blen = udev_device_get_properties_monitor_buf(udev_device, &buf); | |||
731 | if (blen < 32) { | |||
732 | log_debug("device buffer is too small to contain a valid device")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 732, __func__, "device buffer is too small to contain a valid device" ) : -abs(_e); }); | |||
733 | return -EINVAL22; | |||
734 | } | |||
735 | ||||
736 | /* fill in versioned header */ | |||
737 | val = udev_device_get_subsystem(udev_device); | |||
738 | nlh.filter_subsystem_hash = htobe32(util_string_hash32(val))__bswap_32 (util_string_hash32(val)); | |||
739 | ||||
740 | val = udev_device_get_devtype(udev_device); | |||
741 | if (val != NULL((void*)0)) | |||
742 | nlh.filter_devtype_hash = htobe32(util_string_hash32(val))__bswap_32 (util_string_hash32(val)); | |||
743 | ||||
744 | /* add tag bloom filter */ | |||
745 | tag_bloom_bits = 0; | |||
746 | udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))for (list_entry = udev_device_get_tags_list_entry(udev_device ); list_entry != ((void*)0); list_entry = udev_list_entry_get_next (list_entry)) | |||
747 | tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); | |||
748 | if (tag_bloom_bits > 0) { | |||
749 | nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32)__bswap_32 (tag_bloom_bits >> 32); | |||
750 | nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff)__bswap_32 (tag_bloom_bits & 0xffffffff); | |||
751 | } | |||
752 | ||||
753 | /* add properties list */ | |||
754 | nlh.properties_off = iov[0].iov_len; | |||
755 | nlh.properties_len = blen; | |||
756 | iov[1].iov_base = (char *)buf; | |||
757 | iov[1].iov_len = blen; | |||
758 | ||||
759 | /* | |||
760 | * Use custom address for target, or the default one. | |||
761 | * | |||
762 | * If we send to a multicast group, we will get | |||
763 | * ECONNREFUSED, which is expected. | |||
764 | */ | |||
765 | if (destination) | |||
766 | smsg.msg_name = &destination->snl; | |||
767 | else | |||
768 | smsg.msg_name = &udev_monitor->snl_destination; | |||
769 | smsg.msg_namelen = sizeof(struct sockaddr_nl); | |||
770 | count = sendmsg(udev_monitor->sock, &smsg, 0); | |||
771 | if (count < 0) { | |||
772 | if (!destination && errno(*__errno_location ()) == ECONNREFUSED111) { | |||
773 | log_debug("passed device to netlink monitor %p", udev_monitor)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 773, __func__, "passed device to netlink monitor %p" , udev_monitor) : -abs(_e); }); | |||
774 | return 0; | |||
775 | } else | |||
776 | return -errno(*__errno_location ()); | |||
777 | } | |||
778 | ||||
779 | log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libudev/libudev-monitor.c", 779, __func__, "passed %zi byte device to netlink monitor %p" , count, udev_monitor) : -abs(_e); }); | |||
780 | return count; | |||
781 | } | |||
782 | ||||
783 | /** | |||
784 | * udev_monitor_filter_add_match_subsystem_devtype: | |||
785 | * @udev_monitor: the monitor | |||
786 | * @subsystem: the subsystem value to match the incoming devices against | |||
787 | * @devtype: the devtype value to match the incoming devices against | |||
788 | * | |||
789 | * This filter is efficiently executed inside the kernel, and libudev subscribers | |||
790 | * will usually not be woken up for devices which do not match. | |||
791 | * | |||
792 | * The filter must be installed before the monitor is switched to listening mode. | |||
793 | * | |||
794 | * Returns: 0 on success, otherwise a negative error value. | |||
795 | */ | |||
796 | _public___attribute__ ((visibility("default"))) int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) | |||
797 | { | |||
798 | if (udev_monitor == NULL((void*)0)) | |||
799 | return -EINVAL22; | |||
800 | if (subsystem == NULL((void*)0)) | |||
801 | return -EINVAL22; | |||
802 | if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL((void*)0)) | |||
803 | return -ENOMEM12; | |||
804 | return 0; | |||
805 | } | |||
806 | ||||
807 | /** | |||
808 | * udev_monitor_filter_add_match_tag: | |||
809 | * @udev_monitor: the monitor | |||
810 | * @tag: the name of a tag | |||
811 | * | |||
812 | * This filter is efficiently executed inside the kernel, and libudev subscribers | |||
813 | * will usually not be woken up for devices which do not match. | |||
814 | * | |||
815 | * The filter must be installed before the monitor is switched to listening mode. | |||
816 | * | |||
817 | * Returns: 0 on success, otherwise a negative error value. | |||
818 | */ | |||
819 | _public___attribute__ ((visibility("default"))) int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) | |||
820 | { | |||
821 | if (udev_monitor == NULL((void*)0)) | |||
822 | return -EINVAL22; | |||
823 | if (tag == NULL((void*)0)) | |||
824 | return -EINVAL22; | |||
825 | if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL((void*)0)) == NULL((void*)0)) | |||
826 | return -ENOMEM12; | |||
827 | return 0; | |||
828 | } | |||
829 | ||||
830 | /** | |||
831 | * udev_monitor_filter_remove: | |||
832 | * @udev_monitor: monitor | |||
833 | * | |||
834 | * Remove all filters from monitor. | |||
835 | * | |||
836 | * Returns: 0 on success, otherwise a negative error value. | |||
837 | */ | |||
838 | _public___attribute__ ((visibility("default"))) int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) | |||
839 | { | |||
840 | static const struct sock_fprog filter = { 0, NULL((void*)0) }; | |||
841 | ||||
842 | udev_list_cleanup(&udev_monitor->filter_subsystem_list); | |||
843 | if (setsockopt(udev_monitor->sock, SOL_SOCKET1, SO_ATTACH_FILTER26, &filter, sizeof(filter)) < 0) | |||
844 | return -errno(*__errno_location ()); | |||
845 | ||||
846 | return 0; | |||
847 | } |