From b1c097af8df58a94cba031a347061b7cb9b62d9b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:45:52 +0900 Subject: [PATCH 01/13] sd-device: introduce sd_device_monitor --- src/libsystemd/libsystemd.sym | 16 + src/libsystemd/meson.build | 2 + .../sd-device/device-monitor-private.h | 20 + src/libsystemd/sd-device/device-monitor.c | 755 ++++++++++++++++++ src/systemd/sd-device.h | 26 + 5 files changed, 819 insertions(+) create mode 100644 src/libsystemd/sd-device/device-monitor-private.h create mode 100644 src/libsystemd/sd-device/device-monitor.c diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 8d0bebe2ad..8d46081ec4 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -647,4 +647,20 @@ global: sd_hwdb_enumerate; sd_id128_get_boot_app_specific; + + sd_device_monitor_new; + sd_device_monitor_ref; + sd_device_monitor_unref; + + sd_device_monitor_set_receive_buffer_size; + sd_device_monitor_attach_event; + sd_device_monitor_detach_event; + sd_device_monitor_get_event; + sd_device_monitor_start; + sd_device_monitor_stop; + + sd_device_monitor_filter_add_match_subsystem_devtype; + sd_device_monitor_filter_add_match_tag; + sd_device_monitor_filter_update; + sd_device_monitor_filter_remove; } LIBSYSTEMD_239; diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index d95406e7ac..3cfc9753b1 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -53,6 +53,8 @@ libsystemd_sources = files(''' sd-device/device-enumerator-private.h sd-device/device-enumerator.c sd-device/device-internal.h + sd-device/device-monitor-private.h + sd-device/device-monitor.c sd-device/device-private.c sd-device/device-private.h sd-device/device-util.h diff --git a/src/libsystemd/sd-device/device-monitor-private.h b/src/libsystemd/sd-device/device-monitor-private.h new file mode 100644 index 0000000000..2659cc3c46 --- /dev/null +++ b/src/libsystemd/sd-device/device-monitor-private.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-device.h" + +typedef enum MonitorNetlinkGroup { + MONITOR_GROUP_NONE, + MONITOR_GROUP_KERNEL, + MONITOR_GROUP_UDEV, + _MONITOR_NETLINK_GROUP_MAX, + _MONITOR_NETLINK_GROUP_INVALID = -1, +} MonitorNetlinkGroup; + +int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd); +int device_monitor_disconnect(sd_device_monitor *m); +int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender); +int device_monitor_enable_receiving(sd_device_monitor *m); +int device_monitor_get_fd(sd_device_monitor *m); +int device_monitor_send_device(sd_device_monitor *m, sd_device_monitor *destination, sd_device *device); +int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret); diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c new file mode 100644 index 0000000000..6e94ff1fa0 --- /dev/null +++ b/src/libsystemd/sd-device/device-monitor.c @@ -0,0 +1,755 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include +#include +#include + +#include "sd-device.h" +#include "sd-event.h" + +#include "MurmurHash2.h" +#include "alloc-util.h" +#include "device-monitor-private.h" +#include "device-private.h" +#include "device-util.h" +#include "fd-util.h" +#include "format-util.h" +#include "hashmap.h" +#include "missing.h" +#include "mount-util.h" +#include "set.h" +#include "socket-util.h" +#include "string-util.h" +#include "strv.h" + +struct sd_device_monitor { + unsigned n_ref; + + int sock; + union sockaddr_union snl; + union sockaddr_union snl_trusted_sender; + bool bound; + + Hashmap *subsystem_filter; + Set *tag_filter; + bool filter_uptodate; + + sd_event *event; + sd_event_source *event_source; + int64_t event_priority; + sd_device_monitor_handler_t callback; + void *userdata; +}; + +#define UDEV_MONITOR_MAGIC 0xfeedcafe + +typedef struct monitor_netlink_header { + /* "libudev" prefix to distinguish libudev and kernel messages */ + char prefix[8]; + /* Magic to protect against daemon <-> Library message format mismatch + * Used in the kernel from socket filter rules; needs to be stored in network order */ + unsigned magic; + /* Total length of header structure known to the sender */ + unsigned header_size; + /* Properties string buffer */ + unsigned properties_off; + unsigned properties_len; + /* Hashes of primary device properties strings, to let libudev subscribers + * use in-kernel socket filters; values need to be stored in network order */ + unsigned filter_subsystem_hash; + unsigned filter_devtype_hash; + unsigned filter_tag_bloom_hi; + unsigned filter_tag_bloom_lo; +} monitor_netlink_header; + +static int monitor_set_nl_address(sd_device_monitor *m) { + union sockaddr_union snl; + socklen_t addrlen; + + assert(m); + + /* Get the address the kernel has assigned us. + * It is usually, but not necessarily the pid. */ + addrlen = sizeof(struct sockaddr_nl); + if (getsockname(m->sock, &snl.sa, &addrlen) < 0) + return -errno; + + m->snl.nl.nl_pid = snl.nl.nl_pid; + return 0; +} + +int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender) { + assert_return(m, -EINVAL); + assert_return(sender, -EINVAL); + + m->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; + return 0; +} + +_public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) { + int n = (int) size; + + assert_return(m, -EINVAL); + assert_return((size_t) n != size, -EINVAL); + + if (setsockopt(m->sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) < 0 && + setsockopt(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, &n, sizeof(n)) < 0) + return -errno; + + return 0; +} + +int device_monitor_disconnect(sd_device_monitor *m) { + assert(m); + + m->sock = safe_close(m->sock); + return 0; +} + +int device_monitor_get_fd(sd_device_monitor *m) { + assert_return(m, -EINVAL); + + return m->sock; +} + +int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; + _cleanup_close_ int sock = -1; + int r; + + assert_return(ret, -EINVAL); + assert_return(group >= 0 && group < _MONITOR_NETLINK_GROUP_MAX, -EINVAL); + + if (group == MONITOR_GROUP_UDEV && + access("/run/udev/control", F_OK) < 0 && + dev_is_devtmpfs() <= 0) { + + /* + * We do not support subscribing to uevents if no instance of + * udev is running. Uevents would otherwise broadcast the + * processing data of the host into containers, which is not + * desired. + * + * Containers will currently not get any udev uevents, until + * a supporting infrastructure is available. + * + * We do not set a netlink multicast group here, so the socket + * will not receive any messages. + */ + + log_debug("The udev service seems not to be active, disabling the monitor"); + group = MONITOR_GROUP_NONE; + } + + if (fd < 0) { + sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); + if (sock < 0) + return log_debug_errno(errno, "Failed to create socket: %m"); + } + + m = new(sd_device_monitor, 1); + if (!m) + return -ENOMEM; + + *m = (sd_device_monitor) { + .n_ref = 1, + .sock = fd >= 0 ? fd : TAKE_FD(sock), + .bound = fd >= 0, + .snl.nl.nl_family = AF_NETLINK, + .snl.nl.nl_groups = group, + }; + + if (fd >= 0) { + r = monitor_set_nl_address(m); + if (r < 0) + return log_debug_errno(r, "Failed to set netlink address: %m"); + } + + *ret = TAKE_PTR(m); + return 0; +} + +_public_ int sd_device_monitor_new(sd_device_monitor **ret) { + return device_monitor_new_full(ret, MONITOR_GROUP_UDEV, -1); +} + +_public_ int sd_device_monitor_stop(sd_device_monitor *m) { + assert_return(m, -EINVAL); + + m->event_source = sd_event_source_unref(m->event_source); + (void) device_monitor_disconnect(m); + + return 0; +} + +static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + sd_device_monitor *m = userdata; + + assert(m); + + if (device_monitor_receive_device(m, &device) <= 0) + return 0; + + if (m->callback) + return m->callback(m, device, m->userdata); + + return 0; +} + +_public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata, const char *description) { + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + int r; + + assert_return(m, -EINVAL); + + if (!m->event) { + r = sd_device_monitor_attach_event(m, NULL, 0); + if (r < 0) + return r; + } + + r = device_monitor_enable_receiving(m); + if (r < 0) + return r; + + m->callback = callback; + m->userdata = userdata; + + r = sd_event_add_io(m->event, &s, m->sock, EPOLLIN, device_monitor_event_handler, m); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s, m->event_priority); + if (r < 0) + return r; + + if (description) { + r = sd_event_source_set_description(s, description); + if (r < 0) + return r; + } + + m->event_source = TAKE_PTR(s); + + return 0; +} + +_public_ int sd_device_monitor_detach_event(sd_device_monitor *m) { + assert_return(m, -EINVAL); + + (void) sd_device_monitor_stop(m); + m->event = sd_event_unref(m->event); + + return 0; +} + +_public_ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event, int64_t priority) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->event, -EBUSY); + + if (event) + m->event = sd_event_ref(event); + else { + r = sd_event_default(&m->event); + if (r < 0) + return 0; + } + + m->event_priority = priority; + + return 0; +} + +_public_ sd_event *sd_device_monitor_get_event(sd_device_monitor *m) { + assert_return(m, NULL); + + return m->event; +} + +int device_monitor_enable_receiving(sd_device_monitor *m) { + int r; + + assert_return(m, -EINVAL); + + if (!m->filter_uptodate) { + r = sd_device_monitor_filter_update(m); + if (r < 0) + return log_debug_errno(r, "Failed to update filter: %m"); + } + + if (!m->bound) { + if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0) + return log_debug_errno(errno, "Failed to bind monitoring socket to event source: %m"); + + m->bound = true; + } + + r = monitor_set_nl_address(m); + if (r < 0) + return log_debug_errno(r, "Failed to set address: %m"); + + /* enable receiving of sender credentials */ + if (setsockopt(m->sock, SOL_SOCKET, SO_PASSCRED, &const_int_one, sizeof(const_int_one)) < 0) + return log_debug_errno(errno, "Failed to set socket option SO_PASSCRED: %m"); + + return 0; +} + +static sd_device_monitor *device_monitor_free(sd_device_monitor *m) { + assert(m); + + (void) sd_device_monitor_detach_event(m); + + hashmap_free_free_free(m->subsystem_filter); + set_free_free(m->tag_filter); + + return mfree(m); +} + +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_monitor, sd_device_monitor, device_monitor_free); + +static int passes_filter(sd_device_monitor *m, sd_device *device) { + const char *tag, *subsystem, *devtype, *s, *d = NULL; + Iterator i; + int r; + + assert_return(m, -EINVAL); + assert_return(device, -EINVAL); + + if (hashmap_isempty(m->subsystem_filter)) + goto tag; + + r = sd_device_get_subsystem(device, &s); + if (r < 0) + return r; + + r = sd_device_get_devtype(device, &d); + if (r < 0 && r != -ENOENT) + return r; + + HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter, i) { + if (!streq(s, subsystem)) + continue; + + if (!devtype) + goto tag; + + if (!d) + continue; + + if (streq(d, devtype)) + goto tag; + } + + return 0; + +tag: + if (set_isempty(m->tag_filter)) + return 1; + + SET_FOREACH(tag, m->tag_filter, i) + if (sd_device_has_tag(device, tag) > 0) + return 1; + + return 0; +} + +int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + union { + monitor_netlink_header nlh; + char raw[8192]; + } buf; + struct iovec iov = { + .iov_base = &buf, + .iov_len = sizeof(buf) + }; + char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; + union sockaddr_union snl; + struct msghdr smsg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cred_msg, + .msg_controllen = sizeof(cred_msg), + .msg_name = &snl, + .msg_namelen = sizeof(snl), + }; + struct cmsghdr *cmsg; + struct ucred *cred; + ssize_t buflen, bufpos; + bool is_initialized = false; + int r; + + assert(ret); + + buflen = recvmsg(m->sock, &smsg, 0); + if (buflen < 0) { + if (errno != EINTR) + log_debug_errno(errno, "Failed to receive message: %m"); + return -errno; + } + + if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) + return log_debug_errno(EINVAL, "Invalid message length."); + + if (snl.nl.nl_groups == MONITOR_GROUP_NONE) { + /* unicast message, check if we trust the sender */ + if (m->snl_trusted_sender.nl.nl_pid == 0 || + snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid) + return log_debug_errno(EAGAIN, "Unicast netlink message ignored."); + + } else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) { + if (snl.nl.nl_pid > 0) + return log_debug_errno(EAGAIN, "Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid); + } + + cmsg = CMSG_FIRSTHDR(&smsg); + if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) + return log_debug_errno(EAGAIN, "No sender credentials received, message ignored."); + + cred = (struct ucred*) CMSG_DATA(cmsg); + if (cred->uid != 0) + return log_debug_errno(EAGAIN, "Sender uid="UID_FMT", message ignored.", cred->uid); + + if (streq(buf.raw, "libudev")) { + /* udev message needs proper version magic */ + if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) + return log_debug_errno(EAGAIN, "Invalid message signature (%x != %x)", + buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC)); + + if (buf.nlh.properties_off+32 > (size_t) buflen) + return log_debug_errno(EAGAIN, "Invalid message length (%u > %zd)", + buf.nlh.properties_off+32, buflen); + + bufpos = buf.nlh.properties_off; + + /* devices received from udev are always initialized */ + is_initialized = true; + + } else { + /* kernel message with header */ + bufpos = strlen(buf.raw) + 1; + if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen) + return log_debug_errno(EAGAIN, "Invalid message length"); + + /* check message header */ + if (!strstr(buf.raw, "@/")) + return log_debug_errno(EAGAIN, "Invalid message header"); + } + + r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos); + if (r < 0) + return log_debug_errno(r, "Failed to create device: %m"); + + if (is_initialized) + device_set_is_initialized(device); + + /* Skip device, if it does not pass the current filter */ + r = passes_filter(m, device); + if (r < 0) + return log_debug_errno(r, "Failed to check received device passing filter: %m"); + + if (r == 0) + log_debug("Received device does not pass filter, ignoring"); + else + *ret = TAKE_PTR(device); + + return r; +} + +static uint32_t string_hash32(const char *str) { + return MurmurHash2(str, strlen(str), 0); +} + +/* Get a bunch of bit numbers out of the hash, and set the bits in our bit field */ +static uint64_t string_bloom64(const char *str) { + uint64_t bits = 0; + uint32_t hash = string_hash32(str); + + bits |= 1LLU << (hash & 63); + bits |= 1LLU << ((hash >> 6) & 63); + bits |= 1LLU << ((hash >> 12) & 63); + bits |= 1LLU << ((hash >> 18) & 63); + return bits; +} + +int device_monitor_send_device( + sd_device_monitor *m, + sd_device_monitor *destination, + sd_device *device) { + + 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, + }; + /* default destination for sending */ + union sockaddr_union default_destination = { + .nl.nl_family = AF_NETLINK, + .nl.nl_groups = MONITOR_GROUP_UDEV, + }; + uint64_t tag_bloom_bits; + const char *buf, *val; + ssize_t count; + size_t blen; + int r; + + assert(m); + assert(device); + + r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen); + if (r < 0) + return log_debug_errno(r, "Failed to get device properties: %m"); + if (blen < 32) { + log_debug("Device buffer is too small to contain a valid device"); + return -EINVAL; + } + + /* fill in versioned header */ + r = sd_device_get_subsystem(device, &val); + if (r < 0) + return log_debug_errno(r, "Failed to get device subsystem: %m"); + nlh.filter_subsystem_hash = htobe32(string_hash32(val)); + + if (sd_device_get_devtype(device, &val) >= 0 && val) + nlh.filter_devtype_hash = htobe32(string_hash32(val)); + + /* add tag bloom filter */ + tag_bloom_bits = 0; + FOREACH_DEVICE_TAG(device, val) + tag_bloom_bits |= string_bloom64(val); + + if (tag_bloom_bits > 0) { + nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff); + } + + /* add properties list */ + nlh.properties_off = iov[0].iov_len; + nlh.properties_len = blen; + iov[1] = (struct iovec) { + .iov_base = (char*) buf, + .iov_len = blen, + }; + + /* + * Use custom address for target, or the default one. + * + * If we send to a multicast group, we will get + * ECONNREFUSED, which is expected. + */ + smsg.msg_name = destination ? &destination->snl : &default_destination; + smsg.msg_namelen = sizeof(struct sockaddr_nl); + count = sendmsg(m->sock, &smsg, 0); + if (count < 0) { + if (!destination && errno == ECONNREFUSED) { + log_debug("Passed device to netlink monitor"); + return 0; + } else + return log_debug_errno(errno, "Failed to send device to netlink monitor"); + } + + log_debug("Passed %zi byte device to netlink monitor", count); + return count; +} + +static void bpf_stmt(struct sock_filter *ins, unsigned *i, + unsigned short code, unsigned data) { + ins[(*i)++] = (struct sock_filter) { + .code = code, + .k = data, + }; +} + +static void bpf_jmp(struct sock_filter *ins, unsigned *i, + unsigned short code, unsigned data, + unsigned short jt, unsigned short jf) { + ins[(*i)++] = (struct sock_filter) { + .code = code, + .jt = jt, + .jf = jf, + .k = data, + }; +} + +_public_ int sd_device_monitor_filter_update(sd_device_monitor *m) { + struct sock_filter ins[512] = {}; + struct sock_fprog filter; + const char *subsystem, *devtype, *tag; + unsigned i = 0; + Iterator it; + + assert_return(m, -EINVAL); + + if (hashmap_isempty(m->subsystem_filter) && + set_isempty(m->tag_filter)) { + m->filter_uptodate = true; + return 0; + } + + /* load magic in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, magic)); + /* jump if magic matches */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0); + /* wrong magic, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + if (!set_isempty(m->tag_filter)) { + int tag_matches = set_size(m->tag_filter); + + /* add all tags matches */ + SET_FOREACH(tag, m->tag_filter, it) { + uint64_t tag_bloom_bits = string_bloom64(tag); + uint32_t tag_bloom_hi = tag_bloom_bits >> 32; + uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_tag_bloom_hi)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi); + /* jump to next tag if it does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3); + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_tag_bloom_lo)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo); + /* jump behind end of tag match block if tag matches */ + tag_matches--; + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0); + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + } + + /* add all subsystem matches */ + if (!hashmap_isempty(m->subsystem_filter)) { + HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter, it) { + uint32_t hash = string_hash32(subsystem); + + /* load device subsystem value in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_subsystem_hash)); + if (!devtype) { + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); + } else { + hash = string_hash32(devtype); + + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3); + /* load device devtype value in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_devtype_hash)); + /* jump if value does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + if (i+1 >= ELEMENTSOF(ins)) + return -E2BIG; + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + /* install filter */ + filter = (struct sock_fprog) { + .len = i, + .filter = ins, + }; + if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0) + return -errno; + + m->filter_uptodate = true; + return 0; +} + +_public_ int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype) { + _cleanup_free_ char *s = NULL, *d = NULL; + int r; + + assert_return(m, -EINVAL); + assert_return(subsystem, -EINVAL); + + s = strdup(subsystem); + if (!s) + return -ENOMEM; + + if (devtype) { + d = strdup(devtype); + if (!d) + return -ENOMEM; + } + + r = hashmap_ensure_allocated(&m->subsystem_filter, NULL); + if (r < 0) + return r; + + r = hashmap_put(m->subsystem_filter, s, d); + if (r < 0) + return r; + + s = d = NULL; + m->filter_uptodate = false; + + return 0; +} + +_public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag) { + _cleanup_free_ char *t = NULL; + int r; + + assert_return(m, -EINVAL); + assert_return(tag, -EINVAL); + + t = strdup(tag); + if (!t) + return -ENOMEM; + + r = set_ensure_allocated(&m->tag_filter, &string_hash_ops); + if (r < 0) + return r; + + r = set_put(m->tag_filter, t); + if (r == -EEXIST) + return 0; + if (r < 0) + return r; + + TAKE_PTR(t); + m->filter_uptodate = false; + + return 0; +} + +_public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) { + static const struct sock_fprog filter = { 0, NULL }; + + assert_return(m, -EINVAL); + + m->subsystem_filter = hashmap_free_free_free(m->subsystem_filter); + m->tag_filter = set_free_free(m->tag_filter); + + if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0) + return -errno; + + m->filter_uptodate = true; + return 0; +} diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 406db8866d..43fb4a0c2a 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -21,12 +21,19 @@ #include #include +#include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; typedef struct sd_device sd_device; typedef struct sd_device_enumerator sd_device_enumerator; +typedef struct sd_device_monitor sd_device_monitor; + +/* callback */ + +typedef int (*sd_device_monitor_handler_t)(sd_device_monitor *m, sd_device *device, void *userdata); /* device */ @@ -89,8 +96,27 @@ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const c int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent); int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator); +/* device monitor */ + +int sd_device_monitor_new(sd_device_monitor **ret); +sd_device_monitor *sd_device_monitor_ref(sd_device_monitor *m); +sd_device_monitor *sd_device_monitor_unref(sd_device_monitor *m); + +int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size); +int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event, int64_t priority); +int sd_device_monitor_detach_event(sd_device_monitor *m); +sd_event *sd_device_monitor_get_event(sd_device_monitor *m); +int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata, const char *description); +int sd_device_monitor_stop(sd_device_monitor *m); + +int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype); +int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag); +int sd_device_monitor_filter_update(sd_device_monitor *m); +int sd_device_monitor_filter_remove(sd_device_monitor *m); + _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device, sd_device_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_enumerator, sd_device_enumerator_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_monitor, sd_device_monitor_unref); _SD_END_DECLARATIONS; From e39b4d254de7c12be99a17cc54026695b0bd9c27 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:46:31 +0900 Subject: [PATCH 02/13] libudev: re-implement udev-monitor by sd_device_monitor --- src/libudev/libudev-monitor.c | 588 +++------------------------------- src/libudev/libudev-util.c | 16 - 2 files changed, 42 insertions(+), 562 deletions(-) diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index 50c3925058..5be4d40752 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -1,33 +1,17 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include "libudev.h" #include "alloc-util.h" +#include "device-monitor-private.h" #include "device-private.h" #include "device-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "format-util.h" -#include "hashmap.h" #include "libudev-device-internal.h" #include "libudev-private.h" -#include "missing.h" -#include "mount-util.h" -#include "set.h" -#include "socket-util.h" #include "string-util.h" -#include "strv.h" /** * SECTION:libudev-monitor @@ -44,101 +28,35 @@ struct udev_monitor { struct udev *udev; unsigned n_ref; - int sock; - union sockaddr_union snl; - union sockaddr_union snl_trusted_sender; - union sockaddr_union snl_destination; - socklen_t addrlen; - Hashmap *subsystem_filter; - Set *tag_filter; - bool bound; + sd_device_monitor *monitor; }; -enum udev_monitor_netlink_group { - UDEV_MONITOR_NONE, - UDEV_MONITOR_KERNEL, - UDEV_MONITOR_UDEV, -}; - -#define UDEV_MONITOR_MAGIC 0xfeedcafe -struct udev_monitor_netlink_header { - /* "libudev" prefix to distinguish libudev and kernel messages */ - char prefix[8]; - /* - * magic to protect against daemon <-> library message format mismatch - * used in the kernel from socket filter rules; needs to be stored in network order - */ - unsigned magic; - /* total length of header structure known to the sender */ - unsigned header_size; - /* properties string buffer */ - unsigned properties_off; - unsigned properties_len; - /* - * hashes of primary device properties strings, to let libudev subscribers - * use in-kernel socket filters; values need to be stored in network order - */ - unsigned filter_subsystem_hash; - unsigned filter_devtype_hash; - unsigned filter_tag_bloom_hi; - unsigned filter_tag_bloom_lo; -}; - -static int udev_monitor_set_nl_address(struct udev_monitor *udev_monitor) { - union sockaddr_union snl; - socklen_t addrlen; - - assert(udev_monitor); - - /* Get the address the kernel has assigned us. - * It is usually, but not necessarily the pid. */ - addrlen = sizeof(struct sockaddr_nl); - if (getsockname(udev_monitor->sock, &snl.sa, &addrlen) < 0) - return -errno; - - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - return 0; +static MonitorNetlinkGroup monitor_netlink_group_from_string(const char *name) { + if (!name) + return MONITOR_GROUP_NONE; + if (streq(name, "udev")) + return MONITOR_GROUP_UDEV; + if (streq(name, "kernel")) + return MONITOR_GROUP_KERNEL; + return _MONITOR_NETLINK_GROUP_INVALID; } struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor = NULL; - _cleanup_close_ int sock = -1; - unsigned group; + MonitorNetlinkGroup g; int r; - assert_return_errno(!name || STR_IN_SET(name, "udev", "kernel"), NULL, EINVAL); - - if (!name) - group = UDEV_MONITOR_NONE; - else if (streq(name, "udev")) { - /* - * We do not support subscribing to uevents if no instance of - * udev is running. Uevents would otherwise broadcast the - * processing data of the host into containers, which is not - * desired. - * - * Containers will currently not get any udev uevents, until - * a supporting infrastructure is available. - * - * We do not set a netlink multicast group here, so the socket - * will not receive any messages. - */ - if (access("/run/udev/control", F_OK) < 0 && dev_is_devtmpfs() <= 0) { - log_debug("The udev service seems not to be active, disabling the monitor"); - group = UDEV_MONITOR_NONE; - } else - group = UDEV_MONITOR_UDEV; - } else { - assert(streq(name, "kernel")); - group = UDEV_MONITOR_KERNEL; + g = monitor_netlink_group_from_string(name); + if (g < 0) { + errno = EINVAL; + return NULL; } - if (fd < 0) { - sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - if (sock < 0) { - log_debug_errno(errno, "Failed to create socket: %m"); - return NULL; - } + r = device_monitor_new_full(&m, g, fd); + if (r < 0) { + errno = -r; + return NULL; } udev_monitor = new(struct udev_monitor, 1); @@ -150,24 +68,9 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c *udev_monitor = (struct udev_monitor) { .udev = udev, .n_ref = 1, - .sock = fd >= 0 ? fd : TAKE_FD(sock), - .bound = fd >= 0, - .snl.nl.nl_family = AF_NETLINK, - .snl.nl.nl_groups = group, - - /* default destination for sending */ - .snl_destination.nl.nl_family = AF_NETLINK, - .snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV, + .monitor = TAKE_PTR(m), }; - if (fd >= 0) { - r = udev_monitor_set_nl_address(udev_monitor); - if (r < 0) { - log_debug_errno(r, "Failed to set netlink address: %m"); - return NULL; - } - } - return TAKE_PTR(udev_monitor); } @@ -197,25 +100,6 @@ _public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, c return udev_monitor_new_from_netlink_fd(udev, name, -1); } -static void bpf_stmt(struct sock_filter *ins, unsigned *i, - unsigned short code, unsigned data) { - ins[(*i)++] = (struct sock_filter) { - .code = code, - .k = data, - }; -} - -static void bpf_jmp(struct sock_filter *ins, unsigned *i, - unsigned short code, unsigned data, - unsigned short jt, unsigned short jf) { - ins[(*i)++] = (struct sock_filter) { - .code = code, - .jt = jt, - .jf = jf, - .k = data, - }; -} - /** * udev_monitor_filter_update: * @udev_monitor: monitor @@ -226,106 +110,16 @@ static void bpf_jmp(struct sock_filter *ins, unsigned *i, * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) { - struct sock_filter ins[512] = {}; - struct sock_fprog filter; - const char *subsystem, *devtype, *tag; - unsigned i = 0; - Iterator it; - assert_return(udev_monitor, -EINVAL); - if (hashmap_isempty(udev_monitor->subsystem_filter) && - set_isempty(udev_monitor->tag_filter)) - return 0; - - /* load magic in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic)); - /* jump if magic matches */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0); - /* wrong magic, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (!set_isempty(udev_monitor->tag_filter)) { - int tag_matches = set_size(udev_monitor->tag_filter); - - /* add all tags matches */ - SET_FOREACH(tag, udev_monitor->tag_filter, it) { - uint64_t tag_bloom_bits = util_string_bloom64(tag); - uint32_t tag_bloom_hi = tag_bloom_bits >> 32; - uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi); - /* jump to next tag if it does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3); - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo); - /* jump behind end of tag match block if tag matches */ - tag_matches--; - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0); - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* add all subsystem matches */ - if (!hashmap_isempty(udev_monitor->subsystem_filter)) { - HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, it) { - uint32_t hash = util_string_hash32(subsystem); - - /* load device subsystem value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash)); - if (!devtype) { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } else { - hash = util_string_hash32(devtype); - - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3); - /* load device devtype value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash)); - /* jump if value does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (i+1 >= ELEMENTSOF(ins)) - return -E2BIG; - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - /* install filter */ - filter = (struct sock_fprog) { - .len = i, - .filter = ins, - }; - if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0) - return -errno; - - return 0; + return sd_device_monitor_filter_update(udev_monitor->monitor); } int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) { assert_return(udev_monitor, -EINVAL); assert_return(sender, -EINVAL); - udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; - return 0; + return device_monitor_allow_unicast_sender(udev_monitor->monitor, sender->monitor); } /** @@ -337,30 +131,9 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { - int r; - assert_return(udev_monitor, -EINVAL); - r = udev_monitor_filter_update(udev_monitor); - if (r < 0) - return log_debug_errno(r, "Failed to update filter: %m"); - - if (!udev_monitor->bound) { - if (bind(udev_monitor->sock, &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)) < 0) - return log_debug_errno(errno, "Failed to bind udev monitor socket to event source: %m"); - - udev_monitor->bound = true; - } - - r = udev_monitor_set_nl_address(udev_monitor); - if (r < 0) - return log_debug_errno(r, "Failed to set address: %m"); - - /* enable receiving of sender credentials */ - if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &const_int_one, sizeof(const_int_one)) < 0) - return log_debug_errno(errno, "Failed to set socket option SO_PASSCRED: %m"); - - return 0; + return device_monitor_enable_receiving(udev_monitor->monitor); } /** @@ -376,25 +149,19 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) { assert_return(udev_monitor, -EINVAL); - if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0) - return -errno; - - return 0; + return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size); } int udev_monitor_disconnect(struct udev_monitor *udev_monitor) { assert(udev_monitor); - udev_monitor->sock = safe_close(udev_monitor->sock); - return 0; + return device_monitor_disconnect(udev_monitor->monitor); } static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) { assert(udev_monitor); - udev_monitor_disconnect(udev_monitor); - hashmap_free_free_free(udev_monitor->subsystem_filter); - set_free_free(udev_monitor->tag_filter); + sd_device_monitor_unref(udev_monitor->monitor); return mfree(udev_monitor); } @@ -444,166 +211,24 @@ _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) { _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { assert_return(udev_monitor, -EINVAL); - return udev_monitor->sock; -} - -static int passes_filter(struct udev_monitor *udev_monitor, sd_device *device) { - const char *tag, *subsystem, *devtype, *s, *d = NULL; - Iterator i; - int r; - - assert_return(udev_monitor, -EINVAL); - assert_return(device, -EINVAL); - - if (hashmap_isempty(udev_monitor->subsystem_filter)) - goto tag; - - r = sd_device_get_subsystem(device, &s); - if (r < 0) - return r; - - r = sd_device_get_devtype(device, &d); - if (r < 0 && r != -ENOENT) - return r; - - HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, i) { - if (!streq(s, subsystem)) - continue; - - if (!devtype) - goto tag; - - if (!d) - continue; - - if (streq(d, devtype)) - goto tag; - } - - return 0; - -tag: - if (set_isempty(udev_monitor->tag_filter)) - return 1; - - SET_FOREACH(tag, udev_monitor->tag_filter, i) - if (sd_device_has_tag(device, tag) > 0) - return 1; - - return 0; -} - -static int udev_monitor_receive_device_one(struct udev_monitor *udev_monitor, sd_device **ret) { - _cleanup_(sd_device_unrefp) sd_device *device = NULL; - union { - struct udev_monitor_netlink_header nlh; - char raw[8192]; - } buf; - struct iovec iov = { - .iov_base = &buf, - .iov_len = sizeof(buf) - }; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - union sockaddr_union snl; - struct msghdr smsg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cred_msg, - .msg_controllen = sizeof(cred_msg), - .msg_name = &snl, - .msg_namelen = sizeof(snl), - }; - struct cmsghdr *cmsg; - struct ucred *cred; - ssize_t buflen, bufpos; - bool is_initialized = false; - int r; - - assert(ret); - - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) - log_debug_errno(errno, "Failed to receive message: %m"); - return -errno; - } - - if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) - return log_debug_errno(EINVAL, "Invalid message length."); - - if (snl.nl.nl_groups == UDEV_MONITOR_NONE) { - /* unicast message, check if we trust the sender */ - if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || - snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) - return log_debug_errno(EAGAIN, "Unicast netlink message ignored."); - - } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { - if (snl.nl.nl_pid > 0) - return log_debug_errno(EAGAIN, "Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid); - } - - cmsg = CMSG_FIRSTHDR(&smsg); - if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) - return log_debug_errno(EAGAIN, "No sender credentials received, message ignored."); - - cred = (struct ucred*) CMSG_DATA(cmsg); - if (cred->uid != 0) - return log_debug_errno(EAGAIN, "Sender uid="UID_FMT", message ignored.", cred->uid); - - if (streq(buf.raw, "libudev")) { - /* udev message needs proper version magic */ - if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) - return log_debug_errno(EAGAIN, "Invalid message signature (%x != %x)", - buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC)); - - if (buf.nlh.properties_off+32 > (size_t) buflen) - return log_debug_errno(EAGAIN, "Invalid message length (%u > %zd)", - buf.nlh.properties_off+32, buflen); - - bufpos = buf.nlh.properties_off; - - /* devices received from udev are always initialized */ - is_initialized = true; - - } else { - /* kernel message with header */ - bufpos = strlen(buf.raw) + 1; - if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen) - return log_debug_errno(EAGAIN, "Invalid message length"); - - /* check message header */ - if (!strstr(buf.raw, "@/")) - return log_debug_errno(EAGAIN, "Invalid message header"); - } - - r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos); - if (r < 0) - return log_debug_errno(r, "Failed to create device: %m"); - - if (is_initialized) - device_set_is_initialized(device); - - /* skip device, if it does not pass the current filter */ - if (passes_filter(udev_monitor, device) <= 0) - return 0; - - *ret = TAKE_PTR(device); - return 1; + return device_monitor_get_fd(udev_monitor->monitor); } int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) { - struct pollfd pfd = { - .fd = udev_monitor->sock, - .events = POLLIN, - }; + struct pollfd pfd; int r; assert(udev_monitor); assert(ret); + pfd = (struct pollfd) { + .fd = device_monitor_get_fd(udev_monitor->monitor), + .events = POLLIN, + }; + for (;;) { /* r == 0 means a device is received but it does not pass the current filter. */ - r = udev_monitor_receive_device_one(udev_monitor, ret); + r = device_monitor_receive_device(udev_monitor->monitor, ret); if (r != 0) return r; @@ -658,95 +283,16 @@ _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *ud return udev_device_new(udev_monitor->udev, device); } -static int udev_monitor_send_sd_device( - struct udev_monitor *udev_monitor, - struct udev_monitor *destination, - sd_device *device) { - - 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, - }; - uint64_t tag_bloom_bits; - const char *buf, *val; - ssize_t count; - size_t blen; - int r; - - assert(udev_monitor); - assert(device); - - r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen); - if (r < 0) - return log_debug_errno(r, "Failed to get device properties: %m"); - if (blen < 32) { - log_debug("Device buffer is too small to contain a valid device"); - return -EINVAL; - } - - /* fill in versioned header */ - r = sd_device_get_subsystem(device, &val); - if (r < 0) - return log_debug_errno(r, "Failed to get device subsystem: %m"); - nlh.filter_subsystem_hash = htobe32(util_string_hash32(val)); - - if (sd_device_get_devtype(device, &val) >= 0 && val) - nlh.filter_devtype_hash = htobe32(util_string_hash32(val)); - - /* add tag bloom filter */ - tag_bloom_bits = 0; - FOREACH_DEVICE_TAG(device, val) - tag_bloom_bits |= util_string_bloom64(val); - - if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff); - } - - /* add properties list */ - nlh.properties_off = iov[0].iov_len; - nlh.properties_len = blen; - iov[1] = (struct iovec) { - .iov_base = (char*) buf, - .iov_len = blen, - }; - - /* - * Use custom address for target, or the default one. - * - * If we send to a multicast group, we will get - * ECONNREFUSED, which is expected. - */ - smsg.msg_name = destination ? &destination->snl : &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 device to netlink monitor %p", udev_monitor); - return 0; - } else - return log_debug_errno(errno, "Failed to send device to netlink monitor %p", udev_monitor); - } - - log_debug("Passed %zi byte device to netlink monitor %p", count, udev_monitor); - return count; -} - int udev_monitor_send_device( struct udev_monitor *udev_monitor, struct udev_monitor *destination, struct udev_device *udev_device) { + assert(udev_monitor); assert(udev_device); - return udev_monitor_send_sd_device(udev_monitor, destination, udev_device->device); + return device_monitor_send_device(udev_monitor->monitor, + destination ? destination->monitor : NULL, + udev_device->device); } /** @@ -763,32 +309,9 @@ int udev_monitor_send_device( * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) { - _cleanup_free_ char *s = NULL, *d = NULL; - int r; - assert_return(udev_monitor, -EINVAL); - assert_return(subsystem, -EINVAL); - s = strdup(subsystem); - if (!s) - return -ENOMEM; - - if (devtype) { - d = strdup(devtype); - if (!d) - return -ENOMEM; - } - - r = hashmap_ensure_allocated(&udev_monitor->subsystem_filter, NULL); - if (r < 0) - return r; - - r = hashmap_put(udev_monitor->subsystem_filter, s, d); - if (r < 0) - return r; - - s = d = NULL; - return 0; + return sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype); } /** @@ -804,28 +327,9 @@ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) { - _cleanup_free_ char *t = NULL; - int r; - assert_return(udev_monitor, -EINVAL); - assert_return(tag, -EINVAL); - t = strdup(tag); - if (!t) - return -ENOMEM; - - r = set_ensure_allocated(&udev_monitor->tag_filter, &string_hash_ops); - if (r < 0) - return r; - - r = set_put(udev_monitor->tag_filter, t); - if (r == -EEXIST) - return 0; - if (r < 0) - return r; - - TAKE_PTR(t); - return 0; + return sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag); } /** @@ -837,15 +341,7 @@ _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { - static const struct sock_fprog filter = { 0, NULL }; - assert_return(udev_monitor, -EINVAL); - udev_monitor->subsystem_filter = hashmap_free_free_free(udev_monitor->subsystem_filter); - udev_monitor->tag_filter = set_free_free(udev_monitor->tag_filter); - - if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0) - return -errno; - - return 0; + return sd_device_monitor_filter_remove(udev_monitor->monitor); } diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index 97aedda5da..3bb27fbc4e 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -228,19 +228,3 @@ int util_replace_chars(char *str, const char *white) { _public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len) { return encode_devnode_name(str, str_enc, len); } - -uint32_t util_string_hash32(const char *str) { - return MurmurHash2(str, strlen(str), 0); -} - -/* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ -uint64_t util_string_bloom64(const char *str) { - uint64_t bits = 0; - uint32_t hash = util_string_hash32(str); - - bits |= 1LLU << (hash & 63); - bits |= 1LLU << ((hash >> 6) & 63); - bits |= 1LLU << ((hash >> 12) & 63); - bits |= 1LLU << ((hash >> 18) & 63); - return bits; -} From d2ebf9527e3be245fe1be9894dc8b01d516abcce Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:47:10 +0900 Subject: [PATCH 03/13] network: replace udev_monitor by sd_device_monitor --- src/network/networkd-manager.c | 63 ++++++++++------------------------ src/network/networkd-manager.h | 5 ++- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index e5c929f29b..f9accb1fd9 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -15,7 +15,6 @@ #include "dns-domain.h" #include "fd-util.h" #include "fileio.h" -#include "libudev-private.h" #include "local-addresses.h" #include "netlink-util.h" #include "networkd-manager.h" @@ -184,7 +183,8 @@ int manager_connect_bus(Manager *m) { return 0; } -static int manager_udev_process_link(Manager *m, sd_device *device) { +static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) { + Manager *m = userdata; const char *action; Link *link = NULL; int r, ifindex; @@ -203,29 +203,13 @@ static int manager_udev_process_link(Manager *m, sd_device *device) { } r = link_get(m, ifindex, &link); - if (r == -ENODEV) + if (r < 0) { + if (r != -ENODEV) + log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex); return 0; - else if (r < 0) - return r; + } - r = link_initialized(link, device); - if (r < 0) - return r; - - return 0; -} - -static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - Manager *m = userdata; - struct udev_monitor *monitor = m->udev_monitor; - _cleanup_(sd_device_unrefp) sd_device *device = NULL; - int r; - - r = udev_monitor_receive_sd_device(monitor, &device); - if (r < 0) - return r; - - (void) manager_udev_process_link(m, device); + (void) link_initialized(link, device); return 0; } @@ -239,31 +223,21 @@ static int manager_connect_udev(Manager *m) { if (detect_container() > 0) return 0; - m->udev_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL); + r = sd_device_monitor_new(&m->device_monitor); if (r < 0) - return log_error_errno(r, "Could not add udev monitor filter: %m"); + return log_error_errno(r, "Failed to initialize device monitor: %m"); - r = udev_monitor_enable_receiving(m->udev_monitor); - if (r < 0) { - log_error("Could not enable udev monitor"); - return r; - } - - r = sd_event_add_io(m->event, - &m->udev_event_source, - udev_monitor_get_fd(m->udev_monitor), - EPOLLIN, manager_dispatch_link_udev, - m); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); if (r < 0) - return r; + return log_error_errno(r, "Could not add device monitor filter: %m"); - r = sd_event_source_set_description(m->udev_event_source, "networkd-udev"); + r = sd_device_monitor_attach_event(m->device_monitor, m->event, 0); if (r < 0) - return r; + return log_error_errno(r, "Failed to attach event to device monitor: %m"); + + r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m, "networkd-device-monitor"); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %m"); return 0; } @@ -1476,8 +1450,7 @@ void manager_free(Manager *m) { sd_resolve_unref(m->resolve); - sd_event_source_unref(m->udev_event_source); - udev_monitor_unref(m->udev_monitor); + sd_device_monitor_unref(m->device_monitor); sd_bus_unref(m->bus); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 726a4d2d40..289ca96216 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -4,11 +4,11 @@ #include #include "sd-bus.h" +#include "sd-device.h" #include "sd-event.h" #include "sd-id128.h" #include "sd-netlink.h" #include "sd-resolve.h" -#include "libudev.h" #include "dhcp-identifier.h" #include "hashmap.h" @@ -27,8 +27,7 @@ struct Manager { sd_event *event; sd_resolve *resolve; sd_bus *bus; - struct udev_monitor *udev_monitor; - sd_event_source *udev_event_source; + sd_device_monitor *device_monitor; bool enumerating:1; bool dirty:1; From d0955f009195c2512e042cc10f723d6e5ac0d31a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:47:29 +0900 Subject: [PATCH 04/13] core: replace udev_monitor by sd_device_monitor --- src/core/device.c | 51 ++++++++++++++-------------------------------- src/core/manager.h | 5 ++--- 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/src/core/device.c b/src/core/device.c index 80bd2555f1..16c1cf19fa 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -9,7 +9,6 @@ #include "device-private.h" #include "device-util.h" #include "device.h" -#include "libudev-private.h" #include "log.h" #include "parse-util.h" #include "path-util.h" @@ -25,7 +24,7 @@ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_PLUGGED] = UNIT_ACTIVE, }; -static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata); static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask); static void device_unset_sysfs(Device *d) { @@ -472,7 +471,7 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool if (dev) { r = sd_device_get_syspath(dev, &sysfs); if (r < 0) { - log_debug_errno(r, "Couldn't get syspath from udev device, ignoring: %m"); + log_debug_errno(r, "Couldn't get syspath from device, ignoring: %m"); return 0; } } @@ -773,8 +772,7 @@ static int device_following_set(Unit *u, Set **_set) { static void device_shutdown(Manager *m) { assert(m); - m->udev_event_source = sd_event_source_unref(m->udev_event_source); - m->udev_monitor = udev_monitor_unref(m->udev_monitor); + m->device_monitor = sd_device_monitor_unref(m->device_monitor); m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs); } @@ -785,37 +783,35 @@ static void device_enumerate(Manager *m) { assert(m); - if (!m->udev_monitor) { - m->udev_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_monitor) { - log_error_errno(errno, "Failed to allocate udev monitor: %m"); + if (!m->device_monitor) { + r = sd_device_monitor_new(&m->device_monitor); + if (r < 0) { + log_error_errno(r, "Failed to allocate device monitor: %m"); goto fail; } /* This will fail if we are unprivileged, but that * should not matter much, as user instances won't run * during boot. */ - (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024); + (void) sd_device_monitor_set_receive_buffer_size(m->device_monitor, 128*1024*1024); - r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd"); + r = sd_device_monitor_filter_add_match_tag(m->device_monitor, "systemd"); if (r < 0) { log_error_errno(r, "Failed to add udev tag match: %m"); goto fail; } - r = udev_monitor_enable_receiving(m->udev_monitor); + r = sd_device_monitor_attach_event(m->device_monitor, m->event, 0); if (r < 0) { - log_error_errno(r, "Failed to enable udev event reception: %m"); + log_error_errno(r, "Failed to attach event to device monitor: %m"); goto fail; } - r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m); + r = sd_device_monitor_start(m->device_monitor, device_dispatch_io, m, "systemd-device-monitor"); if (r < 0) { - log_error_errno(r, "Failed to watch udev file descriptor: %m"); + log_error_errno(r, "Failed to start device monitor: %m"); goto fail; } - - (void) sd_event_source_set_description(m->udev_event_source, "device"); } r = sd_device_enumerator_new(&e); @@ -868,30 +864,13 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) { } } -static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *dev = NULL; +static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) { Manager *m = userdata; const char *action, *sysfs; int r; assert(m); - - if (revents != EPOLLIN) { - static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5); - - if (ratelimit_below(&limit)) - log_warning("Failed to get udev event"); - if (!(revents & EPOLLIN)) - return 0; - } - - /* - * libudev might filter-out devices which pass the bloom - * filter, so getting NULL here is not necessarily an error. - */ - r = udev_monitor_receive_sd_device(m->udev_monitor, &dev); - if (r < 0) - return 0; + assert(dev); r = sd_device_get_syspath(dev, &sysfs); if (r < 0) { diff --git a/src/core/manager.h b/src/core/manager.h index 6e6e251a55..1daa9f2308 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -4,8 +4,8 @@ #include #include -#include "libudev.h" #include "sd-bus.h" +#include "sd-device.h" #include "sd-event.h" #include "cgroup-util.h" @@ -220,8 +220,7 @@ struct Manager { dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX]; /* Data specific to the device subsystem */ - struct udev_monitor* udev_monitor; - sd_event_source *udev_event_source; + sd_device_monitor *device_monitor; Hashmap *devices_by_sysfs; /* Data specific to the mount subsystem */ From eb968396bb77a2c2f8f8118f696e5eb47d89ffcf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:47:53 +0900 Subject: [PATCH 05/13] login: replace udev_monitor by sd_device_monitor --- src/login/logind.c | 129 ++++++++++++++++++--------------------------- src/login/logind.h | 7 +-- 2 files changed, 53 insertions(+), 83 deletions(-) diff --git a/src/login/logind.c b/src/login/logind.c index 44899064c5..2539b1ef03 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -18,7 +18,6 @@ #include "fd-util.h" #include "format-util.h" #include "fs-util.h" -#include "libudev-private.h" #include "logind.h" #include "parse-util.h" #include "process-util.h" @@ -127,10 +126,6 @@ static Manager* manager_unref(Manager *m) { sd_event_source_unref(m->wall_message_timeout_source); sd_event_source_unref(m->console_active_event_source); - sd_event_source_unref(m->udev_seat_event_source); - sd_event_source_unref(m->udev_device_event_source); - sd_event_source_unref(m->udev_vcsa_event_source); - sd_event_source_unref(m->udev_button_event_source); sd_event_source_unref(m->lid_switch_ignore_event_source); #if ENABLE_UTMP @@ -139,10 +134,10 @@ static Manager* manager_unref(Manager *m) { safe_close(m->console_active_fd); - udev_monitor_unref(m->udev_seat_monitor); - udev_monitor_unref(m->udev_device_monitor); - udev_monitor_unref(m->udev_vcsa_monitor); - udev_monitor_unref(m->udev_button_monitor); + sd_device_monitor_unref(m->device_seat_monitor); + sd_device_monitor_unref(m->device_monitor); + sd_device_monitor_unref(m->device_vcsa_monitor); + sd_device_monitor_unref(m->device_button_monitor); if (m->unlink_nologin) (void) unlink_or_warn("/run/nologin"); @@ -540,72 +535,52 @@ static int manager_enumerate_inhibitors(Manager *m) { return r; } -static int manager_dispatch_seat_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *d = NULL; +static int manager_dispatch_seat_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; - int r; assert(m); + assert(device); - r = udev_monitor_receive_sd_device(m->udev_seat_monitor, &d); - if (r < 0) - return r; - - manager_process_seat_device(m, d); + manager_process_seat_device(m, device); return 0; } -static int manager_dispatch_device_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *d = NULL; +static int manager_dispatch_device_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; - int r; assert(m); + assert(device); - r = udev_monitor_receive_sd_device(m->udev_device_monitor, &d); - if (r < 0) - return r; - - manager_process_seat_device(m, d); + manager_process_seat_device(m, device); return 0; } -static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *d = NULL; +static int manager_dispatch_vcsa_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; const char *name, *action; - int r; assert(m); - - r = udev_monitor_receive_sd_device(m->udev_vcsa_monitor, &d); - if (r < 0) - return r; + assert(device); /* Whenever a VCSA device is removed try to reallocate our * VTs, to make sure our auto VTs never go away. */ - if (sd_device_get_sysname(d, &name) >= 0 && + if (sd_device_get_sysname(device, &name) >= 0 && startswith(name, "vcsa") && - sd_device_get_property_value(d, "ACTION", &action) >= 0 && + sd_device_get_property_value(device, "ACTION", &action) >= 0 && streq(action, "remove")) seat_preallocate_vts(m->seat0); return 0; } -static int manager_dispatch_button_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *d = NULL; +static int manager_dispatch_button_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) { Manager *m = userdata; - int r; assert(m); + assert(device); - r = udev_monitor_receive_sd_device(m->udev_button_monitor, &d); - if (r < 0) - return r; - - manager_process_button_device(m, d); + manager_process_button_device(m, device); return 0; } @@ -844,70 +819,70 @@ static int manager_connect_udev(Manager *m) { int r; assert(m); - assert(!m->udev_seat_monitor); - assert(!m->udev_device_monitor); - assert(!m->udev_vcsa_monitor); - assert(!m->udev_button_monitor); + assert(!m->device_seat_monitor); + assert(!m->device_monitor); + assert(!m->device_vcsa_monitor); + assert(!m->device_button_monitor); - m->udev_seat_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_seat_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat"); + r = sd_device_monitor_new(&m->device_seat_monitor); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_seat_monitor); + r = sd_device_monitor_filter_add_match_tag(m->device_seat_monitor, "master-of-seat"); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_seat_event_source, udev_monitor_get_fd(m->udev_seat_monitor), EPOLLIN, manager_dispatch_seat_udev, m); + r = sd_device_monitor_attach_event(m->device_seat_monitor, m->event, 0); if (r < 0) return r; - m->udev_device_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_device_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL); + r = sd_device_monitor_start(m->device_seat_monitor, manager_dispatch_seat_udev, m, "logind-seat-monitor"); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL); + r = sd_device_monitor_new(&m->device_monitor); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "input", NULL); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_device_monitor); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "graphics", NULL); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_device_event_source, udev_monitor_get_fd(m->udev_device_monitor), EPOLLIN, manager_dispatch_device_udev, m); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "drm", NULL); + if (r < 0) + return r; + + r = sd_device_monitor_attach_event(m->device_monitor, m->event, 0); + if (r < 0) + return r; + + r = sd_device_monitor_start(m->device_monitor, manager_dispatch_device_udev, m, "logind-device-monitor"); if (r < 0) return r; /* Don't watch keys if nobody cares */ if (!manager_all_buttons_ignored(m)) { - m->udev_button_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_button_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch"); + r = sd_device_monitor_new(&m->device_button_monitor); if (r < 0) return r; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL); + r = sd_device_monitor_filter_add_match_tag(m->device_button_monitor, "power-switch"); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_button_monitor); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_button_monitor, "input", NULL); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_button_event_source, udev_monitor_get_fd(m->udev_button_monitor), EPOLLIN, manager_dispatch_button_udev, m); + r = sd_device_monitor_attach_event(m->device_button_monitor, m->event, 0); + if (r < 0) + return r; + + r = sd_device_monitor_start(m->device_button_monitor, manager_dispatch_button_udev, m, "logind-button-monitor"); if (r < 0) return r; } @@ -915,19 +890,19 @@ static int manager_connect_udev(Manager *m) { /* Don't bother watching VCSA devices, if nobody cares */ if (m->n_autovts > 0 && m->console_active_fd >= 0) { - m->udev_vcsa_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!m->udev_vcsa_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); + r = sd_device_monitor_new(&m->device_vcsa_monitor); if (r < 0) return r; - r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); + r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_vcsa_monitor, "vc", NULL); if (r < 0) return r; - r = sd_event_add_io(m->event, &m->udev_vcsa_event_source, udev_monitor_get_fd(m->udev_vcsa_monitor), EPOLLIN, manager_dispatch_vcsa_udev, m); + r = sd_device_monitor_attach_event(m->device_vcsa_monitor, m->event, 0); + if (r < 0) + return r; + + r = sd_device_monitor_start(m->device_vcsa_monitor, manager_dispatch_vcsa_udev, m, "logind-vcsa-monitor"); if (r < 0) return r; } diff --git a/src/login/logind.h b/src/login/logind.h index b1a7b932eb..6290107de2 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -3,7 +3,6 @@ #include -#include "libudev.h" #include "sd-bus.h" #include "sd-device.h" #include "sd-event.h" @@ -36,13 +35,9 @@ struct Manager { LIST_HEAD(Session, session_gc_queue); LIST_HEAD(User, user_gc_queue); - struct udev_monitor *udev_seat_monitor, *udev_device_monitor, *udev_vcsa_monitor, *udev_button_monitor; + sd_device_monitor *device_seat_monitor, *device_monitor, *device_vcsa_monitor, *device_button_monitor; sd_event_source *console_active_event_source; - sd_event_source *udev_seat_event_source; - sd_event_source *udev_device_event_source; - sd_event_source *udev_vcsa_event_source; - sd_event_source *udev_button_event_source; #if ENABLE_UTMP sd_event_source *utmp_event_source; From 13831507edffb8a5f4ca248c2c73cdfbdcdafbeb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:48:36 +0900 Subject: [PATCH 06/13] rfkill: replace udev_monitor by sd_device_monitor --- src/rfkill/rfkill.c | 88 ++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index 7939c2d2fe..79bc1cbc5d 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -11,7 +11,6 @@ #include "fd-util.h" #include "fileio.h" #include "io-util.h" -#include "libudev-private.h" #include "mkdir.h" #include "parse-util.h" #include "proc-cmdline.h" @@ -82,14 +81,36 @@ static int find_device( return 0; } +struct DeviceMonitorData { + const char *sysname; + sd_device *device; +}; + +static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) { + struct DeviceMonitorData *data = userdata; + const char *sysname; + + assert(device); + assert(data); + assert(data->sysname); + + if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) { + data->device = sd_device_ref(device); + return sd_event_exit(sd_device_monitor_get_event(monitor), 0); + } + + return 0; +} + static int wait_for_initialized( sd_device *device, sd_device **ret) { - _cleanup_(udev_monitor_unrefp) struct udev_monitor *monitor = NULL; + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL; - int initialized, watch_fd, r; - const char *sysname; + struct DeviceMonitorData data = {}; + int initialized, r; assert(device); assert(ret); @@ -99,61 +120,48 @@ static int wait_for_initialized( return 0; } - assert_se(sd_device_get_sysname(device, &sysname) >= 0); + assert_se(sd_device_get_sysname(device, &data.sysname) >= 0); /* Wait until the device is initialized, so that we can get * access to the ID_PATH property */ - monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!monitor) - return log_error_errno(errno, "Failed to acquire monitor: %m"); - - r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL); + r = sd_event_default(&event); if (r < 0) - return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m"); + return log_error_errno(r, "Failed to get default event: %m"); - r = udev_monitor_enable_receiving(monitor); + r = sd_device_monitor_new(&monitor); if (r < 0) - return log_error_errno(r, "Failed to enable udev receiving: %m"); + return log_error_errno(r, "Failed to acquire monitor: %m"); - watch_fd = udev_monitor_get_fd(monitor); - if (watch_fd < 0) - return log_error_errno(watch_fd, "Failed to get watch fd: %m"); + r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL); + if (r < 0) + return log_error_errno(r, "Failed to add rfkill device match to monitor: %m"); + + r = sd_device_monitor_attach_event(monitor, event, 0); + if (r < 0) + return log_error_errno(r, "Failed to attach event to device monitor: %m"); + + r = sd_device_monitor_start(monitor, device_monitor_handler, &data, "rfkill-device-monitor"); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %m"); /* Check again, maybe things changed */ - r = sd_device_new_from_subsystem_sysname(&d, "rfkill", sysname); + r = sd_device_new_from_subsystem_sysname(&d, "rfkill", data.sysname); if (r < 0) return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r, - "Failed to open device '%s': %m", sysname); + "Failed to open device '%s': %m", data.sysname); if (sd_device_get_is_initialized(d, &initialized) >= 0 && initialized) { *ret = TAKE_PTR(d); return 0; } - for (;;) { - _cleanup_(sd_device_unrefp) sd_device *t = NULL; - const char *name; + r = sd_event_loop(event); + if (r < 0) + return log_error_errno(r, "Event loop failed: %m"); - r = fd_wait_for_event(watch_fd, POLLIN, EXIT_USEC); - if (r == -EINTR) - continue; - if (r < 0) - return log_error_errno(r, "Failed to watch udev monitor: %m"); - if (r == 0) { - log_error("Timed out waiting for udev monitor."); - return -ETIMEDOUT; - } - - r = udev_monitor_receive_sd_device(monitor, &t); - if (r < 0) - continue; - - if (sd_device_get_sysname(t, &name) >= 0 && streq(name, sysname)) { - *ret = TAKE_PTR(t); - return 0; - } - } + *ret = TAKE_PTR(data.device); + return 0; } static int determine_state_file( From a46556f77d0e585b14063c2be118aa0bb12e45ba Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Oct 2018 22:49:44 +0900 Subject: [PATCH 07/13] udevadm-monitor: replace udev_monitor by sd_device_monitor --- src/udev/udevadm-monitor.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index 8a0db2b89d..b5fbead7bc 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -10,15 +10,14 @@ #include #include -#include "libudev.h" #include "sd-device.h" #include "alloc-util.h" +#include "device-monitor-private.h" #include "device-util.h" #include "fd-util.h" #include "format-util.h" #include "hashmap.h" -#include "libudev-private.h" #include "set.h" #include "string-util.h" #include "udevadm.h" @@ -35,13 +34,13 @@ static void sig_handler(int signum) { udev_exit = true; } -static int receive_and_print_device(struct udev_monitor *monitor, const char *source) { +static int receive_and_print_device(sd_device_monitor *monitor, const char *source) { const char *action = NULL, *devpath = NULL, *subsystem = NULL; _cleanup_(sd_device_unrefp) sd_device *device = NULL; struct timespec ts; int r; - r = udev_monitor_receive_sd_device(monitor, &device); + r = device_monitor_receive_device(monitor, &device); if (r < 0) return log_debug_errno(r, "Failed to receive device from %s, ignoring: %m", source); @@ -68,41 +67,41 @@ static int receive_and_print_device(struct udev_monitor *monitor, const char *so return 0; } -static int setup_monitor(const char *sender, int fd_epoll, struct udev_monitor **ret) { - _cleanup_(udev_monitor_unrefp) struct udev_monitor *monitor = NULL; +static int setup_monitor(MonitorNetlinkGroup sender, int fd_epoll, sd_device_monitor **ret) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; const char *subsystem, *devtype, *tag; struct epoll_event ep = {}; Iterator i; int fd, r; - monitor = udev_monitor_new_from_netlink(NULL, sender); - if (!monitor) - return log_error_errno(errno, "Failed to create netlink socket: %m"); + r = device_monitor_new_full(&monitor, sender, -1); + if (r < 0) + return log_error_errno(r, "Failed to create netlink socket: %m"); - r = udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024); + r = sd_device_monitor_set_receive_buffer_size(monitor, 128*1024*1024); if (r < 0) return log_error_errno(r, "Failed to set receive buffer size: %m"); - fd = udev_monitor_get_fd(monitor); + fd = device_monitor_get_fd(monitor); if (fd < 0) return log_error_errno(r, "Failed to get socket fd for monitoring: %m"); HASHMAP_FOREACH_KEY(devtype, subsystem, arg_subsystem_filter, i) { - r = udev_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, devtype); + r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, devtype); if (r < 0) return log_error_errno(r, "Failed to apply subsystem filter '%s%s%s': %m", subsystem, devtype ? "/" : "", strempty(devtype)); } SET_FOREACH(tag, arg_tag_filter, i) { - r = udev_monitor_filter_add_match_tag(monitor, tag); + r = sd_device_monitor_filter_add_match_tag(monitor, tag); if (r < 0) return log_error_errno(r, "Failed to apply tag filter '%s': %m", tag); } - r = udev_monitor_enable_receiving(monitor); + r = device_monitor_enable_receiving(monitor); if (r < 0) - return log_error_errno(r, "Failed to subscribe %s events: %m", sender); + return log_error_errno(r, "Failed to subscribe %s events: %m", sender == MONITOR_GROUP_UDEV ? "udev" : "kernel"); ep = (struct epoll_event) { .events = EPOLLIN, @@ -223,7 +222,7 @@ static int parse_argv(int argc, char *argv[]) { } int monitor_main(int argc, char *argv[], void *userdata) { - _cleanup_(udev_monitor_unrefp) struct udev_monitor *kernel_monitor = NULL, *udev_monitor = NULL; + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *kernel_monitor = NULL, *udev_monitor = NULL; int fd_kernel = -1, fd_udev = -1; _cleanup_close_ int fd_ep = -1; struct sigaction act; @@ -257,7 +256,7 @@ int monitor_main(int argc, char *argv[], void *userdata) { printf("monitor will print the received events for:\n"); if (arg_print_udev) { - fd_udev = setup_monitor("udev", fd_ep, &udev_monitor); + fd_udev = setup_monitor(MONITOR_GROUP_UDEV, fd_ep, &udev_monitor); if (fd_udev < 0) { r = fd_udev; goto finalize; @@ -267,7 +266,7 @@ int monitor_main(int argc, char *argv[], void *userdata) { } if (arg_print_kernel) { - fd_kernel = setup_monitor("kernel", fd_ep, &kernel_monitor); + fd_kernel = setup_monitor(MONITOR_GROUP_KERNEL, fd_ep, &kernel_monitor); if (fd_kernel < 0) { r = fd_kernel; goto finalize; From 13aca847695f49afeb93367ecdad76035fa6c139 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 29 Aug 2018 17:28:05 +0900 Subject: [PATCH 08/13] udevadm-info,trigger: replace udev_device by sd_device --- src/udev/udevadm-info.c | 220 ++++++++++++++++++------------------- src/udev/udevadm-trigger.c | 134 ++++++++++++---------- src/udev/udevadm-util.c | 32 +++--- src/udev/udevadm-util.h | 5 +- 4 files changed, 200 insertions(+), 191 deletions(-) diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 92c7cfe6bf..dbbc589e6b 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -10,10 +10,15 @@ #include #include +#include "sd-device.h" + +#include "device-enumerator-private.h" +#include "device-private.h" +#include "device-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "libudev-private.h" #include "string-util.h" -#include "udev.h" #include "udevadm.h" #include "udevadm-util.h" @@ -35,22 +40,15 @@ static bool skip_attribute(const char *name) { return false; } -static void print_all_attributes(struct udev_device *device, const char *key) { - struct udev_list_entry *sysattr; +static void print_all_attributes(sd_device *device, const char *key) { + const char *name, *value; - udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) { - const char *name; - const char *value; + FOREACH_DEVICE_PROPERTY(device, name, value) { size_t len; - name = udev_list_entry_get_name(sysattr); if (skip_attribute(name)) continue; - value = udev_device_get_sysattr_value(device, name); - if (value == NULL) - continue; - /* skip any values that look like a path */ if (value[0] == '/') continue; @@ -67,8 +65,8 @@ static void print_all_attributes(struct udev_device *device, const char *key) { printf("\n"); } -static int print_device_chain(struct udev_device *device) { - struct udev_device *device_parent; +static int print_device_chain(sd_device *device) { + sd_device *child, *parent; const char *str; printf("\n" @@ -79,62 +77,54 @@ static int print_device_chain(struct udev_device *device) { "and the attributes from one single parent device.\n" "\n"); - printf(" looking at device '%s':\n", udev_device_get_devpath(device)); - printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device)); - str = udev_device_get_subsystem(device); - if (str == NULL) + (void) sd_device_get_devpath(device, &str); + printf(" looking at device '%s':\n", str); + (void) sd_device_get_sysname(device, &str); + printf(" KERNEL==\"%s\"\n", str); + if (sd_device_get_subsystem(device, &str) < 0) str = ""; printf(" SUBSYSTEM==\"%s\"\n", str); - str = udev_device_get_driver(device); - if (str == NULL) + if (sd_device_get_driver(device, &str) < 0) str = ""; printf(" DRIVER==\"%s\"\n", str); print_all_attributes(device, "ATTR"); - device_parent = device; - do { - device_parent = udev_device_get_parent(device_parent); - if (device_parent == NULL) - break; - printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent)); - printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent)); - str = udev_device_get_subsystem(device_parent); - if (str == NULL) + for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) { + (void) sd_device_get_devpath(parent, &str); + printf(" looking at parent device '%s':\n", str); + (void) sd_device_get_sysname(parent, &str); + printf(" KERNELS==\"%s\"\n", str); + if (sd_device_get_subsystem(parent, &str) < 0) str = ""; printf(" SUBSYSTEMS==\"%s\"\n", str); - str = udev_device_get_driver(device_parent); - if (str == NULL) + if (sd_device_get_driver(parent, &str) < 0) str = ""; printf(" DRIVERS==\"%s\"\n", str); - print_all_attributes(device_parent, "ATTRS"); - } while (device_parent != NULL); + print_all_attributes(parent, "ATTRS"); + } return 0; } -static void print_record(struct udev_device *device) { - const char *str; +static void print_record(sd_device *device) { + const char *str, *val; int i; - struct udev_list_entry *list_entry; - printf("P: %s\n", udev_device_get_devpath(device)); + (void) sd_device_get_devpath(device, &str); + printf("P: %s\n", str); - str = udev_device_get_devnode(device); - if (str != NULL) + if (sd_device_get_devname(device, &str) >= 0) printf("N: %s\n", str + STRLEN("/dev/")); - i = udev_device_get_devlink_priority(device); - if (i != 0) + if (device_get_devlink_priority(device, &i) >= 0) printf("L: %i\n", i); - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) - printf("S: %s\n", - udev_list_entry_get_name(list_entry) + STRLEN("/dev/")); + FOREACH_DEVICE_DEVLINK(device, str) + printf("S: %s\n", str + STRLEN("/dev/")); + + FOREACH_DEVICE_PROPERTY(device, str, val) + printf("E: %s=%s\n", str, val); - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) - printf("E: %s=%s\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); printf("\n"); } @@ -145,7 +135,7 @@ static int stat_device(const char *name, bool export, const char *prefix) { return -errno; if (export) { - if (prefix == NULL) + if (!prefix) prefix = "INFO_"; printf("%sMAJOR=%u\n" "%sMINOR=%u\n", @@ -157,21 +147,24 @@ static int stat_device(const char *name, bool export, const char *prefix) { } static int export_devices(void) { - _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *udev_enumerate; - struct udev_list_entry *list_entry; + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; + int r; - udev_enumerate = udev_enumerate_new(NULL); - if (udev_enumerate == NULL) - return -ENOMEM; + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; - udev_enumerate_scan_devices(udev_enumerate); - udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) { - _cleanup_(udev_device_unrefp) struct udev_device *device; + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; - device = udev_device_new_from_syspath(NULL, udev_list_entry_get_name(list_entry)); - if (device != NULL) - print_record(device); - } + r = device_enumerator_scan_devices(e); + if (r < 0) + return r; + + FOREACH_DEVICE_AND_SUBSYSTEM(e, d) + print_record(d); return 0; } @@ -192,10 +185,10 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) { if ((stats.st_mode & mask) != 0) continue; if (S_ISDIR(stats.st_mode)) { - _cleanup_closedir_ DIR *dir2; + _cleanup_closedir_ DIR *dir2 = NULL; dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); - if (dir2 != NULL) + if (dir2) cleanup_dir(dir2, mask, depth-1); (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR); @@ -210,23 +203,23 @@ static void cleanup_db(void) { (void) unlink("/run/udev/queue.bin"); dir1 = opendir("/run/udev/data"); - if (dir1 != NULL) + if (dir1) cleanup_dir(dir1, S_ISVTX, 1); dir2 = opendir("/run/udev/links"); - if (dir2 != NULL) + if (dir2) cleanup_dir(dir2, 0, 2); dir3 = opendir("/run/udev/tags"); - if (dir3 != NULL) + if (dir3) cleanup_dir(dir3, 0, 2); dir4 = opendir("/run/udev/static_node-tags"); - if (dir4 != NULL) + if (dir4) cleanup_dir(dir4, 0, 2); dir5 = opendir("/run/udev/watch"); - if (dir5 != NULL) + if (dir5) cleanup_dir(dir5, 0, 1); } @@ -258,12 +251,11 @@ static int help(void) { } int info_main(int argc, char *argv[], void *userdata) { - _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; bool root = 0; bool export = 0; const char *export_prefix = NULL; char name[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; int c, r; static const struct option options[] = { @@ -304,9 +296,9 @@ int info_main(int argc, char *argv[], void *userdata) { return -EINVAL; } - device = find_device(optarg, "/dev/"); - if (!device) - return log_error_errno(errno, "device node not found: %m"); + r = find_device(optarg, "/dev/", &device); + if (r < 0) + return log_error_errno(r, "device node not found: %m"); break; case 'p': if (device) { @@ -314,9 +306,9 @@ int info_main(int argc, char *argv[], void *userdata) { return -EINVAL; } - device = find_device(optarg, "/sys"); - if (!device) - return log_error_errno(errno, "syspath not found: %m"); + r = find_device(optarg, "/sys", &device); + if (r < 0) + return log_error_errno(r, "syspath not found: %m"); break; case 'q': action = ACTION_QUERY; @@ -373,57 +365,63 @@ int info_main(int argc, char *argv[], void *userdata) { help(); return -EINVAL; } - device = find_device(argv[optind], NULL); - if (!device) { - log_error("Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected."); - return -EINVAL; - } + r = find_device(argv[optind], NULL, &device); + if (r < 0) + return log_error_errno(r, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected: %m"); } switch(query) { case QUERY_NAME: { - const char *node = udev_device_get_devnode(device); + const char *node; - if (!node) - return log_error_errno(errno, "no device node found"); + r = sd_device_get_devname(device, &node); + if (r < 0) + return log_error_errno(r, "no device node found: %m"); if (root) - printf("%s\n", udev_device_get_devnode(device)); + printf("%s\n", node); else - printf("%s\n", - udev_device_get_devnode(device) + STRLEN("/dev/")); + printf("%s\n", node + STRLEN("/dev/")); break; } - case QUERY_SYMLINK: - list_entry = udev_device_get_devlinks_list_entry(device); - while (list_entry) { - if (root) - printf("%s", udev_list_entry_get_name(list_entry)); - else - printf("%s", - udev_list_entry_get_name(list_entry) + STRLEN("/dev/")); - list_entry = udev_list_entry_get_next(list_entry); - if (list_entry) + case QUERY_SYMLINK: { + const char *devlink; + bool first = true; + + FOREACH_DEVICE_DEVLINK(device, devlink) { + if (!first) printf(" "); + if (root) + printf("%s", devlink); + else + printf("%s", devlink + STRLEN("/dev/")); + + first = false; } printf("\n"); break; - case QUERY_PATH: - printf("%s\n", udev_device_get_devpath(device)); + } + case QUERY_PATH: { + const char *devpath; + + r = sd_device_get_devpath(device, &devpath); + if (r < 0) + return log_error_errno(r, "Failed to get device path: %m"); + + printf("%s\n", devpath); return 0; - case QUERY_PROPERTY: - list_entry = udev_device_get_properties_list_entry(device); - while (list_entry) { + } + case QUERY_PROPERTY: { + const char *key, *value; + + FOREACH_DEVICE_PROPERTY(device, key, value) if (export) - printf("%s%s='%s'\n", strempty(export_prefix), - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); + printf("%s%s='%s'\n", strempty(export_prefix), key, value); else - printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + printf("%s=%s\n", key, value); - list_entry = udev_list_entry_get_next(list_entry); - } break; + } case QUERY_ALL: print_record(device); break; @@ -433,11 +431,9 @@ int info_main(int argc, char *argv[], void *userdata) { break; case ACTION_ATTRIBUTE_WALK: if (!device && argv[optind]) { - device = find_device(argv[optind], NULL); - if (!device) { - log_error("Unknown device, absolute path in /dev/ or /sys expected."); - return -EINVAL; - } + r = find_device(argv[optind], NULL, &device); + if (r < 0) + return log_error_errno(r, "Unknown device, absolute path in /dev/ or /sys expected: %m"); } if (!device) { log_error("Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected."); diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index e08d342f29..2639a82787 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -6,32 +6,36 @@ #include #include #include +#include #include +#include "device-enumerator-private.h" #include "fd-util.h" +#include "libudev-private.h" #include "set.h" #include "string-util.h" -#include "udev.h" +#include "strv.h" #include "udevadm.h" #include "udevadm-util.h" -#include "util.h" -static int verbose; -static int dry_run; +static bool arg_verbose = false; +static bool arg_dry_run = false; -static int exec_list(struct udev_enumerate *udev_enumerate, const char *action, Set *settle_set) { - struct udev_list_entry *entry; +static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_set) { + sd_device *d; int r; - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) { + FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { char filename[UTIL_PATH_SIZE]; const char *syspath; _cleanup_close_ int fd = -1; - syspath = udev_list_entry_get_name(entry); - if (verbose) + if (sd_device_get_syspath(d, &syspath) < 0) + continue; + + if (arg_verbose) printf("%s\n", syspath); - if (dry_run) + if (arg_dry_run) continue; strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); @@ -120,7 +124,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { TYPE_SUBSYSTEMS, } device_type = TYPE_DEVICES; const char *action = "change"; - _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *udev_enumerate = NULL; + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor = NULL; _cleanup_close_ int fd_ep = -1; int fd_udev = -1; @@ -129,9 +133,13 @@ int trigger_main(int argc, char *argv[], void *userdata) { _cleanup_set_free_free_ Set *settle_set = NULL; int c, r; - udev_enumerate = udev_enumerate_new(NULL); - if (!udev_enumerate) - return -errno; + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; + + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { const char *key; @@ -140,10 +148,10 @@ int trigger_main(int argc, char *argv[], void *userdata) { switch (c) { case 'v': - verbose = 1; + arg_verbose = true; break; case 'n': - dry_run = 1; + arg_dry_run = true; break; case 't': if (streq(optarg, "devices")) @@ -165,51 +173,51 @@ int trigger_main(int argc, char *argv[], void *userdata) { break; case 's': - r = udev_enumerate_add_match_subsystem(udev_enumerate, optarg); + r = sd_device_enumerator_add_match_subsystem(e, optarg, true); if (r < 0) return log_error_errno(r, "could not add subsystem match '%s': %m", optarg); break; case 'S': - r = udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg); + r = sd_device_enumerator_add_match_subsystem(e, optarg, false); if (r < 0) return log_error_errno(r, "could not add negative subsystem match '%s': %m", optarg); break; case 'a': key = keyval(optarg, &val, buf, sizeof(buf)); - r = udev_enumerate_add_match_sysattr(udev_enumerate, key, val); + r = sd_device_enumerator_add_match_sysattr(e, key, val, true); if (r < 0) return log_error_errno(r, "could not add sysattr match '%s=%s': %m", key, val); break; case 'A': key = keyval(optarg, &val, buf, sizeof(buf)); - r = udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val); + r = sd_device_enumerator_add_match_sysattr(e, key, val, false); if (r < 0) return log_error_errno(r, "could not add negative sysattr match '%s=%s': %m", key, val); break; case 'p': key = keyval(optarg, &val, buf, sizeof(buf)); - r = udev_enumerate_add_match_property(udev_enumerate, key, val); + r = sd_device_enumerator_add_match_property(e, key, val); if (r < 0) return log_error_errno(r, "could not add property match '%s=%s': %m", key, val); break; case 'g': - r = udev_enumerate_add_match_tag(udev_enumerate, optarg); + r = sd_device_enumerator_add_match_tag(e, optarg); if (r < 0) return log_error_errno(r, "could not add tag match '%s': %m", optarg); break; case 'y': - r = udev_enumerate_add_match_sysname(udev_enumerate, optarg); + r = sd_device_enumerator_add_match_sysname(e, optarg); if (r < 0) return log_error_errno(r, "could not add sysname match '%s': %m", optarg); break; case 'b': { - _cleanup_(udev_device_unrefp) struct udev_device *dev; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - dev = find_device(optarg, "/sys"); - if (!dev) - return log_error_errno(errno, "unable to open the device '%s'", optarg); + r = find_device(optarg, "/sys", &dev); + if (r < 0) + return log_error_errno(r, "unable to open the device '%s'", optarg); - r = udev_enumerate_add_match_parent(udev_enumerate, dev); + r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) return log_error_errno(r, "could not add parent match '%s': %m", optarg); break; @@ -219,13 +227,13 @@ int trigger_main(int argc, char *argv[], void *userdata) { break; case ARG_NAME: { - _cleanup_(udev_device_unrefp) struct udev_device *dev; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - dev = find_device(optarg, "/dev/"); - if (!dev) - return log_error_errno(errno, "unable to open the device '%s'", optarg); + r = find_device(optarg, "/dev/", &dev); + if (r < 0) + return log_error_errno(r, "unable to open the device '%s'", optarg); - r = udev_enumerate_add_match_parent(udev_enumerate, dev); + r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) return log_error_errno(r, "could not add parent match '%s': %m", optarg); break; @@ -243,17 +251,15 @@ int trigger_main(int argc, char *argv[], void *userdata) { } for (; optind < argc; optind++) { - _cleanup_(udev_device_unrefp) struct udev_device *dev; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - dev = find_device(argv[optind], NULL); - if (!dev) { - log_error("unable to open the device '%s'", argv[optind]); - return -EINVAL; - } - - r = udev_enumerate_add_match_parent(udev_enumerate, dev); + r = find_device(argv[optind], NULL, &dev); if (r < 0) - return log_error_errno(r, "could not add tag match '%s': %m", optarg); + return log_error_errno(r, "unable to open the device '%s'", argv[optind]); + + r = sd_device_enumerator_add_match_parent(e, dev); + if (r < 0) + return log_error_errno(r, "could not add parent match '%s': %m", argv[optind]); } if (settle) { @@ -266,12 +272,17 @@ int trigger_main(int argc, char *argv[], void *userdata) { return log_error_errno(errno, "error: unable to create netlink socket: %m"); fd_udev = udev_monitor_get_fd(udev_monitor); + if (fd_udev < 0) + return log_error_errno(fd_udev, "Failed to get udev_monitor fd: %m"); r = udev_monitor_enable_receiving(udev_monitor); if (r < 0) return log_error_errno(r, "error: unable to subscribe to udev events: %m"); - ep_udev = (struct epoll_event) { .events = EPOLLIN, .data.fd = fd_udev }; + ep_udev = (struct epoll_event) { + .events = EPOLLIN, + .data.fd = fd_udev, + }; if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) return log_error_errno(errno, "fail to add fd to epoll: %m"); @@ -282,15 +293,19 @@ int trigger_main(int argc, char *argv[], void *userdata) { switch (device_type) { case TYPE_SUBSYSTEMS: - udev_enumerate_scan_subsystems(udev_enumerate); + r = device_enumerator_scan_subsystems(e); + if (r < 0) + return log_error_errno(r, "Failed to scan subsystems: %m"); break; case TYPE_DEVICES: - udev_enumerate_scan_devices(udev_enumerate); + r = device_enumerator_scan_devices(e); + if (r < 0) + return log_error_errno(r, "Failed to scan devices: %m"); break; default: assert_not_reached("device_type"); } - r = exec_list(udev_enumerate, action, settle_set); + r = exec_list(e, action, settle_set); if (r < 0) return r; @@ -307,20 +322,23 @@ int trigger_main(int argc, char *argv[], void *userdata) { } for (i = 0; i < fdcount; i++) { - if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { - _cleanup_(udev_device_unrefp) struct udev_device *device; - const char *syspath = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *syspath = NULL; - device = udev_monitor_receive_device(udev_monitor); - if (!device) - continue; + if (!(ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN)) + continue; - syspath = udev_device_get_syspath(device); - if (verbose) - printf("settle %s\n", syspath); - if (!set_remove(settle_set, syspath)) - log_debug("Got epoll event on syspath %s not present in syspath set", syspath); - } + if (udev_monitor_receive_sd_device(udev_monitor, &dev) < 0) + continue; + + if (sd_device_get_syspath(dev, &syspath) < 0) + continue; + + if (arg_verbose) + printf("settle %s\n", syspath); + + if (!set_remove(settle_set, syspath)) + log_debug("Got epoll event on syspath %s not present in syspath set", syspath); } } diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 867a6d94c2..6cff5ef84c 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -1,34 +1,30 @@ /* SPDX-License-Identifier: GPL-2.0+ */ +#include + +#include "device-private.h" #include "path-util.h" #include "string-util.h" #include "udevadm-util.h" -struct udev_device *find_device(const char *id, - const char *prefix) { - +int find_device(const char *id, const char *prefix, sd_device **ret) { assert(id); + assert(ret); if (prefix && !startswith(id, prefix)) id = strjoina(prefix, id); + if (path_startswith(id, "/sys/")) + return sd_device_new_from_syspath(ret, id); + if (path_startswith(id, "/dev/")) { - struct stat statbuf; - char type; + struct stat st; - if (stat(id, &statbuf) < 0) - return NULL; + if (stat(id, &st) < 0) + return -errno; - if (S_ISBLK(statbuf.st_mode)) - type = 'b'; - else if (S_ISCHR(statbuf.st_mode)) - type = 'c'; - else - return NULL; + return device_new_from_stat_rdev(ret, &st); + } - return udev_device_new_from_devnum(NULL, type, statbuf.st_rdev); - } else if (path_startswith(id, "/sys/")) - return udev_device_new_from_syspath(NULL, id); - else - return NULL; + return -EINVAL; } diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 0cb0a5ca9f..59e89022a0 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ #pragma once -#include "udev.h" +#include "sd-device.h" -struct udev_device *find_device(const char *id, - const char *prefix); +int find_device(const char *id, const char *prefix, sd_device **ret); From f8d596cdfbc637f036a18b04e50c5cd944bbc7fb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 2 Oct 2018 16:10:39 +0900 Subject: [PATCH 09/13] udevadm-trigger: replace udev_monitor by sd_device_monitor --- src/udev/udevadm-trigger.c | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 2639a82787..bdadad30a0 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -10,6 +10,7 @@ #include #include "device-enumerator-private.h" +#include "device-monitor-private.h" #include "fd-util.h" #include "libudev-private.h" #include "set.h" @@ -125,13 +126,12 @@ int trigger_main(int argc, char *argv[], void *userdata) { } device_type = TYPE_DEVICES; const char *action = "change"; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor = NULL; - _cleanup_close_ int fd_ep = -1; - int fd_udev = -1; - struct epoll_event ep_udev; - bool settle = false; + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_set_free_free_ Set *settle_set = NULL; - int c, r; + _cleanup_close_ int fd_ep = -1; + struct epoll_event ep_monitor; + int c, r, fd_monitor = -1; + bool settle = false; r = sd_device_enumerator_new(&e); if (r < 0) @@ -267,24 +267,24 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (fd_ep < 0) return log_error_errno(errno, "error creating epoll fd: %m"); - udev_monitor = udev_monitor_new_from_netlink(NULL, "udev"); - if (!udev_monitor) - return log_error_errno(errno, "error: unable to create netlink socket: %m"); - - fd_udev = udev_monitor_get_fd(udev_monitor); - if (fd_udev < 0) - return log_error_errno(fd_udev, "Failed to get udev_monitor fd: %m"); - - r = udev_monitor_enable_receiving(udev_monitor); + r = sd_device_monitor_new(&m); if (r < 0) - return log_error_errno(r, "error: unable to subscribe to udev events: %m"); + return log_error_errno(r, "Failed to create device monitor object: %m"); - ep_udev = (struct epoll_event) { + fd_monitor = device_monitor_get_fd(m); + if (fd_monitor < 0) + return log_error_errno(fd_monitor, "Failed to get monitor fd: %m"); + + r = device_monitor_enable_receiving(m); + if (r < 0) + return log_error_errno(r, "Failed to subscribe udev events: %m"); + + ep_monitor = (struct epoll_event) { .events = EPOLLIN, - .data.fd = fd_udev, + .data.fd = fd_monitor, }; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) - return log_error_errno(errno, "fail to add fd to epoll: %m"); + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) + return log_error_errno(errno, "Failed to add fd to epoll: %m"); settle_set = set_new(&string_hash_ops); if (!settle_set) @@ -325,10 +325,10 @@ int trigger_main(int argc, char *argv[], void *userdata) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *syspath = NULL; - if (!(ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN)) + if (!(ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN)) continue; - if (udev_monitor_receive_sd_device(udev_monitor, &dev) < 0) + if (device_monitor_receive_device(m, &dev) <= 0) continue; if (sd_device_get_syspath(dev, &syspath) < 0) From c7d942d6ca674475c8db012c75bba95cbdcd2aaf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 2 Oct 2018 16:11:54 +0900 Subject: [PATCH 10/13] udevadm-trigger: modernize code a bit --- src/udev/udevadm-trigger.c | 82 ++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index bdadad30a0..2fdde4bb99 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -12,7 +12,7 @@ #include "device-enumerator-private.h" #include "device-monitor-private.h" #include "fd-util.h" -#include "libudev-private.h" +#include "path-util.h" #include "set.h" #include "string-util.h" #include "strv.h" @@ -27,9 +27,9 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se int r; FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { - char filename[UTIL_PATH_SIZE]; - const char *syspath; + _cleanup_free_ char *filename = NULL; _cleanup_close_ int fd = -1; + const char *syspath; if (sd_device_get_syspath(d, &syspath) < 0) continue; @@ -39,7 +39,10 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se if (arg_dry_run) continue; - strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); + filename = path_join(NULL, syspath, "uevent"); + if (!filename) + return log_oom(); + fd = open(filename, O_WRONLY|O_CLOEXEC); if (fd < 0) continue; @@ -51,22 +54,28 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se } if (write(fd, action, strlen(action)) < 0) - log_debug_errno(errno, "error writing '%s' to '%s': %m", action, filename); + log_debug_errno(errno, "Failed to write '%s' to '%s', ignoring: %m", action, filename); } return 0; } -static const char *keyval(const char *str, const char **val, char *buf, size_t size) { - char *pos; +static char* keyval(const char *str, const char **key, const char **val) { + char *buf, *pos; + + buf = strdup(str); + if (!buf) + return NULL; - strscpy(buf, size,str); pos = strchr(buf, '='); - if (pos != NULL) { + if (pos) { pos[0] = 0; pos++; } + + *key = buf; *val = pos; + return buf; } @@ -142,9 +151,8 @@ int trigger_main(int argc, char *argv[], void *userdata) { return r; while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { - const char *key; - const char *val; - char buf[UTIL_PATH_SIZE]; + _cleanup_free_ char *buf = NULL; + const char *key, *val; switch (c) { case 'v': @@ -159,7 +167,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { else if (streq(optarg, "subsystems")) device_type = TYPE_SUBSYSTEMS; else { - log_error("unknown type --type=%s", optarg); + log_error("Unknown type --type=%s", optarg); return -EINVAL; } break; @@ -167,7 +175,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (STR_IN_SET(optarg, "add", "remove", "change")) action = optarg; else { - log_error("unknown action '%s'", optarg); + log_error("Unknown action '%s'", optarg); return -EINVAL; } @@ -175,51 +183,57 @@ int trigger_main(int argc, char *argv[], void *userdata) { case 's': r = sd_device_enumerator_add_match_subsystem(e, optarg, true); if (r < 0) - return log_error_errno(r, "could not add subsystem match '%s': %m", optarg); + return log_error_errno(r, "Failed to add subsystem match '%s': %m", optarg); break; case 'S': r = sd_device_enumerator_add_match_subsystem(e, optarg, false); if (r < 0) - return log_error_errno(r, "could not add negative subsystem match '%s': %m", optarg); + return log_error_errno(r, "Failed to add negative subsystem match '%s': %m", optarg); break; case 'a': - key = keyval(optarg, &val, buf, sizeof(buf)); + buf = keyval(optarg, &key, &val); + if (!buf) + return log_oom(); r = sd_device_enumerator_add_match_sysattr(e, key, val, true); if (r < 0) - return log_error_errno(r, "could not add sysattr match '%s=%s': %m", key, val); + return log_error_errno(r, "Failed to add sysattr match '%s=%s': %m", key, val); break; case 'A': - key = keyval(optarg, &val, buf, sizeof(buf)); + buf = keyval(optarg, &key, &val); + if (!buf) + return log_oom(); r = sd_device_enumerator_add_match_sysattr(e, key, val, false); if (r < 0) - return log_error_errno(r, "could not add negative sysattr match '%s=%s': %m", key, val); + return log_error_errno(r, "Failed to add negative sysattr match '%s=%s': %m", key, val); break; case 'p': - key = keyval(optarg, &val, buf, sizeof(buf)); + buf = keyval(optarg, &key, &val); + if (!buf) + return log_oom(); r = sd_device_enumerator_add_match_property(e, key, val); if (r < 0) - return log_error_errno(r, "could not add property match '%s=%s': %m", key, val); + return log_error_errno(r, "Failed to add property match '%s=%s': %m", key, val); break; case 'g': r = sd_device_enumerator_add_match_tag(e, optarg); if (r < 0) - return log_error_errno(r, "could not add tag match '%s': %m", optarg); + return log_error_errno(r, "Failed to add tag match '%s': %m", optarg); break; case 'y': r = sd_device_enumerator_add_match_sysname(e, optarg); if (r < 0) - return log_error_errno(r, "could not add sysname match '%s': %m", optarg); + return log_error_errno(r, "Failed to add sysname match '%s': %m", optarg); break; case 'b': { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; r = find_device(optarg, "/sys", &dev); if (r < 0) - return log_error_errno(r, "unable to open the device '%s'", optarg); + return log_error_errno(r, "Failed to open the device '%s': %m", optarg); r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) - return log_error_errno(r, "could not add parent match '%s': %m", optarg); + return log_error_errno(r, "Failed to add parent match '%s': %m", optarg); break; } case 'w': @@ -231,11 +245,11 @@ int trigger_main(int argc, char *argv[], void *userdata) { r = find_device(optarg, "/dev/", &dev); if (r < 0) - return log_error_errno(r, "unable to open the device '%s'", optarg); + return log_error_errno(r, "Failed to open the device '%s': %m", optarg); r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) - return log_error_errno(r, "could not add parent match '%s': %m", optarg); + return log_error_errno(r, "Failed to add parent match '%s': %m", optarg); break; } @@ -255,17 +269,17 @@ int trigger_main(int argc, char *argv[], void *userdata) { r = find_device(argv[optind], NULL, &dev); if (r < 0) - return log_error_errno(r, "unable to open the device '%s'", argv[optind]); + return log_error_errno(r, "Failed to open the device '%s': %m", argv[optind]); r = sd_device_enumerator_add_match_parent(e, dev); if (r < 0) - return log_error_errno(r, "could not add parent match '%s': %m", argv[optind]); + return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]); } if (settle) { fd_ep = epoll_create1(EPOLL_CLOEXEC); if (fd_ep < 0) - return log_error_errno(errno, "error creating epoll fd: %m"); + return log_error_errno(errno, "Failed to create epoll fd: %m"); r = sd_device_monitor_new(&m); if (r < 0) @@ -303,7 +317,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to scan devices: %m"); break; default: - assert_not_reached("device_type"); + assert_not_reached("Unknown device type"); } r = exec_list(e, action, settle_set); if (r < 0) @@ -317,13 +331,13 @@ int trigger_main(int argc, char *argv[], void *userdata) { fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); if (fdcount < 0) { if (errno != EINTR) - log_error_errno(errno, "error receiving uevent message: %m"); + log_error_errno(errno, "Failed to receive uevent message: %m"); continue; } for (i = 0; i < fdcount; i++) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - const char *syspath = NULL; + const char *syspath; if (!(ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN)) continue; From c4abe7191a5a1d1dffdfc733e596a6b84d3fbd14 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 2 Oct 2018 16:23:50 +0900 Subject: [PATCH 11/13] udevadm-info: use strdup() instead of strscpy() --- src/udev/udevadm-info.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index dbbc589e6b..b2127db0b1 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -12,12 +12,12 @@ #include "sd-device.h" +#include "alloc-util.h" #include "device-enumerator-private.h" #include "device-private.h" #include "device-util.h" #include "dirent-util.h" #include "fd-util.h" -#include "libudev-private.h" #include "string-util.h" #include "udevadm.h" #include "udevadm-util.h" @@ -252,10 +252,9 @@ static int help(void) { int info_main(int argc, char *argv[], void *userdata) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; - bool root = 0; - bool export = 0; + bool root = false, export = false; + _cleanup_free_ char *name = NULL; const char *export_prefix = NULL; - char name[UTIL_PATH_SIZE]; int c, r; static const struct option options[] = { @@ -332,7 +331,9 @@ int info_main(int argc, char *argv[], void *userdata) { break; case 'd': action = ACTION_DEVICE_ID_FILE; - strscpy(name, sizeof(name), optarg); + name = strdup(optarg); + if (!name) + return log_oom(); break; case 'a': action = ACTION_ATTRIBUTE_WALK; From fb3d8e9f441b12a6b8c44b4b35efd1b3ac9484ae Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 9 Oct 2018 15:35:56 +0900 Subject: [PATCH 12/13] udevadm-trigger: use sd_event_loop() --- src/udev/udevadm-trigger.c | 103 ++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 2fdde4bb99..66ed0aee59 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -1,16 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0+ */ #include -#include #include -#include -#include -#include -#include -#include + +#include "sd-device.h" +#include "sd-event.h" #include "device-enumerator-private.h" -#include "device-monitor-private.h" #include "fd-util.h" #include "path-util.h" #include "set.h" @@ -60,6 +56,28 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se return 0; } +static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) { + Set *settle_set = userdata; + const char *syspath; + + assert(dev); + assert(settle_set); + + if (sd_device_get_syspath(dev, &syspath) < 0) + return 0; + + if (arg_verbose) + printf("settle %s\n", syspath); + + if (!set_remove(settle_set, syspath)) + log_debug("Got epoll event on syspath %s not present in syspath set", syspath); + + if (set_isempty(settle_set)) + return sd_event_exit(sd_device_monitor_get_event(m), 0); + + return 0; +} + static char* keyval(const char *str, const char **key, const char **val) { char *buf, *pos; @@ -136,11 +154,10 @@ int trigger_main(int argc, char *argv[], void *userdata) { const char *action = "change"; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_set_free_free_ Set *settle_set = NULL; - _cleanup_close_ int fd_ep = -1; - struct epoll_event ep_monitor; - int c, r, fd_monitor = -1; bool settle = false; + int c, r; r = sd_device_enumerator_new(&e); if (r < 0) @@ -277,32 +294,25 @@ int trigger_main(int argc, char *argv[], void *userdata) { } if (settle) { - fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) - return log_error_errno(errno, "Failed to create epoll fd: %m"); + settle_set = set_new(&string_hash_ops); + if (!settle_set) + return log_oom(); + + r = sd_event_default(&event); + if (r < 0) + return log_error_errno(r, "Failed to get default event: %m"); r = sd_device_monitor_new(&m); if (r < 0) return log_error_errno(r, "Failed to create device monitor object: %m"); - fd_monitor = device_monitor_get_fd(m); - if (fd_monitor < 0) - return log_error_errno(fd_monitor, "Failed to get monitor fd: %m"); - - r = device_monitor_enable_receiving(m); + r = sd_device_monitor_attach_event(m, event, 0); if (r < 0) - return log_error_errno(r, "Failed to subscribe udev events: %m"); + return log_error_errno(r, "Failed to attach event to device monitor: %m"); - ep_monitor = (struct epoll_event) { - .events = EPOLLIN, - .data.fd = fd_monitor, - }; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) - return log_error_errno(errno, "Failed to add fd to epoll: %m"); - - settle_set = set_new(&string_hash_ops); - if (!settle_set) - return log_oom(); + r = sd_device_monitor_start(m, device_monitor_handler, settle_set, "udevadm-trigger-device-monitor"); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %m"); } switch (device_type) { @@ -323,37 +333,10 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; - while (!set_isempty(settle_set)) { - int fdcount; - struct epoll_event ev[4]; - int i; - - fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); - if (fdcount < 0) { - if (errno != EINTR) - log_error_errno(errno, "Failed to receive uevent message: %m"); - continue; - } - - for (i = 0; i < fdcount; i++) { - _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - const char *syspath; - - if (!(ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN)) - continue; - - if (device_monitor_receive_device(m, &dev) <= 0) - continue; - - if (sd_device_get_syspath(dev, &syspath) < 0) - continue; - - if (arg_verbose) - printf("settle %s\n", syspath); - - if (!set_remove(settle_set, syspath)) - log_debug("Got epoll event on syspath %s not present in syspath set", syspath); - } + if (event && !set_isempty(settle_set)) { + r = sd_event_loop(event); + if (r < 0) + return log_error_errno(r, "Event loop failed: %m"); } return 0; From 66a948605b54dace6512d56113e75b5107286586 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 9 Oct 2018 16:02:53 +0900 Subject: [PATCH 13/13] udevadm-monitor: use sd_event_loop() --- src/udev/udevadm-monitor.c | 114 +++++++++++-------------------------- 1 file changed, 32 insertions(+), 82 deletions(-) diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index b5fbead7bc..631f69ded4 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -3,14 +3,9 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include "sd-device.h" +#include "sd-event.h" #include "alloc-util.h" #include "device-monitor-private.h" @@ -19,30 +14,23 @@ #include "format-util.h" #include "hashmap.h" #include "set.h" +#include "signal-util.h" #include "string-util.h" #include "udevadm.h" -static bool udev_exit = false; static bool arg_show_property = false; static bool arg_print_kernel = false; static bool arg_print_udev = false; static Set *arg_tag_filter = NULL; static Hashmap *arg_subsystem_filter = NULL; -static void sig_handler(int signum) { - if (IN_SET(signum, SIGINT, SIGTERM)) - udev_exit = true; -} - -static int receive_and_print_device(sd_device_monitor *monitor, const char *source) { +static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) { const char *action = NULL, *devpath = NULL, *subsystem = NULL; - _cleanup_(sd_device_unrefp) sd_device *device = NULL; + MonitorNetlinkGroup group = PTR_TO_INT(userdata); struct timespec ts; - int r; - r = device_monitor_receive_device(monitor, &device); - if (r < 0) - return log_debug_errno(r, "Failed to receive device from %s, ignoring: %m", source); + assert(device); + assert(IN_SET(group, MONITOR_GROUP_UDEV, MONITOR_GROUP_KERNEL)); (void) sd_device_get_property_value(device, "ACTION", &action); (void) sd_device_get_devpath(device, &devpath); @@ -51,7 +39,7 @@ static int receive_and_print_device(sd_device_monitor *monitor, const char *sour assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); printf("%-6s[%"PRI_TIME".%06"PRI_NSEC"] %-8s %s (%s)\n", - source, + group == MONITOR_GROUP_UDEV ? "UDEV" : "KERNEL", ts.tv_sec, (nsec_t)ts.tv_nsec/1000, action, devpath, subsystem); @@ -67,24 +55,21 @@ static int receive_and_print_device(sd_device_monitor *monitor, const char *sour return 0; } -static int setup_monitor(MonitorNetlinkGroup sender, int fd_epoll, sd_device_monitor **ret) { +static int setup_monitor(MonitorNetlinkGroup sender, sd_event *event, sd_device_monitor **ret) { _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; const char *subsystem, *devtype, *tag; - struct epoll_event ep = {}; Iterator i; - int fd, r; + int r; r = device_monitor_new_full(&monitor, sender, -1); if (r < 0) return log_error_errno(r, "Failed to create netlink socket: %m"); - r = sd_device_monitor_set_receive_buffer_size(monitor, 128*1024*1024); - if (r < 0) - return log_error_errno(r, "Failed to set receive buffer size: %m"); + (void) sd_device_monitor_set_receive_buffer_size(monitor, 128*1024*1024); - fd = device_monitor_get_fd(monitor); - if (fd < 0) - return log_error_errno(r, "Failed to get socket fd for monitoring: %m"); + r = sd_device_monitor_attach_event(monitor, event, 0); + if (r < 0) + return log_error_errno(r, "Failed to attach event: %m"); HASHMAP_FOREACH_KEY(devtype, subsystem, arg_subsystem_filter, i) { r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, devtype); @@ -99,20 +84,12 @@ static int setup_monitor(MonitorNetlinkGroup sender, int fd_epoll, sd_device_mon return log_error_errno(r, "Failed to apply tag filter '%s': %m", tag); } - r = device_monitor_enable_receiving(monitor); + r = sd_device_monitor_start(monitor, device_monitor_handler, INT_TO_PTR(sender), sender == MONITOR_GROUP_UDEV ? "device-monitor-udev" : "device-monitor-kernel"); if (r < 0) - return log_error_errno(r, "Failed to subscribe %s events: %m", sender == MONITOR_GROUP_UDEV ? "udev" : "kernel"); - - ep = (struct epoll_event) { - .events = EPOLLIN, - .data.fd = fd, - }; - - if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd, &ep) < 0) - return log_error_errno(errno, "Failed to add fd to epoll: %m"); + return log_error_errno(r, "Failed to start device monitor: %m"); *ret = TAKE_PTR(monitor); - return fd; + return 0; } static int help(void) { @@ -223,75 +200,48 @@ static int parse_argv(int argc, char *argv[]) { int monitor_main(int argc, char *argv[], void *userdata) { _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *kernel_monitor = NULL, *udev_monitor = NULL; - int fd_kernel = -1, fd_udev = -1; - _cleanup_close_ int fd_ep = -1; - struct sigaction act; - sigset_t mask; + _cleanup_(sd_event_unrefp) sd_event *event; int r; r = parse_argv(argc, argv); if (r <= 0) goto finalize; - /* set signal handlers */ - act = (struct sigaction) { - .sa_handler = sig_handler, - .sa_flags = SA_RESTART, - }; - assert_se(sigaction(SIGINT, &act, NULL) == 0); - assert_se(sigaction(SIGTERM, &act, NULL) == 0); - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGINT) == 0); - assert_se(sigaddset(&mask, SIGTERM) == 0); - assert_se(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0); - /* Callers are expecting to see events as they happen: Line buffering */ setlinebuf(stdout); - fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - r = log_error_errno(errno, "Failed to create epoll fd: %m"); + r = sd_event_default(&event); + if (r < 0) { + log_error_errno(r, "Failed to initialize event: %m"); goto finalize; } + assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); + (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); + (void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); + printf("monitor will print the received events for:\n"); if (arg_print_udev) { - fd_udev = setup_monitor(MONITOR_GROUP_UDEV, fd_ep, &udev_monitor); - if (fd_udev < 0) { - r = fd_udev; + r = setup_monitor(MONITOR_GROUP_UDEV, event, &udev_monitor); + if (r < 0) goto finalize; - } printf("UDEV - the event which udev sends out after rule processing\n"); } if (arg_print_kernel) { - fd_kernel = setup_monitor(MONITOR_GROUP_KERNEL, fd_ep, &kernel_monitor); - if (fd_kernel < 0) { - r = fd_kernel; + r = setup_monitor(MONITOR_GROUP_KERNEL, event, &kernel_monitor); + if (r < 0) goto finalize; - } printf("KERNEL - the kernel uevent\n"); } printf("\n"); - while (!udev_exit) { - struct epoll_event ev[4]; - int fdcount, i; - - fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); - if (fdcount < 0) { - if (errno != EINTR) - log_debug_errno(errno, "Failed to receive uevent message, ignoring: %m"); - continue; - } - - for (i = 0; i < fdcount; i++) - if (ev[i].data.fd == fd_kernel && ev[i].events & EPOLLIN) - (void) receive_and_print_device(kernel_monitor, "KERNEL"); - else if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) - (void) receive_and_print_device(udev_monitor, "UDEV"); + r = sd_event_loop(event); + if (r < 0) { + log_error_errno(r, "Failed to run event loop: %m"); + goto finalize; } r = 0;