O2 - 使用libudev获取设备信息(VirtualBox USB设备管理)

来源:互联网 发布:宅男看片app源码 编辑:程序博客网 时间:2024/04/28 16:47

/** udev_get.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>  #include <string.h>#include <pthread.h>#include <sys/stat.h>  #include <sys/epoll.h>#include <sys/utsname.h>#include <libudev.h>#include "udev_get.h"#define DEVDEBUGstatic struct user_devices *listhead = NULL;static struct user_devices *listtail = NULL;static struct user_devices *listread = NULL;static pthread_mutex_t listmutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t atomicmutex = PTHREAD_MUTEX_INITIALIZER;static pthread_t g_pthid;static int monitor_stop = 0;static int initmark = 0;enum devtype {DEVNULL = 0, DEVCHAR = 1, DEVBLK, DEVALL};static int find_devtype(const char *devpath){struct stat devstat;if (NULL == devpath)return DEVNULL;if (stat(devpath, &devstat))return DEVNULL;//printf("%s (%d)\n", devpath, (int)devstat.st_mode);/*必须先检查是否为块文件,根据定义来看,块设备都是字符设备#define__S_IFCHR0020000Character device.0010 0000 0000 0000#define__S_IFBLK0060000Block device.0110 0000 0000 0000*/if (S_IFBLK == (devstat.st_mode & S_IFBLK))return DEVBLK;else if(S_IFCHR == (devstat.st_mode & S_IFCHR))return DEVCHAR;elsereturn DEVALL;}static int device_equal(struct user_devices *dev1, struct user_devices *dev2){if (NULL == dev1 || NULL == dev2) return 0;if (!strcmp(dev1->serial, dev2->serial)) return 1;if (dev1->vendor_id[0] && dev2->vendor_id[0] && dev1->model_id[0] && dev2->model_id[0])if(!strcmp(dev1->vendor_id, dev2->vendor_id) && !strcmp(dev1->model_id, dev2->model_id))return 1;return 0;}static struct user_devices *list_find_dev_serial(struct user_devices *aimdev){pthread_mutex_lock(&listmutex);struct user_devices *retval = NULL;if (NULL == listhead || NULL == aimdev) goto out;struct user_devices *pdev = listhead;while(NULL != pdev) {if (device_equal(pdev, aimdev)) {retval = pdev;goto out;} elsepdev = pdev->next;}out:pthread_mutex_unlock(&listmutex);return retval;}static void insert_devnum(struct user_devices *in, struct user_devices *val){int i;for(i = 0; i < in->subdev_cnt; i++) {if (in->sdev[i].major == val->sdev[0].major && in->sdev[i].minor == val->sdev[0].minor)break;}if (i == in->subdev_cnt) {snprintf(in->sdev[i].syspath, sizeof(in->sdev[0].syspath), "%s", val->sdev[0].syspath);snprintf(in->sdev[i].devname, sizeof(in->sdev[0].devname), "%s", val->sdev[0].devname);in->sdev[i].major = val->sdev[0].major;in->sdev[i].minor = val->sdev[0].minor;in->subdev_cnt += 1;}}static void list_ergodic_dev(){pthread_mutex_lock(&listmutex);struct user_devices *pdev = listhead;while(pdev != NULL) {printf("serial = %s\tsubdevcnt = %d\n", pdev->serial, pdev->subdev_cnt);pdev = pdev->next;}pthread_mutex_unlock(&listmutex);}static int list_add_dev(struct user_devices *pdev){pthread_mutex_lock(&listmutex);if (NULL == listhead || NULL == listtail) {listhead = listtail = pdev;goto out;}struct user_devices *p = listhead;struct user_devices *past = NULL;while (p != NULL) {if (device_equal(pdev, p)) {insert_devnum(p, pdev);free(pdev);goto out;}past = p;p = p->next;}/* add a new user_devices to the listtail */past->next = pdev;listtail = pdev;pdev->next = NULL;out:pthread_mutex_unlock(&listmutex);return 0;}static int list_del_dev(struct user_devices *pdev){pthread_mutex_lock(&listmutex);if (NULL == listhead || NULL == listtail)goto out;struct user_devices *cur = listhead, *past = NULL;while (cur != NULL) {if (device_equal(pdev, cur)) {if (cur == listread)listread = listread->next;if (listhead == cur)listhead = cur->next;else {if (listtail == cur) {listtail = past;past->next = NULL;} else {past->next = cur->next;}}free(cur);goto out;}past = cur;cur = cur->next;}out:free(pdev);pthread_mutex_unlock(&listmutex);return 0;}static void list_clear_dev(){pthread_mutex_lock(&atomicmutex);pthread_mutex_lock(&listmutex);struct user_devices *p = listhead;while(NULL != p) {struct user_devices *tmp = p;p = p->next;free(tmp);}listhead = listtail = listread = NULL;pthread_mutex_unlock(&listmutex);pthread_mutex_unlock(&atomicmutex);}static int list_node_cp(struct user_devices *dst, struct user_devices *src){if (NULL == src || NULL == dst) return 1;memcpy(dst, src, sizeof(struct user_devices));dst->next = NULL;return 0;}static struct user_devices *get_user_device(struct udev_device *device) {dev_t devnum;char *str;const char *serial, *serialshort, *vendor, *model, *revision, *bus, *syspath, *devname;struct utsname unamex;char prefixseri[128] = {0};devnum = udev_device_get_devnum(device);if (major(devnum) <= 0) goto errout;serial = udev_device_get_property_value(device, "ID_SERIAL");if (!serial) {serial = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE");if (!serial) goto errout;}serialshort = udev_device_get_property_value(device, "ID_SERIAL_SHORT");if (serialshort) {if (NULL != (str = strstr(serial, serialshort)))str[-1] = '\0';}uname(&unamex);snprintf(prefixseri, sizeof(prefixseri), "Linux_%s", unamex.release);if (!strncmp(serial, prefixseri, strlen(prefixseri))) goto errout;struct user_devices *tmpdev = NULL;tmpdev = (struct user_devices *)calloc(1, sizeof(struct user_devices));if (NULL == tmpdev) goto errout;snprintf(tmpdev->serial, sizeof(tmpdev->serial), "%s", serial);vendor = udev_device_get_property_value(device, "ID_VENDOR_ID");if (vendor)snprintf(tmpdev->vendor_id, sizeof(tmpdev->vendor_id), "%s", vendor);model = udev_device_get_property_value(device, "ID_MODEL_ID");if (model)snprintf(tmpdev->model_id, sizeof(tmpdev->model_id), "%s", model);revision = udev_device_get_property_value(device, "ID_REVISION");if (revision)snprintf(tmpdev->revision, sizeof(tmpdev->revision), "%s", revision);bus = udev_device_get_property_value(device, "ID_BUS");if (bus)snprintf(tmpdev->bus, sizeof(tmpdev->bus), "%s", bus);int loop;for (loop = 0; loop < tmpdev->subdev_cnt; loop ++) {if (tmpdev->sdev[loop].major == major(devnum)&& tmpdev->sdev[loop].minor == minor(devnum))return tmpdev;}syspath = udev_device_get_syspath(device);if (syspath)snprintf(tmpdev->sdev[tmpdev->subdev_cnt].syspath, sizeof(tmpdev->sdev[0].syspath), "%s", syspath);devname = udev_device_get_devnode(device);if (devname) {snprintf(tmpdev->sdev[tmpdev->subdev_cnt].devname, sizeof(tmpdev->sdev[0].devname), "%s", devname);tmpdev->sdev[tmpdev->subdev_cnt].type = find_devtype(devname);}tmpdev->sdev[tmpdev->subdev_cnt].major = major(devnum);tmpdev->sdev[tmpdev->subdev_cnt].minor = minor(devnum);tmpdev->subdev_cnt += 1;return tmpdev;errout:return NULL;}static int enumerate_devices(const char *subsystem) {struct udev *udev = NULL;struct udev_enumerate *udev_enumerate = NULL;struct udev_list_entry *list_entry;udev = udev_new();if (udev == NULL)return 1;udev_enumerate = udev_enumerate_new(udev);if (udev_enumerate == NULL)return -1;udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);udev_enumerate_scan_devices(udev_enumerate);udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {struct udev_device *device;device = udev_device_new_from_syspath(udev_enumerate_get_udev(udev_enumerate),  udev_list_entry_get_name(list_entry));if (device != NULL) {pthread_mutex_lock(&atomicmutex);struct user_devices *d = get_user_device(device);if (d)list_add_dev(d);pthread_mutex_unlock(&atomicmutex);udev_device_unref(device);}}udev_enumerate_unref(udev_enumerate);udev_unref(udev);return 0;}static void *devices_monitor(void *param) {struct udev *udev = NULL;udev = udev_new();struct udev_monitor *mon = NULL;int fd;mon = udev_monitor_new_from_netlink(udev, "udev");udev_monitor_enable_receiving(mon);fd = udev_monitor_get_fd(mon);while (!monitor_stop) {fd_set fds;struct timeval tv;int ret;FD_ZERO(&fds);FD_SET(fd, &fds);tv.tv_sec = 0;tv.tv_usec = 1000 * 100;/* select timeout : 100ms */ret = select(fd+1, &fds, NULL, NULL, &tv);/* Check if our file descriptor has received data. */if (ret > 0 && FD_ISSET(fd, &fds)) {struct udev_device *dev;dev = udev_monitor_receive_device(mon);if (dev) {const char *str = udev_device_get_action(dev);if (str != NULL) {if (!strcmp(str, "remove")) {pthread_mutex_lock(&atomicmutex);struct user_devices *p = get_user_device(dev);if (p) list_del_dev(p);pthread_mutex_unlock(&atomicmutex);} else if (!strcmp(str, "add")) {pthread_mutex_lock(&atomicmutex);struct user_devices *p = get_user_device(dev);if (p) list_add_dev(p);pthread_mutex_unlock(&atomicmutex);}}udev_device_unref(dev);}}}udev_monitor_unref(mon);udev_unref(udev);return NULL;}void udev_init(){if (initmark) return;initmark = 1;listhead = NULL;listtail = NULL;listread = NULL;monitor_stop = 0;pthread_create(&g_pthid, NULL, devices_monitor, NULL);}void udev_uninit(){monitor_stop = 1;initmark = 0;pthread_join(g_pthid, NULL);list_clear_dev();}int udev_get_dev(struct user_devices *pdev){int retval = 1;if (NULL == listhead)enumerate_devices(NULL);pthread_mutex_lock(&listmutex);if (NULL == pdev) goto out;listread = listhead;if (NULL == listread)goto out;if (!list_node_cp(pdev, listread)) {listread = listread->next;retval = 0;}out:pthread_mutex_unlock(&listmutex);return retval;}int udev_get_nextdev(struct user_devices *pdev){int retval = 1;pthread_mutex_lock(&listmutex);if (NULL == pdev || NULL == listread) goto out;if (!list_node_cp(pdev, listread)) {listread = listread->next;retval = 0;goto out;}out:pthread_mutex_unlock(&listmutex);return retval;}#ifdef DEVDEBUGvoid printdev(struct user_devices *dev){int i;printf("serial = %s\n", dev->serial);printf("vendor_id = %s\n", dev->vendor_id);printf("model_id = %s\n", dev->model_id);printf("revision = %s\n", dev->revision);printf("bus = %s\n", dev->bus);for (i = 0; i < dev->subdev_cnt; i++) {printf("syspath = %s\n", dev->sdev[i].syspath);printf("devname = %s\n", dev->sdev[i].devname);printf("devnum = (%d:%d) (%d)\n", dev->sdev[i].major, dev->sdev[i].minor, dev->sdev[i].type);}printf("\n");}/* gcc udev_get.c -o udev_get -g -Wall -ludev -lpthread */int main(int argc, char *argv[]) {int glob = 0;while (1) {udev_init();struct user_devices dev;int loop = 100;while (--loop) {if (!udev_get_dev(&dev))printdev(&dev);while(!udev_get_nextdev(&dev))printdev(&dev);list_clear_dev();usleep(1000 * 1);printf("############ ((%d))\n\n", ++glob);}udev_uninit();}return 0;}#endif

/** udev_get.h */#ifndef UDEV_GET_H#define UDEV_GET_Hstruct subdev {char syspath[256];/* /sys目录下的路径 */char devname[128];/* /dev目录下的路径 */int major;/* 主设备号 */int minor;/* 次设备号 */int type;/* 设备类型, 1表示字符设备,2表示块设备,其他值表示其他类型设备 */};struct user_devices {char serial[256];/* 序列号,即设备的名字 */char vendor_id[8];/* 产商ID */char model_id[8];/* 模块ID */char revision[32];/* 版本ID */char bus[32];/* 总线类型 */int subdev_cnt;struct subdev sdev[32];struct user_devices *next;/* NULL */};/* udev_init* description:调用其他接口前调用该函数进行初始化* param:无* return:无*/void udev_init();/* udev_uninit* description:不再调用其他接口后,调用该函数进行反初始化* param:无* return:无*/void udev_uninit();/* udev_get_dev* description:遍历所有设备,先调用该函数,再调用udev_get_nextdev函数获取剩余的设备* param:用户传入结构体指针用来存储获取的设备信息* return:0表示正常,其他值表示错误*/int udev_get_dev(struct user_devices *pdev);/* udev_get_nextdev* description:遍历所有设备,在调用udev_get_dev后调用该函数* param:用户传入结构体指针用来存储获取的设备信息* return:0表示正常,其他值表示错误*/int udev_get_nextdev(struct user_devices *pdev);#endif

#Makefileudev:udev_get.ogcc udev_get.c -o udev -g -Wall -Wunused-function -ludev -lpthreadclean:rm -rf udev_get.o udev



参考文档:http://www.signal11.us/oss/udev/

udev_example.c

参考代码:systemd-221/src/test/test-libudev.c

0 0
原创粉丝点击