1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
9 #include "device-monitor-private.h"
10 #include "device-private.h"
11 #include "device-util.h"
12 #include "libudev-device-internal.h"
13 #include "string-util.h"
16 * SECTION:libudev-monitor
17 * @short_description: device event source
19 * Connects to a device event source.
25 * Opaque object handling an event source.
30 sd_device_monitor
*monitor
;
33 static MonitorNetlinkGroup
monitor_netlink_group_from_string(const char *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
;
44 * udev_monitor_new_from_netlink:
45 * @udev: udev library context
46 * @name: name of event source
48 * Create new udev monitor and connect to a specified event
49 * source. Valid sources identifiers are "udev" and "kernel".
51 * Applications should usually not connect directly to the
52 * "kernel" events, because the devices might not be useable
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
60 * The initial refcount is 1, and needs to be decremented to
61 * release the resources of the udev monitor.
63 * Returns: a new udev monitor, or #NULL, in case of an error
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
;
71 g
= monitor_netlink_group_from_string(name
);
73 return_with_errno(NULL
, EINVAL
);
75 r
= device_monitor_new_full(&m
, g
, -1);
77 return_with_errno(NULL
, r
);
79 udev_monitor
= new(struct udev_monitor
, 1);
81 return_with_errno(NULL
, ENOMEM
);
83 *udev_monitor
= (struct udev_monitor
) {
86 .monitor
= TAKE_PTR(m
),
93 * udev_monitor_filter_update:
94 * @udev_monitor: monitor
96 * Update the installed socket filter. This is only needed,
97 * if the filter was removed or changed.
99 * Returns: 0 on success, otherwise a negative error value.
101 _public_
int udev_monitor_filter_update(struct udev_monitor
*udev_monitor
) {
102 assert_return(udev_monitor
, -EINVAL
);
104 return sd_device_monitor_filter_update(udev_monitor
->monitor
);
108 * udev_monitor_enable_receiving:
109 * @udev_monitor: the monitor which should receive events
111 * Binds the @udev_monitor socket to the event source.
113 * Returns: 0 on success, otherwise a negative error value.
115 _public_
int udev_monitor_enable_receiving(struct udev_monitor
*udev_monitor
) {
116 assert_return(udev_monitor
, -EINVAL
);
118 return device_monitor_enable_receiving(udev_monitor
->monitor
);
122 * udev_monitor_set_receive_buffer_size:
123 * @udev_monitor: the monitor which should receive events
124 * @size: the size in bytes
126 * Set the size of the kernel socket buffer. This call needs the
127 * appropriate privileges to succeed.
129 * Returns: 0 on success, otherwise -1 on error.
131 _public_
int udev_monitor_set_receive_buffer_size(struct udev_monitor
*udev_monitor
, int size
) {
132 assert_return(udev_monitor
, -EINVAL
);
134 return sd_device_monitor_set_receive_buffer_size(udev_monitor
->monitor
, (size_t) size
);
137 static struct udev_monitor
*udev_monitor_free(struct udev_monitor
*udev_monitor
) {
138 assert(udev_monitor
);
140 sd_device_monitor_unref(udev_monitor
->monitor
);
141 return mfree(udev_monitor
);
146 * @udev_monitor: udev monitor
148 * Take a reference of a udev monitor.
150 * Returns: the passed udev monitor
154 * udev_monitor_unref:
155 * @udev_monitor: udev monitor
157 * Drop a reference of a udev monitor. If the refcount reaches zero,
158 * the bound socket will be closed, and the resources of the monitor
163 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor
, udev_monitor
, udev_monitor_free
);
166 * udev_monitor_get_udev:
167 * @udev_monitor: udev monitor
169 * Retrieve the udev library context the monitor was created with.
171 * Returns: the udev library context
173 _public_
struct udev
*udev_monitor_get_udev(struct udev_monitor
*udev_monitor
) {
174 assert_return(udev_monitor
, NULL
);
176 return udev_monitor
->udev
;
180 * udev_monitor_get_fd:
181 * @udev_monitor: udev monitor
183 * Retrieve the socket file descriptor associated with the monitor.
185 * Returns: the socket file descriptor
187 _public_
int udev_monitor_get_fd(struct udev_monitor
*udev_monitor
) {
188 assert_return(udev_monitor
, -EINVAL
);
190 return device_monitor_get_fd(udev_monitor
->monitor
);
193 static int udev_monitor_receive_sd_device(struct udev_monitor
*udev_monitor
, sd_device
**ret
) {
197 assert(udev_monitor
);
200 pfd
= (struct pollfd
) {
201 .fd
= device_monitor_get_fd(udev_monitor
->monitor
),
206 /* r == 0 means a device is received but it does not pass the current filter. */
207 r
= device_monitor_receive_device(udev_monitor
->monitor
, ret
);
212 /* wait next message */
213 r
= poll(&pfd
, 1, 0);
215 if (IN_SET(errno
, EINTR
, EAGAIN
))
222 /* receive next message */
229 * udev_monitor_receive_device:
230 * @udev_monitor: udev monitor
232 * Receive data from the udev monitor socket, allocate a new udev
233 * device, fill in the received data, and return the device.
235 * Only socket connections with uid=0 are accepted.
237 * The monitor socket is by default set to NONBLOCK. A variant of poll() on
238 * the file descriptor returned by udev_monitor_get_fd() should to be used to
239 * wake up when new devices arrive, or alternatively the file descriptor
240 * switched into blocking mode.
242 * The initial refcount is 1, and needs to be decremented to
243 * release the resources of the udev device.
245 * Returns: a new udev device, or #NULL, in case of an error
247 _public_
struct udev_device
*udev_monitor_receive_device(struct udev_monitor
*udev_monitor
) {
248 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
251 assert_return(udev_monitor
, NULL
);
253 r
= udev_monitor_receive_sd_device(udev_monitor
, &device
);
255 return_with_errno(NULL
, r
);
257 return udev_device_new(udev_monitor
->udev
, device
);
261 * udev_monitor_filter_add_match_subsystem_devtype:
262 * @udev_monitor: the monitor
263 * @subsystem: the subsystem value to match the incoming devices against
264 * @devtype: the devtype value to match the incoming devices against
266 * This filter is efficiently executed inside the kernel, and libudev subscribers
267 * will usually not be woken up for devices which do not match.
269 * The filter must be installed before the monitor is switched to listening mode.
271 * Returns: 0 on success, otherwise a negative error value.
273 _public_
int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor
*udev_monitor
, const char *subsystem
, const char *devtype
) {
274 assert_return(udev_monitor
, -EINVAL
);
276 return sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor
->monitor
, subsystem
, devtype
);
280 * udev_monitor_filter_add_match_tag:
281 * @udev_monitor: the monitor
282 * @tag: the name of a tag
284 * This filter is efficiently executed inside the kernel, and libudev subscribers
285 * will usually not be woken up for devices which do not match.
287 * The filter must be installed before the monitor is switched to listening mode.
289 * Returns: 0 on success, otherwise a negative error value.
291 _public_
int udev_monitor_filter_add_match_tag(struct udev_monitor
*udev_monitor
, const char *tag
) {
292 assert_return(udev_monitor
, -EINVAL
);
294 return sd_device_monitor_filter_add_match_tag(udev_monitor
->monitor
, tag
);
298 * udev_monitor_filter_remove:
299 * @udev_monitor: monitor
301 * Remove all filters from monitor.
303 * Returns: 0 on success, otherwise a negative error value.
305 _public_
int udev_monitor_filter_remove(struct udev_monitor
*udev_monitor
) {
306 assert_return(udev_monitor
, -EINVAL
);
308 return sd_device_monitor_filter_remove(udev_monitor
->monitor
);