现在关注的是libudev的枚举已连接的设备
2. 枚举设备
使用udev_enumrate_new创建一个枚举器,用于扫描系统已接设备。使用udev_enumrate_ref和udev_enumrate_unref增加或减少引用记数。
使用udev_enumrate_add_match/nomatch_xxx系列函数增加枚举的过滤器,过滤关键字以字符表示,如"block"设备。
使用udev_enumrate_scan_xxx系列函数扫描/sys目录下,所有与过滤器匹配的设备。扫描完成后的数据结构是一个链表,使用udev_enumerate_get_list_entry获取链表的首个结点,使用udev_list_entry_foreach遍历整个链表。
代码浅析开始,第一层。
首先这段摘抄的话,不知道分析的是什么版本的。我现在要分析的是udev-175版本,在其目录下的libudev目录即为libudev源代码所在目录。应该是udev_enumerate_new,应该是他粗心写错了。
一般的过程:
enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_property(enumerate, "ID_PATH", id_path);
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_scan_devices(enumerate);
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
struct udev_device *device;
const char *node;
device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
udev_list_entry_get_name(list_entry));
.......
.......
}
1. udev_enumerate_new [libudev-enumerate.c]
/**
* udev_enumerate_new:
* @udev: udev library context
*
* Returns: an enumeration context
**/
UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev)
{
struct udev_enumerate *udev_enumerate;
udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
if (udev_enumerate == NULL)
return NULL;
udev_enumerate->refcount = 1;
udev_enumerate->udev = udev;
udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
udev_list_init(udev, &udev_enumerate->properties_match_list, false);
udev_list_init(udev, &udev_enumerate->tags_match_list, true);
udev_list_init(udev, &udev_enumerate->devices_list, false);
return udev_enumerate;
}
要枚举,就要保存东西,有很多个,需要个list。申请一个枚举结构体,并做list的初始化。
2. udev_enumerate_add_match_property [libudev-enumerate.c]
/**
* udev_enumerate_add_match_property:
* @udev_enumerate: context
* @property: filter for a property of the device to include in the list
* @value: value of the property
*
* Returns: 0 on success, otherwise a negative error value.
*/
UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
{
if (udev_enumerate == NULL)
return -EINVAL;
if (property == NULL)
return 0;
if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
return -ENOMEM;
return 0;
}
将匹配的properties添加到list中
3. udev_enumerate_add_match_subsystem [libudev-enumerate.c]
/**
* udev_enumerate_add_match_subsystem:
* @udev_enumerate: context
* @subsystem: filter for a subsystem of the device to include in the list
*
* Returns: 0 on success, otherwise a negative error value.
*/
UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
{
if (udev_enumerate == NULL)
return -EINVAL;
if (subsystem == NULL)
return 0;
if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
return -ENOMEM;
return 0;
}
将匹配的subsystem添加到list中
4. udev_enumerate_scan_devices [libudev-enumerate.c]
/**
* udev_enumerate_scan_devices:
* @udev_enumerate: udev enumeration context
*
* Returns: 0 on success, otherwise a negative error value.
**/
UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
{
if (udev_enumerate == NULL)
return -EINVAL;
/* efficiently lookup tags only, we maintain a reverse-index */
if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
return scan_devices_tags(udev_enumerate);
/* walk the subtree of one parent device only */
if (udev_enumerate->parent_match != NULL)
return scan_devices_children(udev_enumerate);
/* scan devices of all subsystems */
return scan_devices_all(udev_enumerate);
}
有四个return,第一个不必说了,后面三个,一般会执行哪一个呢?
需要重点分析
5. udev_enumerate_get_udev [libudev-enumerate.c]
/**
* udev_enumerate_get_udev:
* @udev_enumerate: context
*
* Returns: the udev library context.
*/
UDEV_EXPORT struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
{
if (udev_enumerate == NULL)
return NULL;
return udev_enumerate->udev;
}
这个比较好看,后面深入分析时一眼可以看出来了。udev_enumerate_get_udev,
即 get udev of udev_enumerate,get udev_enumerate->udev
6. udev_device_new_from_syspath [libudev-device.c]
/**
* udev_device_new_from_syspath:
* @udev: udev library context
* @syspath: sys device path including sys directory
*
* Create new udev device, and fill in information from the sys
* device and the udev database entry. The syspath is the absolute
* path to the device, including the sys mount point.
*
* The initial refcount is 1, and needs to be decremented to
* release the resources of the udev device.
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
{
size_t len;
const char *subdir;
char path[UTIL_PATH_SIZE];
char *pos;
struct stat statbuf;
struct udev_device *udev_device;
if (udev == NULL)
return NULL;
if (syspath == NULL)
return NULL;
/* path starts in sys */
len = strlen(udev_get_sys_path(udev));
if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
info(udev, "not in sys :%s\n", syspath);
return NULL;
}
/* path is not a root directory */
subdir = &syspath[len+1];
pos = strrchr(subdir, '/');
if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
dbg(udev, "not a subdir :%s\n", syspath);
return NULL;
}
/* resolve possible symlink to real path */
util_strscpy(path, sizeof(path), syspath);
util_resolve_sys_link(udev, path, sizeof(path));
if (strncmp(&path[len], "/devices/", 9) == 0) {
char file[UTIL_PATH_SIZE];
/* all "devices" require a "uevent" file */
util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
if (stat(file, &statbuf) != 0) {
dbg(udev, "not a device: %s\n", syspath);
return NULL;
}
} else {
/* everything else just needs to be a directory */
if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
dbg(udev, "directory not found: %s\n", syspath);
return NULL;
}
}
udev_device = udev_device_new(udev);
if (udev_device == NULL)
return NULL;
udev_device_set_syspath(udev_device, path);
info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
return udev_device;
}
需要重点分析
接下来会分析两个需要重点分析的函数。第一层就是个流程,看着比较连贯的。后面的分析就比较分散了。