diff options
Diffstat (limited to 'src/libudev/libudev-monitor.c')
-rw-r--r-- | src/libudev/libudev-monitor.c | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index 3f1fee7f7e..282aa2b0d9 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -23,12 +23,8 @@ #include <unistd.h> #include <errno.h> #include <string.h> -#include <dirent.h> #include <poll.h> -#include <sys/stat.h> #include <sys/socket.h> -#include <sys/un.h> -#include <arpa/inet.h> #include <linux/netlink.h> #include <linux/filter.h> @@ -36,6 +32,7 @@ #include "libudev-private.h" #include "socket-util.h" #include "missing.h" +#include "formats-util.h" /** * SECTION:libudev-monitor @@ -147,6 +144,22 @@ static bool udev_has_devtmpfs(struct udev *udev) { return false; } +static void monitor_set_nl_address(struct udev_monitor *udev_monitor) { + union sockaddr_union snl; + socklen_t addrlen; + int r; + + assert(udev_monitor); + + /* get the address the kernel has assigned us + * it is usually, but not necessarily the pid + */ + addrlen = sizeof(struct sockaddr_nl); + r = getsockname(udev_monitor->sock, &snl.sa, &addrlen); + if (r >= 0) + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; +} + struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) { struct udev_monitor *udev_monitor; @@ -186,7 +199,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c if (fd < 0) { udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - if (udev_monitor->sock == -1) { + if (udev_monitor->sock < 0) { log_debug_errno(errno, "error getting socket: %m"); free(udev_monitor); return NULL; @@ -194,6 +207,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c } else { udev_monitor->bound = true; udev_monitor->sock = fd; + monitor_set_nl_address(udev_monitor); } udev_monitor->snl.nl.nl_family = AF_NETLINK; @@ -369,6 +383,7 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; return 0; } + /** * udev_monitor_enable_receiving: * @udev_monitor: the monitor which should receive events @@ -391,19 +406,9 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) udev_monitor->bound = true; } - if (err >= 0) { - union sockaddr_union snl; - socklen_t addrlen; - - /* - * get the address the kernel has assigned us - * it is usually, but not necessarily the pid - */ - addrlen = sizeof(struct sockaddr_nl); - err = getsockname(udev_monitor->sock, &snl.sa, &addrlen); - if (err == 0) - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - } else { + if (err >= 0) + monitor_set_nl_address(udev_monitor); + else { log_debug_errno(errno, "bind failed: %m"); return -errno; } @@ -647,6 +652,8 @@ retry: return NULL; } if (buf.nlh.properties_off+32 > (size_t)buflen) { + log_debug("message smaller than expected (%u > %zd)", + buf.nlh.properties_off+32, buflen); return NULL; } @@ -670,8 +677,10 @@ retry: } udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos); - if (!udev_device) + if (!udev_device) { + log_debug("could not create device: %m"); return NULL; + } if (is_initialized) udev_device_set_is_initialized(udev_device); @@ -698,32 +707,36 @@ retry: int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_monitor *destination, struct udev_device *udev_device) { - const char *buf; - ssize_t blen; - ssize_t count; - struct msghdr smsg; - struct iovec iov[2]; - const char *val; - struct udev_monitor_netlink_header nlh; + const char *buf, *val; + ssize_t blen, count; + struct udev_monitor_netlink_header nlh = { + .prefix = "libudev", + .magic = htonl(UDEV_MONITOR_MAGIC), + .header_size = sizeof nlh, + }; + struct iovec iov[2] = { + { .iov_base = &nlh, .iov_len = sizeof nlh }, + }; + struct msghdr smsg = { + .msg_iov = iov, + .msg_iovlen = 2, + }; struct udev_list_entry *list_entry; uint64_t tag_bloom_bits; blen = udev_device_get_properties_monitor_buf(udev_device, &buf); - if (blen < 32) + if (blen < 32) { + log_debug("device buffer is too small to contain a valid device"); return -EINVAL; + } - /* add versioned header */ - memzero(&nlh, sizeof(struct udev_monitor_netlink_header)); - memcpy(nlh.prefix, "libudev", 8); - nlh.magic = htonl(UDEV_MONITOR_MAGIC); - nlh.header_size = sizeof(struct udev_monitor_netlink_header); + /* fill in versioned header */ val = udev_device_get_subsystem(udev_device); nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); + val = udev_device_get_devtype(udev_device); if (val != NULL) nlh.filter_devtype_hash = htonl(util_string_hash32(val)); - iov[0].iov_base = &nlh; - iov[0].iov_len = sizeof(struct udev_monitor_netlink_header); /* add tag bloom filter */ tag_bloom_bits = 0; @@ -740,22 +753,27 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, iov[1].iov_base = (char *)buf; iov[1].iov_len = blen; - memzero(&smsg, sizeof(struct msghdr)); - smsg.msg_iov = iov; - smsg.msg_iovlen = 2; /* * Use custom address for target, or the default one. * * If we send to a multicast group, we will get * ECONNREFUSED, which is expected. */ - if (destination != NULL) + if (destination) smsg.msg_name = &destination->snl; else smsg.msg_name = &udev_monitor->snl_destination; smsg.msg_namelen = sizeof(struct sockaddr_nl); count = sendmsg(udev_monitor->sock, &smsg, 0); - log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor); + if (count < 0) { + if (!destination && errno == ECONNREFUSED) { + log_debug("passed device to netlink monitor %p", udev_monitor); + return 0; + } else + return -errno; + } + + log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor); return count; } |