#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
+#include <poll.h>
#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/filter.h>
/* we consider udev running when /dev is on devtmpfs */
static bool udev_has_devtmpfs(struct udev *udev) {
- union file_handle_union h = {
- .handle.handle_bytes = MAX_HANDLE_SZ
- };
-
+ union file_handle_union h = FILE_HANDLE_INIT;
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX], *e;
int mount_id;
} buf;
ssize_t buflen;
ssize_t bufpos;
+ bool is_initialized = false;
retry:
if (udev_monitor == NULL)
}
} else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
if (snl.nl.nl_pid > 0) {
- log_debug("multicast kernel netlink message from pid %d ignored",
- snl.nl.nl_pid);
+ log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",
+ snl.nl.nl_pid);
return NULL;
}
}
cred = (struct ucred *)CMSG_DATA(cmsg);
if (cred->uid != 0) {
- log_debug("sender uid=%d, message ignored", cred->uid);
+ log_debug("sender uid="UID_FMT", message ignored", cred->uid);
return NULL;
}
- udev_device = udev_device_new(udev_monitor->udev);
- if (udev_device == NULL)
- return NULL;
-
if (memcmp(buf.raw, "libudev", 8) == 0) {
/* udev message needs proper version magic */
if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) {
log_debug("unrecognized message signature (%x != %x)",
buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC));
- udev_device_unref(udev_device);
return NULL;
}
if (buf.nlh.properties_off+32 > (size_t)buflen) {
- udev_device_unref(udev_device);
+ log_debug("message smaller than expected (%u > %zd)",
+ buf.nlh.properties_off+32, buflen);
return NULL;
}
bufpos = buf.nlh.properties_off;
/* devices received from udev are always initialized */
- udev_device_set_is_initialized(udev_device);
+ is_initialized = true;
} else {
/* kernel message with header */
bufpos = strlen(buf.raw) + 1;
if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
log_debug("invalid message length");
- udev_device_unref(udev_device);
return NULL;
}
/* check message header */
if (strstr(buf.raw, "@/") == NULL) {
log_debug("unrecognized message header");
- udev_device_unref(udev_device);
return NULL;
}
}
- udev_device_set_info_loaded(udev_device);
-
- while (bufpos < buflen) {
- char *key;
- size_t keylen;
-
- key = &buf.raw[bufpos];
- keylen = strlen(key);
- if (keylen == 0)
- break;
- bufpos += keylen + 1;
- udev_device_add_property_from_string_parse(udev_device, key);
- }
-
- if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
- log_debug("missing values, invalid device");
- udev_device_unref(udev_device);
+ udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
+ if (!udev_device) {
+ log_debug("could not create device: %m");
return NULL;
}
+ if (is_initialized)
+ udev_device_set_is_initialized(udev_device);
+
/* skip device, if it does not pass the current filter */
if (!passes_filter(udev_monitor, udev_device)) {
struct pollfd pfd[1];
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;
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);
+ if (count < 0) {
+ if (!destination && errno == ECONNREFUSED) {
+ log_debug("passed unknown number of bytes to netlink monitor %p", udev_monitor);
+ return 0;
+ } else
+ return -errno;
+ }
+
log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor);
return count;
}