diff options
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | udev/lib/exported_symbols | 1 | ||||
-rw-r--r-- | udev/lib/libudev-device.c | 18 | ||||
-rw-r--r-- | udev/lib/libudev-monitor.c | 281 | ||||
-rw-r--r-- | udev/lib/libudev-private.h | 1 | ||||
-rw-r--r-- | udev/lib/libudev-util.c | 65 | ||||
-rw-r--r-- | udev/lib/libudev.h | 1 | ||||
-rw-r--r-- | udev/lib/test-libudev.c | 7 |
8 files changed, 326 insertions, 54 deletions
diff --git a/configure.ac b/configure.ac index cbe2833f22..f611864258 100644 --- a/configure.ac +++ b/configure.ac @@ -14,9 +14,9 @@ AC_PREFIX_DEFAULT([/usr]) test "$prefix" = NONE && test "$exec_prefix" = NONE && exec_prefix= dnl /* libudev version */ -LIBUDEV_LT_CURRENT=2 -LIBUDEV_LT_REVISION=1 -LIBUDEV_LT_AGE=2 +LIBUDEV_LT_CURRENT=3 +LIBUDEV_LT_REVISION=0 +LIBUDEV_LT_AGE=3 AC_SUBST(LIBUDEV_LT_CURRENT) AC_SUBST(LIBUDEV_LT_REVISION) AC_SUBST(LIBUDEV_LT_AGE) diff --git a/udev/lib/exported_symbols b/udev/lib/exported_symbols index 27314e4a26..23cd8fbe28 100644 --- a/udev/lib/exported_symbols +++ b/udev/lib/exported_symbols @@ -56,6 +56,7 @@ udev_monitor_unref udev_monitor_get_udev udev_monitor_get_fd udev_monitor_receive_device +udev_monitor_filter_add_match_subsystem udev_queue_new udev_queue_ref udev_queue_unref diff --git a/udev/lib/libudev-device.c b/udev/lib/libudev-device.c index 2b6086d032..92b2d18b83 100644 --- a/udev/lib/libudev-device.c +++ b/udev/lib/libudev-device.c @@ -1074,7 +1074,6 @@ const char *udev_device_get_property_value(struct udev_device *udev_device, cons #define MONITOR_BUF_SIZE 4096 static int update_envp_monitor_buf(struct udev_device *udev_device) { - const char *action; struct udev_list_entry *list_entry; size_t bufpos; size_t len; @@ -1093,23 +1092,8 @@ static int update_envp_monitor_buf(struct udev_device *udev_device) if (udev_device->envp == NULL) return -ENOMEM; - /* header <action>@<devpath> */ - action = udev_device_get_action(udev_device); - if (action == NULL) - return -EINVAL; - bufpos = util_strlcpy(udev_device->monitor_buf, action, MONITOR_BUF_SIZE); - len = util_strlcpy(&udev_device->monitor_buf[bufpos], "@", MONITOR_BUF_SIZE-bufpos); - if (len >= MONITOR_BUF_SIZE-bufpos) - return -EINVAL; - bufpos += len; - len = util_strlcpy(&udev_device->monitor_buf[bufpos], - udev_device_get_devpath(udev_device), - MONITOR_BUF_SIZE-bufpos); - if (len+1 >= MONITOR_BUF_SIZE-bufpos) - return -EINVAL; - bufpos += len+1; - i = 0; + bufpos = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { /* add string to envp array */ udev_device->envp[i++] = &udev_device->monitor_buf[bufpos]; diff --git a/udev/lib/libudev-monitor.c b/udev/lib/libudev-monitor.c index e68bdf5bac..570fcafbb4 100644 --- a/udev/lib/libudev-monitor.c +++ b/udev/lib/libudev-monitor.c @@ -16,10 +16,13 @@ #include <errno.h> #include <string.h> #include <dirent.h> +#include <sys/poll.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> +#include <arpa/inet.h> #include <linux/netlink.h> +#include <linux/filter.h> #include "libudev.h" #include "libudev-private.h" @@ -32,6 +35,7 @@ struct udev_monitor { struct sockaddr_nl snl_peer; struct sockaddr_un sun; socklen_t addrlen; + struct udev_list_node filter_subsystem_list; }; enum udev_monitor_netlink_group { @@ -39,6 +43,38 @@ enum udev_monitor_netlink_group { UDEV_MONITOR_UDEV = 2, }; +#define UDEV_MONITOR_MAGIC 0xcafe1dea +struct udev_monitor_netlink_header { + /* udev version text */ + char version[16]; + /* + * 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 int magic; + /* properties buffer */ + unsigned short properties_off; + unsigned short properties_len; + /* + * crc32 of some common device properties to filter with socket filters in the client + * used in the kernel from socket filter rules; needs to be stored in network order + */ + unsigned int filter_subsystem; +}; + +static struct udev_monitor *udev_monitor_new(struct udev *udev) +{ + struct udev_monitor *udev_monitor; + + udev_monitor = calloc(1, sizeof(struct udev_monitor)); + if (udev_monitor == NULL) + return NULL; + udev_monitor->refcount = 1; + udev_monitor->udev = udev; + udev_list_init(&udev_monitor->filter_subsystem_list); + return udev_monitor; +} + /** * udev_monitor_new_from_socket: * @udev: udev library context @@ -68,11 +104,9 @@ struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char return NULL; if (socket_path == NULL) return NULL; - udev_monitor = calloc(1, sizeof(struct udev_monitor)); + udev_monitor = udev_monitor_new(udev); if (udev_monitor == NULL) return NULL; - udev_monitor->refcount = 1; - udev_monitor->udev = udev; udev_monitor->sun.sun_family = AF_LOCAL; if (socket_path[0] == '@') { @@ -143,11 +177,9 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char else return NULL; - udev_monitor = calloc(1, sizeof(struct udev_monitor)); + udev_monitor = udev_monitor_new(udev); if (udev_monitor == NULL) return NULL; - udev_monitor->refcount = 1; - udev_monitor->udev = udev; udev_monitor->sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (udev_monitor->sock == -1) { @@ -166,19 +198,91 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char return udev_monitor; } +static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data) +{ + struct sock_filter *ins = &inss[*i]; + + ins->code = code; + ins->k = data; + (*i)++; +} + +static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data, + unsigned short jt, unsigned short jf) +{ + struct sock_filter *ins = &inss[*i]; + + ins->code = code; + ins->jt = jt; + ins->jf = jf; + ins->k = data; + (*i)++; +} + +static int filter_apply(struct udev_monitor *udev_monitor) +{ + static struct sock_filter ins[256]; + static struct sock_fprog filter; + unsigned int i; + struct udev_list_entry *list_entry; + int err; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) + return 0; + + memset(ins, 0x00, sizeof(ins)); + i = 0; + + /* load magic in accu */ + 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, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + + /* load filter_subsystem value in accu */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem)); + /* add all subsystem match values */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { + const char *subsys = udev_list_entry_get_name(list_entry); + unsigned int crc; + + crc = util_crc32((unsigned char *)subsys, strlen(subsys)); + /* jump if value does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, crc, 0, 1); + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + if (i+1 >= ARRAY_SIZE(ins)) + return -1; + } + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + + /* install filter */ + filter.len = i; + filter.filter = ins; + err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); + return err; +} + int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { int err; const int on = 1; - if (udev_monitor->sun.sun_family != 0) + if (udev_monitor->sun.sun_family != 0) { err = bind(udev_monitor->sock, (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen); - else if (udev_monitor->snl.nl_family != 0) + } else if (udev_monitor->snl.nl_family != 0) { + filter_apply(udev_monitor); err = bind(udev_monitor->sock, (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl)); - else + } else { return -EINVAL; + } if (err < 0) { err(udev_monitor->udev, "bind failed: %m\n"); @@ -231,6 +335,7 @@ void udev_monitor_unref(struct udev_monitor *udev_monitor) return; if (udev_monitor->sock >= 0) close(udev_monitor->sock); + udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list); dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor); free(udev_monitor); } @@ -265,6 +370,25 @@ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) return udev_monitor->sock; } +static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) +{ + struct udev_list_entry *list_entry; + int pass = 0; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) + return 1; + + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { + const char *subsys = udev_device_get_subsystem(udev_device); + + if (strcmp(udev_list_entry_get_name(list_entry), subsys) == 0) { + pass= 1; + break; + } + } + return pass; +} + /** * udev_monitor_receive_device: * @udev_monitor: udev monitor @@ -292,12 +416,14 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito struct ucred *cred; char buf[4096]; size_t bufpos; + struct udev_monitor_netlink_header *nlh; int devpath_set = 0; int subsystem_set = 0; int action_set = 0; int maj = 0; int min = 0; +retry: if (udev_monitor == NULL) return NULL; memset(buf, 0x00, sizeof(buf)); @@ -311,7 +437,7 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito if (udev_monitor->snl.nl_family != 0) { smsg.msg_name = &snl; - smsg.msg_namelen = sizeof snl; + smsg.msg_namelen = sizeof(snl); } if (recvmsg(udev_monitor->sock, &smsg, 0) < 0) { @@ -343,17 +469,27 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito return NULL; } - /* skip header */ - bufpos = strlen(buf) + 1; - if (bufpos < sizeof("a@/d") || bufpos >= sizeof(buf)) { - info(udev_monitor->udev, "invalid message length\n"); - return NULL; - } + nlh = (struct udev_monitor_netlink_header *) buf; + if (nlh->magic == ntohl(UDEV_MONITOR_MAGIC)) { + /* udev message with version magic */ + if (nlh->properties_off < sizeof(struct udev_monitor_netlink_header)) + return NULL; + if (nlh->properties_off+32U > sizeof(buf)) + return NULL; + bufpos = nlh->properties_off; + } else { + /* kernel message with header */ + bufpos = strlen(buf) + 1; + if (bufpos < sizeof("a@/d") || bufpos >= sizeof(buf)) { + info(udev_monitor->udev, "invalid message length\n"); + return NULL; + } - /* check message header */ - if (strstr(buf, "@/") == NULL) { - info(udev_monitor->udev, "unrecognized message header\n"); - return NULL; + /* check message header */ + if (strstr(buf, "@/") == NULL) { + info(udev_monitor->udev, "unrecognized message header\n"); + return NULL; + } } udev_device = device_new(udev_monitor->udev); @@ -430,6 +566,23 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito udev_device_unref(udev_device); return NULL; } + + /* skip device, if it does not pass the current filter */ + if (!passes_filter(udev_monitor, udev_device)) { + struct pollfd pfd[1]; + int rc; + + udev_device_unref(udev_device); + + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + rc = poll(pfd, 1, 0); + if (rc > 0) + goto retry; + return NULL; + } + if (maj > 0) udev_device_set_devnum(udev_device, makedev(maj, min)); udev_device_set_info_loaded(udev_device); @@ -438,27 +591,87 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_device *udev_device) { + struct msghdr smsg; + struct iovec iov[2]; const char *buf; - ssize_t len; + ssize_t blen; ssize_t count; - len = udev_device_get_properties_monitor_buf(udev_device, &buf); - if (len < 32) + blen = udev_device_get_properties_monitor_buf(udev_device, &buf); + if (blen < 32) return -1; - if (udev_monitor->sun.sun_family != 0) - count = sendto(udev_monitor->sock, - buf, len, 0, - (struct sockaddr *)&udev_monitor->sun, - udev_monitor->addrlen); - else if (udev_monitor->snl.nl_family != 0) + + if (udev_monitor->sun.sun_family != 0) { + const char *action; + char header[2048]; + size_t hlen; + + /* header <action>@<devpath> */ + action = udev_device_get_action(udev_device); + if (action == NULL) + return -EINVAL; + util_strlcpy(header, action, sizeof(header)); + util_strlcat(header, "@", sizeof(header)); + hlen = util_strlcat(header, udev_device_get_devpath(udev_device), sizeof(header))+1; + if (hlen >= sizeof(header)) + return -EINVAL; + iov[0].iov_base = header; + iov[0].iov_len = hlen; + + /* add properties list */ + iov[1].iov_base = (char *)buf; + iov[1].iov_len = blen; + + memset(&smsg, 0x00, sizeof(struct msghdr)); + smsg.msg_iov = iov; + smsg.msg_iovlen = 2; + smsg.msg_name = &udev_monitor->sun; + smsg.msg_namelen = udev_monitor->addrlen; + } else if (udev_monitor->snl.nl_family != 0) { + const char *val; + size_t vlen; + struct udev_monitor_netlink_header nlh; + + + /* add versioned header */ + memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header)); + util_strlcpy(nlh.version, "udev-" VERSION, sizeof(nlh.version)); + nlh.magic = htonl(UDEV_MONITOR_MAGIC); + val = udev_device_get_subsystem(udev_device); + vlen = strlen(val); + nlh.filter_subsystem = htonl(util_crc32((unsigned char *)val, vlen)); + iov[0].iov_base = &nlh; + iov[0].iov_len = sizeof(struct udev_monitor_netlink_header); + + /* add properties list */ + nlh.properties_off = iov[0].iov_len; + nlh.properties_len = blen; + iov[1].iov_base = (char *)buf; + iov[1].iov_len = blen; + + memset(&smsg, 0x00, sizeof(struct msghdr)); + smsg.msg_iov = iov; + smsg.msg_iovlen = 2; /* no destination besides the muticast group, we will always get ECONNREFUSED */ - count = sendto(udev_monitor->sock, - buf, len, 0, - (struct sockaddr *)&udev_monitor->snl_peer, - sizeof(struct sockaddr_nl)); - else + smsg.msg_name = &udev_monitor->snl_peer; + smsg.msg_namelen = sizeof(struct sockaddr_nl); + } else { return -1; + } + count = sendmsg(udev_monitor->sock, &smsg, 0); info(udev_monitor->udev, "passed %zi bytes to monitor %p\n", count, udev_monitor); return count; } + +int udev_monitor_filter_add_match_subsystem(struct udev_monitor *udev_monitor, const char *subsystem) +{ + if (udev_monitor == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add(udev_monitor->udev, + &udev_monitor->filter_subsystem_list, subsystem, NULL, 1, 0) == NULL) + return -ENOMEM; + return 0; +} diff --git a/udev/lib/libudev-private.h b/udev/lib/libudev-private.h index 1e47d51080..178004c485 100644 --- a/udev/lib/libudev-private.h +++ b/udev/lib/libudev-private.h @@ -173,4 +173,5 @@ extern int udev_util_replace_whitespace(const char *str, char *to, size_t len); extern int udev_util_replace_chars(char *str, const char *white); extern int udev_util_encode_string(const char *str, char *str_enc, size_t len); extern void util_set_fd_cloexec(int fd); +extern unsigned int util_crc32(const unsigned char *buf, size_t len); #endif diff --git a/udev/lib/libudev-util.c b/udev/lib/libudev-util.c index 243a99dce9..018e2cdb08 100644 --- a/udev/lib/libudev-util.c +++ b/udev/lib/libudev-util.c @@ -461,3 +461,68 @@ void util_set_fd_cloexec(int fd) flags |= FD_CLOEXEC; fcntl(fd, F_SETFD, flags); } + +unsigned int util_crc32(const unsigned char *buf, size_t len) +{ + unsigned int crc; + const unsigned char *end; + static const unsigned int crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + + crc = 0xffffffff; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/udev/lib/libudev.h b/udev/lib/libudev.h index e0aa571e26..4094b3a822 100644 --- a/udev/lib/libudev.h +++ b/udev/lib/libudev.h @@ -84,6 +84,7 @@ extern void udev_monitor_unref(struct udev_monitor *udev_monitor); extern struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); extern int udev_monitor_get_fd(struct udev_monitor *udev_monitor); extern struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); +extern int udev_monitor_filter_add_match_subsystem(struct udev_monitor *udev_monitor, const char *subsystem); /* sys enumeration */ struct udev_enumerate; diff --git a/udev/lib/test-libudev.c b/udev/lib/test-libudev.c index be167cff47..0f09bbbb60 100644 --- a/udev/lib/test-libudev.c +++ b/udev/lib/test-libudev.c @@ -228,6 +228,12 @@ static int test_monitor(struct udev *udev) printf("no socket\n"); return -1; } + if (udev_monitor_filter_add_match_subsystem(udev_monitor, "block") < 0 || + udev_monitor_filter_add_match_subsystem(udev_monitor, "tty") < 0 || + udev_monitor_filter_add_match_subsystem(udev_monitor, "usb") < 0) { + printf("filter failed\n"); + return -1; + } if (udev_monitor_enable_receiving(udev_monitor) < 0) { printf("bind failed\n"); return -1; @@ -251,6 +257,7 @@ static int test_monitor(struct udev *udev) device = udev_monitor_receive_device(udev_monitor); if (device == NULL) { printf("no device from socket\n"); +sleep(1); continue; } print_device(device); |