X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-monitor.c;h=85ab23bdd4aba8b5e2be1dae8f8f56908aebd3d1;hp=b3e5d5f348499bb20acb0a208fe414cfb75b4861;hb=13d83b88b600c24ada4ec78232f508ce7f8f3ca5;hpb=f712894dd4c2a2d8e374de133b7ed854e203fa96 diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c index b3e5d5f34..85ab23bdd 100644 --- a/libudev/libudev-monitor.c +++ b/libudev/libudev-monitor.c @@ -50,6 +50,7 @@ struct udev_monitor { socklen_t addrlen; struct udev_list_node filter_subsystem_list; struct udev_list_node filter_tag_list; + bool bound; }; enum udev_monitor_netlink_group { @@ -116,7 +117,7 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev) * * Returns: a new udev monitor, or #NULL, in case of an error **/ -struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path) +UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path) { struct udev_monitor *udev_monitor; struct stat statbuf; @@ -144,7 +145,7 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char 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_CLOEXEC, 0); + 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); @@ -155,32 +156,7 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char return udev_monitor; } -/** - * udev_monitor_new_from_netlink: - * @udev: udev library context - * @name: name of event source - * - * Create new udev monitor and connect to a specified event - * source. Valid sources identifiers are "udev" and "kernel". - * - * Applications should usually not connect directly to the - * "kernel" events, because the devices might not be useable - * at that time, before udev has configured them, and created - * device nodes. - * - * Accessing devices at the same time as udev, might result - * in unpredictable behavior. - * - * The "udev" events are sent out after udev has finished its - * event processing, all rules have been processed, and needed - * device nodes are created. - * - * 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 - **/ -struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) { struct udev_monitor *udev_monitor; unsigned int group; @@ -201,11 +177,16 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char if (udev_monitor == NULL) return NULL; - udev_monitor->sock = socket(PF_NETLINK, SOCK_DGRAM|SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); - if (udev_monitor->sock == -1) { - err(udev, "error getting socket: %m\n"); - free(udev_monitor); - return NULL; + if (fd < 0) { + udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); + if (udev_monitor->sock == -1) { + err(udev, "error getting socket: %m\n"); + free(udev_monitor); + return NULL; + } + } else { + udev_monitor->bound = true; + udev_monitor->sock = fd; } udev_monitor->snl.nl_family = AF_NETLINK; @@ -219,6 +200,36 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char return udev_monitor; } +/** + * udev_monitor_new_from_netlink: + * @udev: udev library context + * @name: name of event source + * + * Create new udev monitor and connect to a specified event + * source. Valid sources identifiers are "udev" and "kernel". + * + * Applications should usually not connect directly to the + * "kernel" events, because the devices might not be useable + * at that time, before udev has configured them, and created + * device nodes. + * + * Accessing devices at the same time as udev, might result + * in unpredictable behavior. + * + * The "udev" events are sent out after udev has finished its + * event processing, all rules have been processed, and needed + * device nodes are created. + * + * 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 + **/ +UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +{ + return udev_monitor_new_from_netlink_fd(udev, name, -1); +} + static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, unsigned short code, unsigned int data) { @@ -250,7 +261,7 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_update(struct udev_monitor *udev_monitor) +UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor) { struct sock_filter ins[512]; struct sock_fprog filter; @@ -342,6 +353,7 @@ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); /* install filter */ + memset(&filter, 0x00, sizeof(filter)); filter.len = i; filter.filter = ins; err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); @@ -361,18 +373,26 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { - int err; + int err = 0; const int on = 1; if (udev_monitor->sun.sun_family != 0) { - err = bind(udev_monitor->sock, - (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen); + 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); - err = bind(udev_monitor->sock, - (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl)); + 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; @@ -410,7 +430,7 @@ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) * * Returns: 0 on success, otherwise -1 on error. */ -int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) +UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) { if (udev_monitor == NULL) return -1; @@ -434,7 +454,7 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor) * * Returns: the passed udev monitor **/ -struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) +UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) { if (udev_monitor == NULL) return NULL; @@ -451,7 +471,7 @@ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) * will be released. * **/ -void udev_monitor_unref(struct udev_monitor *udev_monitor) +UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor) { if (udev_monitor == NULL) return; @@ -474,7 +494,7 @@ void udev_monitor_unref(struct udev_monitor *udev_monitor) * * Returns: the udev library context **/ -struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) +UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) { if (udev_monitor == NULL) return NULL; @@ -489,7 +509,7 @@ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) * * Returns: the socket file descriptor **/ -int udev_monitor_get_fd(struct udev_monitor *udev_monitor) +UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { if (udev_monitor == NULL) return -1; @@ -550,7 +570,7 @@ tag: * * Returns: a new udev device, or #NULL, in case of an error **/ -struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) +UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) { struct udev_device *udev_device; struct msghdr smsg; @@ -625,8 +645,11 @@ retry: if (memcmp(buf, "libudev", 8) == 0) { /* udev message needs proper version magic */ nlh = (struct udev_monitor_netlink_header *) buf; - if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) + if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) { + err(udev_monitor->udev, "ignored a message from an invalid release of udevadm (%x != %x)\n", + nlh->magic, htonl(UDEV_MONITOR_MAGIC)); return NULL; + } if (nlh->properties_off+32 > buflen) return NULL; bufpos = nlh->properties_off; @@ -800,14 +823,14 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +UDEV_EXPORT 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; if (subsystem == NULL) return -EINVAL; if (udev_list_entry_add(udev_monitor->udev, - &udev_monitor->filter_subsystem_list, subsystem, devtype, 0, 0) == NULL) + &udev_monitor->filter_subsystem_list, subsystem, devtype, 0) == NULL) return -ENOMEM; return 0; } @@ -824,14 +847,14 @@ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_mo * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) +UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) { if (udev_monitor == NULL) return -EINVAL; if (tag == NULL) return -EINVAL; if (udev_list_entry_add(udev_monitor->udev, - &udev_monitor->filter_tag_list, tag, NULL, 0, 0) == NULL) + &udev_monitor->filter_tag_list, tag, NULL, 0) == NULL) return -ENOMEM; return 0; } @@ -844,7 +867,7 @@ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const c * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) +UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { static struct sock_fprog filter = { 0, NULL };