2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <poll.h>
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2015-11-17 06:52:45 +01:00
|
|
|
#include "libudev.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2018-10-08 15:46:31 +02:00
|
|
|
#include "device-monitor-private.h"
|
2018-08-24 10:04:10 +02:00
|
|
|
#include "device-private.h"
|
|
|
|
#include "device-util.h"
|
2020-06-10 11:43:40 +02:00
|
|
|
#include "io-util.h"
|
2018-08-22 09:30:33 +02:00
|
|
|
#include "libudev-device-internal.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* SECTION:libudev-monitor
|
|
|
|
* @short_description: device event source
|
|
|
|
*
|
|
|
|
* Connects to a device event source.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_monitor:
|
|
|
|
*
|
2011-06-28 00:15:39 +02:00
|
|
|
* Opaque object handling an event source.
|
2009-06-15 17:09:43 +02:00
|
|
|
*/
|
2008-08-28 23:05:01 +02:00
|
|
|
struct udev_monitor {
|
2012-01-10 01:34:15 +01:00
|
|
|
struct udev *udev;
|
2018-08-28 06:07:48 +02:00
|
|
|
unsigned n_ref;
|
2018-10-08 15:46:31 +02:00
|
|
|
sd_device_monitor *monitor;
|
2008-08-28 23:05:01 +02:00
|
|
|
};
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
static MonitorNetlinkGroup monitor_netlink_group_from_string(const char *name) {
|
|
|
|
if (!name)
|
|
|
|
return MONITOR_GROUP_NONE;
|
|
|
|
if (streq(name, "udev"))
|
|
|
|
return MONITOR_GROUP_UDEV;
|
|
|
|
if (streq(name, "kernel"))
|
|
|
|
return MONITOR_GROUP_KERNEL;
|
|
|
|
return _MONITOR_NETLINK_GROUP_INVALID;
|
2015-06-02 20:57:52 +02:00
|
|
|
}
|
|
|
|
|
2018-10-29 16:54:12 +01:00
|
|
|
/**
|
|
|
|
* udev_monitor_new_from_netlink:
|
|
|
|
* @udev: udev library context
|
|
|
|
* @name: name of event source
|
|
|
|
*
|
|
|
|
* Create new udev monitor and connect to a specified event
|
|
|
|
* source. Valid sources identifiers are "udev" and "kernel".
|
|
|
|
*
|
|
|
|
* Applications should usually not connect directly to the
|
2019-04-27 02:22:40 +02:00
|
|
|
* "kernel" events, because the devices might not be usable
|
2018-10-29 16:54:12 +01:00
|
|
|
* at that time, before udev has configured them, and created
|
|
|
|
* device nodes. Accessing devices at the same time as udev,
|
|
|
|
* might result in unpredictable behavior. The "udev" events
|
|
|
|
* are sent out after udev has finished its event processing,
|
|
|
|
* all rules have been processed, and needed device nodes are
|
|
|
|
* created.
|
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev monitor.
|
|
|
|
*
|
|
|
|
* Returns: a new udev monitor, or #NULL, in case of an error
|
|
|
|
**/
|
|
|
|
_public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) {
|
2018-10-08 15:46:31 +02:00
|
|
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
|
2018-11-16 03:44:17 +01:00
|
|
|
struct udev_monitor *udev_monitor;
|
2018-10-08 15:46:31 +02:00
|
|
|
MonitorNetlinkGroup g;
|
2018-08-24 09:51:58 +02:00
|
|
|
int r;
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
g = monitor_netlink_group_from_string(name);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (g < 0)
|
|
|
|
return_with_errno(NULL, EINVAL);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-10-29 16:54:12 +01:00
|
|
|
r = device_monitor_new_full(&m, g, -1);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 09:51:58 +02:00
|
|
|
udev_monitor = new(struct udev_monitor, 1);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (!udev_monitor)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
2018-08-24 09:51:58 +02:00
|
|
|
|
|
|
|
*udev_monitor = (struct udev_monitor) {
|
|
|
|
.udev = udev,
|
|
|
|
.n_ref = 1,
|
2018-10-08 15:46:31 +02:00
|
|
|
.monitor = TAKE_PTR(m),
|
2018-08-24 09:51:58 +02:00
|
|
|
};
|
|
|
|
|
2018-11-16 03:44:17 +01:00
|
|
|
return udev_monitor;
|
2008-09-09 17:38:10 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_filter_update:
|
|
|
|
* @udev_monitor: monitor
|
|
|
|
*
|
2011-06-28 00:15:39 +02:00
|
|
|
* Update the installed socket filter. This is only needed,
|
|
|
|
* if the filter was removed or changed.
|
2009-06-15 17:09:43 +02:00
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise a negative error value.
|
|
|
|
*/
|
2018-08-24 10:00:40 +02:00
|
|
|
_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return sd_device_monitor_filter_update(udev_monitor->monitor);
|
2009-04-22 03:50:11 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_enable_receiving:
|
|
|
|
* @udev_monitor: the monitor which should receive events
|
|
|
|
*
|
|
|
|
* Binds the @udev_monitor socket to the event source.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise a negative error value.
|
|
|
|
*/
|
2018-08-24 10:10:27 +02:00
|
|
|
_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return device_monitor_enable_receiving(udev_monitor->monitor);
|
2008-08-28 23:05:01 +02:00
|
|
|
}
|
|
|
|
|
2010-05-07 23:04:42 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_set_receive_buffer_size:
|
|
|
|
* @udev_monitor: the monitor which should receive events
|
|
|
|
* @size: the size in bytes
|
|
|
|
*
|
|
|
|
* Set the size of the kernel socket buffer. This call needs the
|
|
|
|
* appropriate privileges to succeed.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise -1 on error.
|
|
|
|
*/
|
2018-08-24 10:12:04 +02:00
|
|
|
_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size);
|
2008-10-17 16:49:27 +02:00
|
|
|
}
|
|
|
|
|
2018-08-28 06:07:48 +02:00
|
|
|
static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) {
|
|
|
|
assert(udev_monitor);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
sd_device_monitor_unref(udev_monitor->monitor);
|
2018-08-28 06:07:48 +02:00
|
|
|
return mfree(udev_monitor);
|
|
|
|
}
|
|
|
|
|
2008-08-30 16:16:37 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_ref:
|
|
|
|
* @udev_monitor: udev monitor
|
|
|
|
*
|
|
|
|
* Take a reference of a udev monitor.
|
|
|
|
*
|
|
|
|
* Returns: the passed udev monitor
|
|
|
|
**/
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2008-08-30 16:16:37 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_unref:
|
|
|
|
* @udev_monitor: udev monitor
|
|
|
|
*
|
2009-04-16 01:49:16 +02:00
|
|
|
* Drop a reference of a udev monitor. If the refcount reaches zero,
|
2008-10-26 15:48:48 +01:00
|
|
|
* the bound socket will be closed, and the resources of the monitor
|
2008-08-30 16:16:37 +02:00
|
|
|
* will be released.
|
|
|
|
*
|
2013-11-19 01:15:31 +01:00
|
|
|
* Returns: #NULL
|
2008-08-30 16:16:37 +02:00
|
|
|
**/
|
2018-08-28 06:07:48 +02:00
|
|
|
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free);
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2008-08-30 16:16:37 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_get_udev:
|
|
|
|
* @udev_monitor: udev monitor
|
|
|
|
*
|
2008-09-01 16:41:41 +02:00
|
|
|
* Retrieve the udev library context the monitor was created with.
|
2008-08-30 16:16:37 +02:00
|
|
|
*
|
|
|
|
* Returns: the udev library context
|
|
|
|
**/
|
2018-08-24 10:12:04 +02:00
|
|
|
_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
|
|
|
|
assert_return(udev_monitor, NULL);
|
|
|
|
|
2012-01-10 01:34:15 +01:00
|
|
|
return udev_monitor->udev;
|
2008-08-28 23:05:01 +02:00
|
|
|
}
|
|
|
|
|
2008-08-30 16:16:37 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_get_fd:
|
|
|
|
* @udev_monitor: udev monitor
|
|
|
|
*
|
|
|
|
* Retrieve the socket file descriptor associated with the monitor.
|
|
|
|
*
|
|
|
|
* Returns: the socket file descriptor
|
|
|
|
**/
|
2018-08-24 10:12:04 +02:00
|
|
|
_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return device_monitor_get_fd(udev_monitor->monitor);
|
2008-08-28 23:05:01 +02:00
|
|
|
}
|
|
|
|
|
2018-10-29 16:54:12 +01:00
|
|
|
static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
|
2018-08-24 10:04:10 +02:00
|
|
|
int r;
|
2008-08-28 23:05:01 +02:00
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
assert(udev_monitor);
|
2018-08-24 10:04:10 +02:00
|
|
|
assert(ret);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 10:04:10 +02:00
|
|
|
for (;;) {
|
|
|
|
/* r == 0 means a device is received but it does not pass the current filter. */
|
2018-10-08 15:46:31 +02:00
|
|
|
r = device_monitor_receive_device(udev_monitor->monitor, ret);
|
2018-08-24 10:04:10 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (;;) {
|
2020-06-10 11:43:40 +02:00
|
|
|
/* Wait for next message */
|
|
|
|
r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0);
|
2018-08-24 10:04:10 +02:00
|
|
|
if (r < 0) {
|
2020-06-10 11:43:40 +02:00
|
|
|
if (IN_SET(r, -EINTR, -EAGAIN))
|
2018-08-24 10:04:10 +02:00
|
|
|
continue;
|
|
|
|
|
2020-06-10 11:43:40 +02:00
|
|
|
return r;
|
2020-06-09 13:40:25 +02:00
|
|
|
}
|
|
|
|
if (r == 0)
|
2018-08-24 10:04:10 +02:00
|
|
|
return -EAGAIN;
|
|
|
|
|
2020-06-10 11:43:40 +02:00
|
|
|
/* Receive next message */
|
2018-08-24 10:04:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-08-28 23:05:01 +02:00
|
|
|
}
|
2008-10-09 23:38:30 +02:00
|
|
|
|
2018-08-24 10:04:10 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_receive_device:
|
|
|
|
* @udev_monitor: udev monitor
|
|
|
|
*
|
|
|
|
* Receive data from the udev monitor socket, allocate a new udev
|
|
|
|
* device, fill in the received data, and return the device.
|
|
|
|
*
|
|
|
|
* Only socket connections with uid=0 are accepted.
|
|
|
|
*
|
|
|
|
* The monitor socket is by default set to NONBLOCK. A variant of poll() on
|
|
|
|
* the file descriptor returned by udev_monitor_get_fd() should to be used to
|
|
|
|
* wake up when new devices arrive, or alternatively the file descriptor
|
|
|
|
* switched into blocking mode.
|
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev device.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, in case of an error
|
|
|
|
**/
|
|
|
|
_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
|
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
|
|
|
int r;
|
2018-08-22 09:30:33 +02:00
|
|
|
|
2018-08-24 10:04:10 +02:00
|
|
|
assert_return(udev_monitor, NULL);
|
2018-08-22 09:30:33 +02:00
|
|
|
|
2018-08-24 10:04:10 +02:00
|
|
|
r = udev_monitor_receive_sd_device(udev_monitor, &device);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2018-08-22 09:30:33 +02:00
|
|
|
|
2018-08-24 10:04:10 +02:00
|
|
|
return udev_device_new(udev_monitor->udev, device);
|
2018-08-22 09:30:33 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_filter_add_match_subsystem_devtype:
|
|
|
|
* @udev_monitor: the monitor
|
|
|
|
* @subsystem: the subsystem value to match the incoming devices against
|
2009-08-08 15:29:38 +02:00
|
|
|
* @devtype: the devtype value to match the incoming devices against
|
2009-06-15 17:09:43 +02:00
|
|
|
*
|
2011-06-28 00:15:39 +02:00
|
|
|
* This filter is efficiently executed inside the kernel, and libudev subscribers
|
2010-04-22 18:12:36 +02:00
|
|
|
* will usually not be woken up for devices which do not match.
|
|
|
|
*
|
2009-06-15 17:09:43 +02:00
|
|
|
* The filter must be installed before the monitor is switched to listening mode.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise a negative error value.
|
|
|
|
*/
|
2018-08-24 10:00:40 +02:00
|
|
|
_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype);
|
2009-04-22 03:50:11 +02:00
|
|
|
}
|
2009-04-23 04:07:51 +02:00
|
|
|
|
2010-04-22 18:12:36 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_filter_add_match_tag:
|
|
|
|
* @udev_monitor: the monitor
|
|
|
|
* @tag: the name of a tag
|
|
|
|
*
|
2011-06-28 00:15:39 +02:00
|
|
|
* This filter is efficiently executed inside the kernel, and libudev subscribers
|
2010-04-22 18:12:36 +02:00
|
|
|
* will usually not be woken up for devices which do not match.
|
|
|
|
*
|
|
|
|
* The filter must be installed before the monitor is switched to listening mode.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise a negative error value.
|
|
|
|
*/
|
2018-08-24 10:00:40 +02:00
|
|
|
_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag);
|
2010-04-22 18:12:36 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* udev_monitor_filter_remove:
|
|
|
|
* @udev_monitor: monitor
|
|
|
|
*
|
|
|
|
* Remove all filters from monitor.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, otherwise a negative error value.
|
|
|
|
*/
|
2018-08-24 10:00:40 +02:00
|
|
|
_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) {
|
|
|
|
assert_return(udev_monitor, -EINVAL);
|
|
|
|
|
2018-10-08 15:46:31 +02:00
|
|
|
return sd_device_monitor_filter_remove(udev_monitor->monitor);
|
2009-04-23 04:07:51 +02:00
|
|
|
}
|