chiark / gitweb /
udev: fix a few issues detected by the llvm static analyzer
[elogind.git] / src / udev / libudev-monitor.c
index 77dc555..4406b55 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "libudev.h"
 #include "libudev-private.h"
+#include "socket-util.h"
 
 /**
  * SECTION:libudev-monitor
@@ -43,10 +44,9 @@ struct udev_monitor {
         struct udev *udev;
         int refcount;
         int sock;
-        struct sockaddr_nl snl;
-        struct sockaddr_nl snl_trusted_sender;
-        struct sockaddr_nl snl_destination;
-        struct sockaddr_un sun;
+        union sockaddr_union snl;
+        union sockaddr_union snl_trusted_sender;
+        union sockaddr_union snl_destination;
         socklen_t addrlen;
         struct udev_list filter_subsystem_list;
         struct udev_list filter_tag_list;
@@ -102,63 +102,14 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev)
  * @udev: udev library context
  * @socket_path: unix socket path
  *
- * This function should not be used in any new application. The
- * kernel's netlink socket multiplexes messages to all interested
- * clients. Creating custom sockets from udev to applications
- * should be avoided.
+ * This function is removed from libudev and will not do anything.
  *
- * Create a new udev monitor and connect to a specified socket. The
- * path to a socket either points to an existing socket file, or if
- * the socket path starts with a '@' character, an abstract namespace
- * socket will be used.
- *
- * A socket file will not be created. If it does not already exist,
- * it will fall-back and connect to an abstract namespace socket with
- * the given path. The permissions adjustment of a socket file, as
- * well as the later cleanup, needs to be done by the caller.
- *
- * 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
+ * Returns: #NULL
  **/
-UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
+_public_ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
 {
-        struct udev_monitor *udev_monitor;
-        struct stat statbuf;
-
-        if (udev == NULL)
-                return NULL;
-        if (socket_path == NULL)
-                return NULL;
-        udev_monitor = udev_monitor_new(udev);
-        if (udev_monitor == NULL)
-                return NULL;
-
-        udev_monitor->sun.sun_family = AF_LOCAL;
-        if (socket_path[0] == '@') {
-                /* translate leading '@' to abstract namespace */
-                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-                udev_monitor->sun.sun_path[0] = '\0';
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-        } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
-                /* existing socket file */
-                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-        } else {
-                /* no socket file, assume abstract namespace socket */
-                util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
-                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
-        }
-        udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
-        if (udev_monitor->sock == -1) {
-                err(udev, "error getting socket: %m\n");
-                free(udev_monitor);
-                return NULL;
-        }
-
-        dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
-        return udev_monitor;
+        errno = ENOSYS;
+        return NULL;
 }
 
 struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
@@ -194,14 +145,13 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
                 udev_monitor->sock = fd;
         }
 
-        udev_monitor->snl.nl_family = AF_NETLINK;
-        udev_monitor->snl.nl_groups = group;
+        udev_monitor->snl.nl.nl_family = AF_NETLINK;
+        udev_monitor->snl.nl.nl_groups = group;
 
         /* default destination for sending */
-        udev_monitor->snl_destination.nl_family = AF_NETLINK;
-        udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
+        udev_monitor->snl_destination.nl.nl_family = AF_NETLINK;
+        udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV;
 
-        dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
         return udev_monitor;
 }
 
@@ -227,7 +177,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
  *
  * Returns: a new udev monitor, or #NULL, in case of an error
  **/
-UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
+_public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
 {
         return udev_monitor_new_from_netlink_fd(udev, name, -1);
 }
@@ -264,7 +214,7 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
+_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
 {
         struct sock_filter ins[512];
         struct sock_fprog filter;
@@ -365,7 +315,7 @@ UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
 
 int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
 {
-        udev_monitor->snl_trusted_sender.nl_pid = sender->snl.nl_pid;
+        udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
         return 0;
 }
 /**
@@ -376,44 +326,36 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
+_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
 {
         int err = 0;
         const int on = 1;
 
-        if (udev_monitor->sun.sun_family != 0) {
-                if (!udev_monitor->bound) {
-                        err = bind(udev_monitor->sock,
-                                   (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
-                        if (err == 0)
-                                udev_monitor->bound = true;
-                }
-        } else if (udev_monitor->snl.nl_family != 0) {
-                udev_monitor_filter_update(udev_monitor);
-                if (!udev_monitor->bound) {
-                        err = bind(udev_monitor->sock,
-                                   (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
-                        if (err == 0)
-                                udev_monitor->bound = true;
-                }
-                if (err == 0) {
-                        struct sockaddr_nl 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, (struct sockaddr *)&snl, &addrlen);
-                        if (err == 0)
-                                udev_monitor->snl.nl_pid = snl.nl_pid;
-                }
-        } else {
+        if (udev_monitor->snl.nl.nl_family == 0)
                 return -EINVAL;
+
+        udev_monitor_filter_update(udev_monitor);
+
+        if (!udev_monitor->bound) {
+                err = bind(udev_monitor->sock,
+                           &udev_monitor->snl.sa, sizeof(struct sockaddr_nl));
+                if (err == 0)
+                        udev_monitor->bound = true;
         }
 
-        if (err < 0) {
+        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 {
                 err(udev_monitor->udev, "bind failed: %m\n");
                 return err;
         }
@@ -433,7 +375,7 @@ UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
  *
  * Returns: 0 on success, otherwise -1 on error.
  */
-UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
+_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
 {
         if (udev_monitor == NULL)
                 return -1;
@@ -457,7 +399,7 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
  *
  * Returns: the passed udev monitor
  **/
-UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
+_public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
 {
         if (udev_monitor == NULL)
                 return NULL;
@@ -474,7 +416,7 @@ UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_moni
  * will be released.
  *
  **/
-UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor)
+_public_ void udev_monitor_unref(struct udev_monitor *udev_monitor)
 {
         if (udev_monitor == NULL)
                 return;
@@ -485,7 +427,6 @@ UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor)
                 close(udev_monitor->sock);
         udev_list_cleanup(&udev_monitor->filter_subsystem_list);
         udev_list_cleanup(&udev_monitor->filter_tag_list);
-        dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
         free(udev_monitor);
 }
 
@@ -497,7 +438,7 @@ UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor)
  *
  * Returns: the udev library context
  **/
-UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
+_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
 {
         if (udev_monitor == NULL)
                 return NULL;
@@ -512,7 +453,7 @@ UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor
  *
  * Returns: the socket file descriptor
  **/
-UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
+_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
 {
         if (udev_monitor == NULL)
                 return -1;
@@ -571,14 +512,14 @@ tag:
  *
  * Returns: a new udev device, or #NULL, in case of an error
  **/
-UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
+_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
 {
         struct udev_device *udev_device;
         struct msghdr smsg;
         struct iovec iov;
         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
         struct cmsghdr *cmsg;
-        struct sockaddr_nl snl;
+        union sockaddr_union snl;
         struct ucred *cred;
         char buf[8192];
         ssize_t buflen;
@@ -596,7 +537,7 @@ retry:
         smsg.msg_control = cred_msg;
         smsg.msg_controllen = sizeof(cred_msg);
 
-        if (udev_monitor->snl.nl_family != 0) {
+        if (udev_monitor->snl.nl.nl_family != 0) {
                 smsg.msg_name = &snl;
                 smsg.msg_namelen = sizeof(snl);
         }
@@ -604,27 +545,27 @@ retry:
         buflen = recvmsg(udev_monitor->sock, &smsg, 0);
         if (buflen < 0) {
                 if (errno != EINTR)
-                        info(udev_monitor->udev, "unable to receive message\n");
+                        dbg(udev_monitor->udev, "unable to receive message\n");
                 return NULL;
         }
 
         if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
-                info(udev_monitor->udev, "invalid message length\n");
+                dbg(udev_monitor->udev, "invalid message length\n");
                 return NULL;
         }
 
-        if (udev_monitor->snl.nl_family != 0) {
-                if (snl.nl_groups == 0) {
+        if (udev_monitor->snl.nl.nl_family != 0) {
+                if (snl.nl.nl_groups == 0) {
                         /* unicast message, check if we trust the sender */
-                        if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
-                            snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
-                                info(udev_monitor->udev, "unicast netlink message ignored\n");
+                        if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
+                            snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
+                                dbg(udev_monitor->udev, "unicast netlink message ignored\n");
                                 return NULL;
                         }
-                } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
-                        if (snl.nl_pid > 0) {
-                                info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
-                                     snl.nl_pid);
+                } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
+                        if (snl.nl.nl_pid > 0) {
+                                dbg(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
+                                     snl.nl.nl_pid);
                                 return NULL;
                         }
                 }
@@ -632,13 +573,13 @@ retry:
 
         cmsg = CMSG_FIRSTHDR(&smsg);
         if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-                info(udev_monitor->udev, "no sender credentials received, message ignored\n");
+                dbg(udev_monitor->udev, "no sender credentials received, message ignored\n");
                 return NULL;
         }
 
         cred = (struct ucred *)CMSG_DATA(cmsg);
         if (cred->uid != 0) {
-                info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
+                dbg(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
                 return NULL;
         }
 
@@ -657,13 +598,13 @@ retry:
                 /* kernel message with header */
                 bufpos = strlen(buf) + 1;
                 if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
-                        info(udev_monitor->udev, "invalid message length\n");
+                        dbg(udev_monitor->udev, "invalid message length\n");
                         return NULL;
                 }
 
                 /* check message header */
                 if (strstr(buf, "@/") == NULL) {
-                        info(udev_monitor->udev, "unrecognized message header\n");
+                        dbg(udev_monitor->udev, "unrecognized message header\n");
                         return NULL;
                 }
         }
@@ -686,7 +627,7 @@ retry:
         }
 
         if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
-                info(udev_monitor->udev, "missing values, invalid device\n");
+                dbg(udev_monitor->udev, "missing values, invalid device\n");
                 udev_device_unref(udev_device);
                 return NULL;
         }
@@ -716,98 +657,65 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
         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;
+        struct udev_list_entry *list_entry;
+        uint64_t tag_bloom_bits;
+
+        if (udev_monitor->snl.nl.nl_family == 0)
+                return -EINVAL;
 
         blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
         if (blen < 32)
                 return -EINVAL;
 
-        if (udev_monitor->sun.sun_family != 0) {
-                struct msghdr smsg;
-                struct iovec iov[2];
-                const char *action;
-                char header[2048];
-                char *s;
-
-                /* header <action>@<devpath> */
-                action = udev_device_get_action(udev_device);
-                if (action == NULL)
-                        return -EINVAL;
-                s = header;
-                if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
-                        return -EINVAL;
-                iov[0].iov_base = header;
-                iov[0].iov_len = (s - header)+1;
-
-                /* add properties list */
-                iov[1].iov_base = (char *)buf;
-                iov[1].iov_len = blen;
-
-                memset(&smsg, 0x00, sizeof(struct msghdr));
-                smsg.msg_iov = iov;
-                smsg.msg_iovlen = 2;
-                smsg.msg_name = &udev_monitor->sun;
-                smsg.msg_namelen = udev_monitor->addrlen;
-                count = sendmsg(udev_monitor->sock, &smsg, 0);
-                info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor);
-                return count;
+        /* add versioned header */
+        memset(&nlh, 0x00, 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);
+        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;
+        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);
         }
 
-        if (udev_monitor->snl.nl_family != 0) {
-                struct msghdr smsg;
-                struct iovec iov[2];
-                const char *val;
-                struct udev_monitor_netlink_header nlh;
-                struct udev_list_entry *list_entry;
-                uint64_t tag_bloom_bits;
-
-                /* add versioned header */
-                memset(&nlh, 0x00, 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);
-                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;
-                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);
-                }
-
-                /* add properties list */
-                nlh.properties_off = iov[0].iov_len;
-                nlh.properties_len = blen;
-                iov[1].iov_base = (char *)buf;
-                iov[1].iov_len = blen;
+        /* add properties list */
+        nlh.properties_off = iov[0].iov_len;
+        nlh.properties_len = blen;
+        iov[1].iov_base = (char *)buf;
+        iov[1].iov_len = blen;
 
-                memset(&smsg, 0x00, 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)
-                        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);
-                info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
-                return count;
-        }
-
-        return -EINVAL;
+        memset(&smsg, 0x00, 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)
+                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);
+        dbg(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
+        return count;
 }
 
 /**
@@ -823,7 +731,7 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
+_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
 {
         if (udev_monitor == NULL)
                 return -EINVAL;
@@ -846,7 +754,7 @@ UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_moni
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
+_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
 {
         if (udev_monitor == NULL)
                 return -EINVAL;
@@ -865,7 +773,7 @@ UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_moni
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
+_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
 {
         static struct sock_fprog filter = { 0, NULL };