diff options
| -rw-r--r-- | udev/lib/Makefile.am | 3 | ||||
| -rw-r--r-- | udev/lib/exported_symbols | 10 | ||||
| -rw-r--r-- | udev/lib/libudev-private.h | 6 | ||||
| -rw-r--r-- | udev/lib/libudev-queue.c | 286 | ||||
| -rw-r--r-- | udev/lib/libudev.h | 14 | ||||
| -rw-r--r-- | udev/lib/test-libudev.c | 51 | 
6 files changed, 365 insertions, 5 deletions
| diff --git a/udev/lib/Makefile.am b/udev/lib/Makefile.am index e800cf7f41..08e7ff865b 100644 --- a/udev/lib/Makefile.am +++ b/udev/lib/Makefile.am @@ -24,7 +24,8 @@ libudev_la_SOURCES =\  	libudev-device.c \  	libudev-enumerate.c \  	libudev-ctrl.c \ -	libudev-monitor.c +	libudev-monitor.c \ +	libudev-queue.c  libudev_la_LDFLAGS = \  	-version-info $(LIBUDEV_LT_CURRENT):$(LIBUDEV_LT_REVISION):$(LIBUDEV_LT_AGE) \ diff --git a/udev/lib/exported_symbols b/udev/lib/exported_symbols index edd3c76f3d..81abb58d64 100644 --- a/udev/lib/exported_symbols +++ b/udev/lib/exported_symbols @@ -51,3 +51,13 @@ udev_monitor_unref  udev_monitor_get_udev  udev_monitor_get_fd  udev_monitor_receive_device +udev_queue_new +udev_queue_ref +udev_queue_unref +udev_queue_get_udev +udev_queue_get_kernel_seqnum +udev_queue_get_udev_seqnum +udev_queue_get_queue_is_empty +udev_queue_get_seqnum_is_finished +udev_queue_get_queued_list_entry +udev_queue_get_failed_list_entry diff --git a/udev/lib/libudev-private.h b/udev/lib/libudev-private.h index fd7f4551e7..7747b344fe 100644 --- a/udev/lib/libudev-private.h +++ b/udev/lib/libudev-private.h @@ -120,6 +120,12 @@ extern void list_entry_move_to_end(struct udev_list_entry *list_entry);  	     entry != NULL; \  	     entry = tmp, tmp = udev_list_entry_get_next(tmp)) +/* libudev-queue */ +extern int queue_export_udev_seqnum(struct udev_queue *udev_queue, unsigned long long int seqnum); +extern int queue_export_device_queued(struct udev_queue *udev_queue, struct udev_device *udev_device); +extern int queue_export_device_finished(struct udev_queue *udev_queue, struct udev_device *udev_device); +extern int queue_export_device_failed(struct udev_queue *udev_queue, struct udev_device *udev_device); +  /* libudev-utils */  #define UTIL_PATH_SIZE		1024  #define UTIL_LINE_SIZE		2048 diff --git a/udev/lib/libudev-queue.c b/udev/lib/libudev-queue.c new file mode 100644 index 0000000000..3ca533b1e0 --- /dev/null +++ b/udev/lib/libudev-queue.c @@ -0,0 +1,286 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include "libudev.h" +#include "libudev-private.h" + +struct udev_queue { +	struct udev *udev; +	int refcount; +	unsigned long long int last_seen_udev_seqnum; +	struct list_node queue_list; +	struct list_node failed_list; +}; + +struct udev_queue *udev_queue_new(struct udev *udev) +{ +	struct udev_queue *udev_queue; + +	if (udev == NULL) +		return NULL; + +	udev_queue = malloc(sizeof(struct udev_queue)); +	if (udev_queue == NULL) +		return NULL; +	memset(udev_queue, 0x00, sizeof(struct udev_queue)); +	udev_queue->refcount = 1; +	udev_queue->udev = udev; +	list_init(&udev_queue->queue_list); +	list_init(&udev_queue->failed_list); +	return udev_queue; +} + +struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) +{ +	if (udev_queue == NULL) +		return NULL; +	udev_queue->refcount++; +	return udev_queue; +} + +void udev_queue_unref(struct udev_queue *udev_queue) +{ +	if (udev_queue == NULL) +		return; +	udev_queue->refcount--; +	if (udev_queue->refcount > 0) +		return; +	list_cleanup(udev_queue->udev, &udev_queue->queue_list); +	list_cleanup(udev_queue->udev, &udev_queue->failed_list); +	free(udev_queue); +} + +struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) +{ +	if (udev_queue == NULL) +		return NULL; +	return udev_queue->udev; +} + +unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) +{ +	char filename[UTIL_PATH_SIZE]; +	unsigned long long int seqnum; +	int fd; +	char buf[32]; +	ssize_t len; + +	if (udev_queue == NULL) +		return -EINVAL; +	util_strlcpy(filename, udev_get_sys_path(udev_queue->udev), sizeof(filename)); +	util_strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename)); +	fd = open(filename, O_RDONLY); +	if (fd < 0) +		return 0; +	len = read(fd, buf, sizeof(buf)); +	close(fd); +	if (len <= 2) +		return 0; +	buf[len-1] = '\0'; +	seqnum = strtoull(buf, NULL, 10); +	info(udev_queue->udev, "seqnum=%llu\n", seqnum); +	return seqnum; +} + +unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) +{ +	char filename[UTIL_PATH_SIZE]; +	unsigned long long int seqnum; +	int fd; +	char buf[32]; +	ssize_t len; + +	if (udev_queue == NULL) +		return -EINVAL; +	util_strlcpy(filename, udev_get_dev_path(udev_queue->udev), sizeof(filename)); +	util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); +	fd = open(filename, O_RDONLY); +	if (fd < 0) +		return 0; +	len = read(fd, buf, sizeof(buf)); +	close(fd); +	if (len <= 2) +		return 0; +	buf[len-1] = '\0'; +	seqnum = strtoull(buf, NULL, 10); +	info(udev_queue->udev, "seqnum=%llu\n", seqnum); +	udev_queue->last_seen_udev_seqnum = seqnum; +	return seqnum; +} + +int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) +{ +	char queuename[UTIL_PATH_SIZE]; +	struct stat statbuf; +	unsigned long long int seqnum_kernel; + +	if (udev_queue == NULL) +		return -EINVAL; +	util_strlcpy(queuename, udev_get_dev_path(udev_queue->udev), sizeof(queuename)); +	util_strlcat(queuename, "/.udev/queue", sizeof(queuename)); +	if (stat(queuename, &statbuf) == 0) { +		info(udev_queue->udev, "queue is not empty\n"); +		return 0; +	} +	seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue); +	if (seqnum_kernel <= udev_queue->last_seen_udev_seqnum) { +		info(udev_queue->udev, "queue is empty\n"); +		return 1; +	} +	udev_queue_get_udev_seqnum(udev_queue); +	if (seqnum_kernel <= udev_queue->last_seen_udev_seqnum) { +		info(udev_queue->udev, "queue is empty\n"); +		return 1; +	} +	info(udev_queue->udev, "queue is empty, but kernel events still pending [%llu]<->[%llu]\n", +	     seqnum_kernel, udev_queue->last_seen_udev_seqnum); +	return 0; +} + +int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) +{ +	char filename[UTIL_PATH_SIZE]; +	struct stat statbuf; + +	if (udev_queue == NULL) +		return -EINVAL; +	/* if we have not seen this seqnum, check if it is/was already queued */ +	if (seqnum < udev_queue->last_seen_udev_seqnum) { +		udev_queue_get_udev_seqnum(udev_queue); +		if (seqnum < udev_queue->last_seen_udev_seqnum) +			return 0; +	} +	snprintf(filename, sizeof(filename), "%s/.udev/queue/%llu", +		 udev_get_dev_path(udev_queue->udev), seqnum); +	if (stat(filename, &statbuf) == 0) +		return 0; +	info(udev_queue->udev, "seqnum: %llu finished\n", seqnum); +	return 1; +} + +struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) +{ +	char path[UTIL_PATH_SIZE]; +	DIR *dir; +	struct dirent *dent; + +	if (udev_queue == NULL) +		return NULL; +	list_cleanup(udev_queue->udev, &udev_queue->queue_list); +	util_strlcpy(path, udev_get_dev_path(udev_queue->udev), sizeof(path)); +	util_strlcat(path, "/.udev/queue", sizeof(path)); +	dir = opendir(path); +	if (dir == NULL) +		return NULL; +	for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { +		char filename[UTIL_PATH_SIZE]; +		char syspath[UTIL_PATH_SIZE]; +		size_t syslen; +		ssize_t len; + +		if (dent->d_name[0] == '.') +			continue; +		util_strlcpy(filename, path, sizeof(filename)); +		util_strlcat(filename, "/", sizeof(filename)); +		util_strlcat(filename, dent->d_name, sizeof(filename)); + +		syslen = util_strlcpy(syspath, udev_get_sys_path(udev_queue->udev), sizeof(syspath)); +		len = readlink(filename, &syspath[syslen], sizeof(syspath)-syslen); +		if (len < 0 || len >= (ssize_t)(sizeof(syspath)-syslen)) +			continue; +		syspath[syslen + len] = '\0'; +		info(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name); +		list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, dent->d_name, 0, 0); +	} +	closedir(dir); +	return list_get_entry(&udev_queue->queue_list); +} + +struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue) +{ +	char path[UTIL_PATH_SIZE]; +	DIR *dir; +	struct dirent *dent; + +	if (udev_queue == NULL) +		return NULL; +	list_cleanup(udev_queue->udev, &udev_queue->failed_list); +	util_strlcpy(path, udev_get_dev_path(udev_queue->udev), sizeof(path)); +	util_strlcat(path, "/.udev/failed", sizeof(path)); +	dir = opendir(path); +	if (dir == NULL) +		return NULL; +	for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { +		char filename[UTIL_PATH_SIZE]; +		char syspath[UTIL_PATH_SIZE]; +		struct stat statbuf; +		size_t syslen; +		ssize_t len; + +		if (dent->d_name[0] == '.') +			continue; +		util_strlcpy(filename, path, sizeof(filename)); +		util_strlcat(filename, "/", sizeof(filename)); +		util_strlcat(filename, dent->d_name, sizeof(filename)); + +		syslen = util_strlcpy(syspath, udev_get_sys_path(udev_queue->udev), sizeof(syspath)); +		len = readlink(filename, &syspath[syslen], sizeof(syspath)-syslen); +		if (len < 0 || len >= (ssize_t)(sizeof(syspath)-syslen)) +			continue; +		syspath[syslen + len] = '\0'; +		info(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name); +		util_strlcpy(filename, syspath, sizeof(filename)); +		util_strlcat(filename, "/uevent", sizeof(filename)); +		if (stat(filename, &statbuf) != 0) +			continue; +		list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0); +	} +	closedir(dir); +	return list_get_entry(&udev_queue->failed_list); +} + +int queue_export_udev_seqnum(struct udev_queue *udev_queue, unsigned long long int seqnum) +{ +	return 0; +} + +extern int queue_export_device_queued(struct udev_queue *udev_queue, struct udev_device *udev_device) +{ +	return 0; +} + +extern int queue_export_device_finished(struct udev_queue *udev_queue, struct udev_device *udev_device) +{ +	return 0; +} + +extern int queue_export_device_failed(struct udev_queue *udev_queue, struct udev_device *udev_device) +{ +	return 0; +} diff --git a/udev/lib/libudev.h b/udev/lib/libudev.h index 49d24f1476..cc6939c02f 100644 --- a/udev/lib/libudev.h +++ b/udev/lib/libudev.h @@ -96,8 +96,8 @@ extern struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev  struct udev_enumerate;  extern struct udev_enumerate *udev_enumerate_new(struct udev *udev);  extern struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); -extern struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);  extern void udev_enumerate_unref(struct udev_enumerate *udev_enumerate); +extern struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);  extern int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);  extern int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);  extern int udev_enumerate_add_match_attr(struct udev_enumerate *udev_enumerate, const char *attr, const char *value); @@ -107,4 +107,16 @@ extern int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);  extern int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);  extern struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); +/* event queue */ +struct udev_queue; +extern struct udev_queue *udev_queue_new(struct udev *udev); +extern struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); +extern void udev_queue_unref(struct udev_queue *udev_queue); +extern struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); +extern unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue); +extern unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue); +extern int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); +extern int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum); +extern struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue); +extern struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);  #endif diff --git a/udev/lib/test-libudev.c b/udev/lib/test-libudev.c index 5e9897c715..9c7acb048a 100644 --- a/udev/lib/test-libudev.c +++ b/udev/lib/test-libudev.c @@ -19,6 +19,7 @@  #include <stdio.h>  #include <stdarg.h> +#include <stdlib.h>  #include <unistd.h>  #include <errno.h>  #include <string.h> @@ -168,10 +169,9 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate)  		device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),  						      udev_list_entry_get_name(list_entry));  		if (device != NULL) { -			printf("device:    '%s' (%s) '%s'\n", +			printf("device: '%s' (%s)\n",  			       udev_device_get_syspath(device), -			       udev_device_get_subsystem(device), -			       udev_device_get_sysname(device)); +			       udev_device_get_subsystem(device));  			udev_device_unref(device);  			count++;  		} @@ -230,6 +230,49 @@ static int test_monitor(struct udev *udev, const char *socket_path)  	return 0;  } +static int test_queue(struct udev *udev) +{ +	struct udev_queue *udev_queue; +	unsigned long long int seqnum; +	struct udev_list_entry *list_entry; + +	udev_queue = udev_queue_new(udev); +	if (udev_queue == NULL) +		return -1; +	seqnum = udev_queue_get_kernel_seqnum(udev_queue); +	printf("seqnum kernel: %llu\n", seqnum); +	seqnum = udev_queue_get_udev_seqnum(udev_queue); +	printf("seqnum udev  : %llu\n", seqnum); + +	if (udev_queue_get_queue_is_empty(udev_queue)) +		printf("queue is empty\n"); +	printf("get queue list\n"); +	udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) +		printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); +	printf("\n"); +	printf("get queue list again\n"); +	udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) +		printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); +	printf("\n"); +	printf("get failed list\n"); +	udev_list_entry_foreach(list_entry, udev_queue_get_failed_list_entry(udev_queue)) +		printf("failed: '%s'\n", udev_list_entry_get_name(list_entry)); +	printf("\n"); + +	list_entry = udev_queue_get_queued_list_entry(udev_queue); +	if (list_entry != NULL) { +		printf("event [%llu] is queued\n", seqnum); +		seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10); +		if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum)) +			printf("event [%llu] is not finished\n", seqnum); +		else +			printf("event [%llu] is finished\n", seqnum); +	} +	printf("\n"); +	udev_queue_unref(udev_queue); +	return 0; +} +  int main(int argc, char *argv[], char *envp[])  {  	struct udev *udev = NULL; @@ -351,6 +394,8 @@ int main(int argc, char *argv[], char *envp[])  	test_enumerate_print_list(udev_enumerate);  	udev_enumerate_unref(udev_enumerate); +	test_queue(udev); +  	test_monitor(udev, socket);  out:  	udev_unref(udev); | 
