along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <poll.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
#include <string.h>
-#include <poll.h>
#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/filter.h>
+#include <unistd.h>
#include "libudev.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "format-util.h"
#include "libudev-private.h"
-#include "socket-util.h"
#include "missing.h"
+#include "mount-util.h"
+#include "socket-util.h"
+#include "string-util.h"
/**
* SECTION:libudev-monitor
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;
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;
+ return mfree(udev_monitor);
}
} else {
udev_monitor->bound = true;
udev_monitor->sock = fd;
+ monitor_set_nl_address(udev_monitor);
}
udev_monitor->snl.nl.nl_family = AF_NETLINK;
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
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 {
- log_debug_errno(errno, "bind failed: %m");
- return -errno;
- }
+ if (err >= 0)
+ monitor_set_nl_address(udev_monitor);
+ else
+ return log_debug_errno(errno, "bind failed: %m");
/* enable receiving of sender credentials */
err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (memcmp(buf.raw, "libudev", 8) == 0) {
/* udev message needs proper version magic */
- if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) {
+ if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) {
log_debug("unrecognized message signature (%x != %x)",
- buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC));
+ buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
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;
}
}
udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
- if (!udev_device)
+ if (!udev_device) {
+ log_debug_errno(errno, "could not create device: %m");
return NULL;
+ }
if (is_initialized)
udev_device_set_is_initialized(udev_device);
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 = htobe32(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));
+ nlh.filter_subsystem_hash = htobe32(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);
+ nlh.filter_devtype_hash = htobe32(util_string_hash32(val));
/* add tag bloom filter */
tag_bloom_bits = 0;
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
if (tag_bloom_bits > 0) {
- nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32);
- nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff);
+ nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32);
+ nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff);
}
/* add properties list */
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;
}