]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libudev/libudev-monitor.c
tree-wide: when %m is used in log_*, always specify errno explicitly
[thirdparty/systemd.git] / src / libudev / libudev-monitor.c
index eb7b6f87b24e001e84db381a515ad60cf353eb16..8287694c498637cafe4cc1f6cbed7c926375046d 100644 (file)
   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
@@ -143,6 +150,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;
@@ -182,14 +205,14 @@ 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;
+                        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;
@@ -365,6 +388,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
@@ -387,22 +411,10 @@ _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 {
-                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));
@@ -637,12 +649,14 @@ retry:
 
         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;
                 }
 
@@ -666,8 +680,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_errno(errno, "could not create device: %m");
                 return NULL;
+        }
 
         if (is_initialized)
                 udev_device_set_is_initialized(udev_device);
@@ -694,40 +710,44 @@ 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 = 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 */
@@ -736,22 +756,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;
 }