X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fudev%2Flibudev-monitor.c;h=4406b55f97d625a44844518e1cbad9f83d0681de;hp=77dc55572f1396e185df185f30ba9ec1ed286a8d;hb=b49d9b50cfd377f28de0886330ba7bbd231fb472;hpb=3e2147858f21943d5f4a781c60f33ac22c6096ed diff --git a/src/udev/libudev-monitor.c b/src/udev/libudev-monitor.c index 77dc55572..4406b55f9 100644 --- a/src/udev/libudev-monitor.c +++ b/src/udev/libudev-monitor.c @@ -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 = 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 };