mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
add TAG= to improve event filtering and device enumeration
This commit is contained in:
parent
e7964b93e8
commit
28460195c2
@ -28,9 +28,9 @@ CLEANFILES =
|
||||
# ------------------------------------------------------------------------------
|
||||
# libudev
|
||||
# ------------------------------------------------------------------------------
|
||||
LIBUDEV_CURRENT=7
|
||||
LIBUDEV_CURRENT=8
|
||||
LIBUDEV_REVISION=0
|
||||
LIBUDEV_AGE=7
|
||||
LIBUDEV_AGE=8
|
||||
|
||||
SUBDIRS += libudev/docs
|
||||
|
||||
|
@ -68,6 +68,7 @@ udev_monitor_enable_receiving
|
||||
udev_monitor_get_fd
|
||||
udev_monitor_receive_device
|
||||
udev_monitor_filter_add_match_subsystem_devtype
|
||||
udev_monitor_filter_add_match_tag
|
||||
udev_monitor_filter_update
|
||||
udev_monitor_filter_remove
|
||||
</SECTION>
|
||||
@ -85,6 +86,7 @@ udev_enumerate_add_nomatch_subsystem
|
||||
udev_enumerate_add_match_sysattr
|
||||
udev_enumerate_add_nomatch_sysattr
|
||||
udev_enumerate_add_match_property
|
||||
udev_enumerate_add_match_tag
|
||||
udev_enumerate_add_match_sysname
|
||||
udev_enumerate_add_syspath
|
||||
udev_enumerate_scan_devices
|
||||
|
@ -60,6 +60,7 @@ udev_monitor_get_udev
|
||||
udev_monitor_get_fd
|
||||
udev_monitor_receive_device
|
||||
udev_monitor_filter_add_match_subsystem_devtype
|
||||
udev_monitor_filter_add_match_tag
|
||||
udev_monitor_filter_update
|
||||
udev_monitor_filter_remove
|
||||
udev_queue_new
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libudev - interface to udev device information
|
||||
*
|
||||
* Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
|
||||
* Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -13,6 +13,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
@ -21,6 +22,37 @@
|
||||
#include "libudev.h"
|
||||
#include "libudev-private.h"
|
||||
|
||||
static int udev_device_tag_index(struct udev_device *udev_device, bool add)
|
||||
{
|
||||
struct udev *udev = udev_device_get_udev(udev_device);
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) {
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/tags/",
|
||||
udev_list_entry_get_name(list_entry), "/",
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
|
||||
|
||||
if (add) {
|
||||
util_create_path(udev, filename);
|
||||
symlink(udev_device_get_devpath(udev_device), filename);
|
||||
if (udev_device_get_sysname_old(udev_device) != NULL) {
|
||||
char filename_old[UTIL_PATH_SIZE];
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/tags/",
|
||||
udev_list_entry_get_name(list_entry),
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname_old(udev_device), NULL);
|
||||
unlink(filename_old);
|
||||
}
|
||||
} else {
|
||||
unlink(filename);
|
||||
util_delete_path(udev, filename);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_device_update_db(struct udev_device *udev_device)
|
||||
{
|
||||
struct udev *udev = udev_device_get_udev(udev_device);
|
||||
@ -41,6 +73,8 @@ int udev_device_update_db(struct udev_device *udev_device)
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
|
||||
if (udev_list_entry_get_flags(list_entry))
|
||||
goto file;
|
||||
if (udev_device_get_tags_list_entry(udev_device) != NULL)
|
||||
goto file;
|
||||
if (udev_device_get_devlink_priority(udev_device) != 0)
|
||||
goto file;
|
||||
if (udev_device_get_event_timeout(udev_device) >= 0)
|
||||
@ -80,7 +114,7 @@ file:
|
||||
if (f == NULL) {
|
||||
err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (udev_device_get_devnode(udev_device) != NULL) {
|
||||
fprintf(f, "N:%s\n", &udev_device_get_devnode(udev_device)[devlen]);
|
||||
@ -100,10 +134,13 @@ file:
|
||||
udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry));
|
||||
}
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
|
||||
fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry));
|
||||
fclose(f);
|
||||
rename(filename_tmp, filename);
|
||||
info(udev, "created db file for '%s' in '%s'\n", udev_device_get_devpath(udev_device), filename);
|
||||
out:
|
||||
udev_device_tag_index(udev_device, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -112,6 +149,7 @@ int udev_device_delete_db(struct udev_device *udev_device)
|
||||
struct udev *udev = udev_device_get_udev(udev_device);
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
udev_device_tag_index(udev_device, false);
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
|
||||
unlink(filename);
|
||||
@ -124,9 +162,13 @@ int udev_device_rename_db(struct udev_device *udev_device)
|
||||
char filename_old[UTIL_PATH_SIZE];
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
if (strcmp(udev_device_get_sysname(udev_device), udev_device_get_sysname_old(udev_device)) == 0)
|
||||
return 0;
|
||||
|
||||
util_strscpyl(filename_old, sizeof(filename_old), udev_get_dev_path(udev), "/.udev/db/",
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname_old(udev_device), NULL);
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
|
||||
udev_device_tag_index(udev_device, true);
|
||||
return rename(filename_old, filename);
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ struct udev_device {
|
||||
struct udev_list_node devlinks_list;
|
||||
struct udev_list_node properties_list;
|
||||
struct udev_list_node sysattr_list;
|
||||
struct udev_list_node tags_list;
|
||||
unsigned long long int seqnum;
|
||||
int event_timeout;
|
||||
int timeout;
|
||||
@ -68,18 +69,21 @@ struct udev_device {
|
||||
dev_t devnum;
|
||||
int watch_handle;
|
||||
int maj, min;
|
||||
unsigned int parent_set:1;
|
||||
unsigned int subsystem_set:1;
|
||||
unsigned int devtype_set:1;
|
||||
unsigned int devlinks_uptodate:1;
|
||||
unsigned int envp_uptodate:1;
|
||||
unsigned int driver_set:1;
|
||||
unsigned int info_loaded:1;
|
||||
bool parent_set;
|
||||
bool subsystem_set;
|
||||
bool devtype_set;
|
||||
bool devlinks_uptodate;
|
||||
bool envp_uptodate;
|
||||
bool tags_uptodate;
|
||||
bool driver_set;
|
||||
bool info_loaded;
|
||||
bool db_loaded;
|
||||
bool uevent_loaded;
|
||||
};
|
||||
|
||||
struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
|
||||
{
|
||||
udev_device->envp_uptodate = 0;
|
||||
udev_device->envp_uptodate = false;
|
||||
if (value == NULL) {
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
@ -149,6 +153,26 @@ void udev_device_add_property_from_string_parse(struct udev_device *udev_device,
|
||||
}
|
||||
if (slink[0] != '\0')
|
||||
udev_device_add_devlink(udev_device, slink, 0);
|
||||
} else if (strncmp(property, "TAGS=", 5) == 0) {
|
||||
char tags[UTIL_PATH_SIZE];
|
||||
char *next;
|
||||
|
||||
util_strscpy(tags, sizeof(tags), &property[5]);
|
||||
next = strchr(tags, ':');
|
||||
if (next != NULL) {
|
||||
next++;
|
||||
while (next[0] != '\0') {
|
||||
char *tag;
|
||||
|
||||
tag = next;
|
||||
next = strchr(tag, ':');
|
||||
if (next == NULL)
|
||||
break;
|
||||
next[0] = '\0';
|
||||
next++;
|
||||
udev_device_add_tag(udev_device, tag);
|
||||
}
|
||||
}
|
||||
} else if (strncmp(property, "DRIVER=", 7) == 0) {
|
||||
udev_device_set_driver(udev_device, &property[7]);
|
||||
} else if (strncmp(property, "ACTION=", 7) == 0) {
|
||||
@ -208,6 +232,9 @@ int udev_device_read_db(struct udev_device *udev_device)
|
||||
char line[UTIL_LINE_SIZE];
|
||||
FILE *f;
|
||||
|
||||
if (udev_device->db_loaded)
|
||||
return 0;
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/",
|
||||
udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
|
||||
|
||||
@ -284,6 +311,9 @@ int udev_device_read_db(struct udev_device *udev_device)
|
||||
case 'E':
|
||||
udev_device_add_property_from_string(udev_device, val);
|
||||
break;
|
||||
case 'G':
|
||||
udev_device_add_tag(udev_device, val);
|
||||
break;
|
||||
case 'W':
|
||||
udev_device_set_watch_handle(udev_device, atoi(val));
|
||||
break;
|
||||
@ -292,6 +322,7 @@ int udev_device_read_db(struct udev_device *udev_device)
|
||||
fclose(f);
|
||||
|
||||
info(udev_device->udev, "device %p filled with db file data\n", udev_device);
|
||||
udev_device->db_loaded = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -303,6 +334,9 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
|
||||
int maj = 0;
|
||||
int min = 0;
|
||||
|
||||
if (udev_device->uevent_loaded)
|
||||
return 0;
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
@ -329,21 +363,14 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
|
||||
}
|
||||
|
||||
udev_device->devnum = makedev(maj, min);
|
||||
|
||||
fclose(f);
|
||||
udev_device->uevent_loaded = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_load_info(struct udev_device *device)
|
||||
{
|
||||
device->info_loaded = 1;
|
||||
udev_device_read_uevent_file(device);
|
||||
udev_device_read_db(device);
|
||||
}
|
||||
|
||||
void udev_device_set_info_loaded(struct udev_device *device)
|
||||
{
|
||||
device->info_loaded = 1;
|
||||
device->info_loaded = true;
|
||||
}
|
||||
|
||||
struct udev_device *udev_device_new(struct udev *udev)
|
||||
@ -362,6 +389,7 @@ struct udev_device *udev_device_new(struct udev *udev)
|
||||
udev_list_init(&udev_device->devlinks_list);
|
||||
udev_list_init(&udev_device->properties_list);
|
||||
udev_list_init(&udev_device->sysattr_list);
|
||||
udev_list_init(&udev_device->tags_list);
|
||||
udev_device->event_timeout = -1;
|
||||
udev_device->watch_handle = -1;
|
||||
/* copy global properties */
|
||||
@ -420,7 +448,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
|
||||
util_strscpy(path, sizeof(path), syspath);
|
||||
util_resolve_sys_link(udev, path, sizeof(path));
|
||||
|
||||
if (strncmp(&syspath[len], "/devices/", 9) == 0) {
|
||||
if (strncmp(&path[len], "/devices/", 9) == 0) {
|
||||
char file[UTIL_PATH_SIZE];
|
||||
|
||||
/* all "devices" require a "uevent" file */
|
||||
@ -648,7 +676,7 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->parent_set) {
|
||||
udev_device->parent_set = 1;
|
||||
udev_device->parent_set = true;
|
||||
udev_device->parent_device = device_new_from_parent(udev_device);
|
||||
}
|
||||
if (udev_device->parent_device != NULL)
|
||||
@ -758,12 +786,13 @@ void udev_device_unref(struct udev_device *udev_device)
|
||||
free(udev_device->devtype);
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list);
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list);
|
||||
free(udev_device->action);
|
||||
free(udev_device->driver);
|
||||
free(udev_device->devpath_old);
|
||||
free(udev_device->sysname_old);
|
||||
free(udev_device->knodename);
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
|
||||
free(udev_device->envp);
|
||||
free(udev_device->monitor_buf);
|
||||
dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
|
||||
@ -842,7 +871,7 @@ const char *udev_device_get_devnode(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
return udev_device->devnode;
|
||||
}
|
||||
|
||||
@ -862,7 +891,7 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->subsystem_set) {
|
||||
udev_device->subsystem_set = 1;
|
||||
udev_device->subsystem_set = true;
|
||||
/* read "subsystem" link */
|
||||
if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
|
||||
udev_device_set_subsystem(udev_device, subsystem);
|
||||
@ -900,9 +929,8 @@ const char *udev_device_get_devtype(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->devtype_set) {
|
||||
udev_device->devtype_set = 1;
|
||||
if (!udev_device->info_loaded)
|
||||
udev_device_read_uevent_file(udev_device);
|
||||
udev_device->devtype_set = true;
|
||||
udev_device_read_uevent_file(udev_device);
|
||||
}
|
||||
return udev_device->devtype;
|
||||
}
|
||||
@ -925,13 +953,13 @@ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
return udev_list_get_entry(&udev_device->devlinks_list);
|
||||
}
|
||||
|
||||
void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
|
||||
{
|
||||
udev_device->devlinks_uptodate = 0;
|
||||
udev_device->devlinks_uptodate = false;
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
|
||||
}
|
||||
|
||||
@ -951,13 +979,15 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
|
||||
{
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
if (!udev_device->info_loaded) {
|
||||
udev_device_read_uevent_file(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
}
|
||||
if (!udev_device->devlinks_uptodate) {
|
||||
char symlinks[UTIL_PATH_SIZE];
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_device->devlinks_uptodate = 1;
|
||||
udev_device->devlinks_uptodate = true;
|
||||
list_entry = udev_device_get_devlinks_list_entry(udev_device);
|
||||
if (list_entry != NULL) {
|
||||
char *s;
|
||||
@ -970,6 +1000,21 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
|
||||
udev_device_add_property(udev_device, "DEVLINKS", symlinks);
|
||||
}
|
||||
}
|
||||
if (!udev_device->tags_uptodate) {
|
||||
udev_device->tags_uptodate = true;
|
||||
if (udev_device_get_tags_list_entry(udev_device) != NULL) {
|
||||
char tags[UTIL_PATH_SIZE];
|
||||
struct udev_list_entry *list_entry;
|
||||
char *s;
|
||||
size_t l;
|
||||
|
||||
s = tags;
|
||||
l = util_strpcpyl(&s, sizeof(tags), ":", NULL);
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
|
||||
l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
|
||||
udev_device_add_property(udev_device, "TAGS", tags);
|
||||
}
|
||||
}
|
||||
return udev_list_get_entry(&udev_device->properties_list);
|
||||
}
|
||||
|
||||
@ -986,7 +1031,7 @@ const char *udev_device_get_driver(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
if (!udev_device->driver_set) {
|
||||
udev_device->driver_set = 1;
|
||||
udev_device->driver_set = true;
|
||||
if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0)
|
||||
udev_device->driver = strdup(driver);
|
||||
}
|
||||
@ -1004,7 +1049,7 @@ dev_t udev_device_get_devnum(struct udev_device *udev_device)
|
||||
if (udev_device == NULL)
|
||||
return makedev(0, 0);
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_uevent_file(udev_device);
|
||||
return udev_device->devnum;
|
||||
}
|
||||
|
||||
@ -1184,7 +1229,7 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy
|
||||
udev_device->subsystem = strdup(subsystem);
|
||||
if (udev_device->subsystem == NULL)
|
||||
return -ENOMEM;
|
||||
udev_device->subsystem_set = 1;
|
||||
udev_device->subsystem_set = true;
|
||||
udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
|
||||
return 0;
|
||||
}
|
||||
@ -1195,7 +1240,7 @@ int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype
|
||||
udev_device->devtype = strdup(devtype);
|
||||
if (udev_device->devtype == NULL)
|
||||
return -ENOMEM;
|
||||
udev_device->devtype_set = 1;
|
||||
udev_device->devtype_set = true;
|
||||
udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
|
||||
return 0;
|
||||
}
|
||||
@ -1216,7 +1261,7 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_device->devlinks_uptodate = 0;
|
||||
udev_device->devlinks_uptodate = false;
|
||||
list_entry = udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0);
|
||||
if (list_entry == NULL)
|
||||
return -ENOMEM;
|
||||
@ -1225,6 +1270,40 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
|
||||
{
|
||||
if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL)
|
||||
return -EINVAL;
|
||||
udev_device->tags_uptodate = false;
|
||||
if (udev_list_entry_add(udev_device->udev, &udev_device->tags_list, tag, NULL, 1, 0) != NULL)
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void udev_device_cleanup_tags_list(struct udev_device *udev_device)
|
||||
{
|
||||
udev_device->tags_uptodate = false;
|
||||
udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list);
|
||||
}
|
||||
|
||||
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
|
||||
{
|
||||
return udev_list_get_entry(&udev_device->tags_list);
|
||||
}
|
||||
|
||||
int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (!udev_device->info_loaded)
|
||||
udev_device_read_db(udev_device);
|
||||
list_entry = udev_device_get_tags_list_entry(udev_device);
|
||||
list_entry = udev_list_entry_get_by_name(list_entry, tag);
|
||||
if (list_entry != NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENVP_SIZE 128
|
||||
#define MONITOR_BUF_SIZE 4096
|
||||
static int update_envp_monitor_buf(struct udev_device *udev_device)
|
||||
@ -1273,7 +1352,7 @@ static int update_envp_monitor_buf(struct udev_device *udev_device)
|
||||
}
|
||||
udev_device->envp[i] = NULL;
|
||||
udev_device->monitor_buf_len = s - udev_device->monitor_buf;
|
||||
udev_device->envp_uptodate = 1;
|
||||
udev_device->envp_uptodate = true;
|
||||
dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
|
||||
i, udev_device->monitor_buf_len);
|
||||
return 0;
|
||||
@ -1312,7 +1391,7 @@ int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
|
||||
udev_device->driver = strdup(driver);
|
||||
if (udev_device->driver == NULL)
|
||||
return -ENOMEM;
|
||||
udev_device->driver_set = 1;
|
||||
udev_device->driver_set = true;
|
||||
udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
|
||||
return 0;
|
||||
}
|
||||
@ -1385,7 +1464,7 @@ int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
|
||||
int udev_device_get_event_timeout(struct udev_device *udev_device)
|
||||
{
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
return udev_device->event_timeout;
|
||||
}
|
||||
|
||||
@ -1421,7 +1500,7 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
|
||||
int udev_device_get_devlink_priority(struct udev_device *udev_device)
|
||||
{
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
return udev_device->devlink_priority;
|
||||
}
|
||||
|
||||
@ -1434,7 +1513,7 @@ int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
|
||||
int udev_device_get_watch_handle(struct udev_device *udev_device)
|
||||
{
|
||||
if (!udev_device->info_loaded)
|
||||
device_load_info(udev_device);
|
||||
udev_device_read_db(udev_device);
|
||||
return udev_device->watch_handle;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libudev - interface to udev device information
|
||||
*
|
||||
* Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
|
||||
* Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -51,6 +51,7 @@ struct udev_enumerate {
|
||||
struct udev_list_node subsystem_nomatch_list;
|
||||
struct udev_list_node sysname_match_list;
|
||||
struct udev_list_node properties_match_list;
|
||||
struct udev_list_node tags_match_list;
|
||||
struct udev_list_node devices_list;
|
||||
struct syspath *devices;
|
||||
unsigned int devices_cur;
|
||||
@ -79,6 +80,7 @@ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
|
||||
udev_list_init(&udev_enumerate->subsystem_nomatch_list);
|
||||
udev_list_init(&udev_enumerate->sysname_match_list);
|
||||
udev_list_init(&udev_enumerate->properties_match_list);
|
||||
udev_list_init(&udev_enumerate->tags_match_list);
|
||||
udev_list_init(&udev_enumerate->devices_list);
|
||||
return udev_enumerate;
|
||||
}
|
||||
@ -121,6 +123,7 @@ void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
|
||||
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_nomatch_list);
|
||||
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysname_match_list);
|
||||
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->properties_match_list);
|
||||
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->tags_match_list);
|
||||
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
|
||||
for (i = 0; i < udev_enumerate->devices_cur; i++)
|
||||
free(udev_enumerate->devices[i].syspath);
|
||||
@ -191,7 +194,7 @@ static int syspath_cmp(const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
/* For devices that should be moved to the absolute end of the list */
|
||||
static int devices_delay_end(struct udev *udev, const char *syspath)
|
||||
static bool devices_delay_end(struct udev *udev, const char *syspath)
|
||||
{
|
||||
static const char *delay_device_list[] = {
|
||||
"/block/md",
|
||||
@ -205,10 +208,10 @@ static int devices_delay_end(struct udev *udev, const char *syspath)
|
||||
for (i = 0; delay_device_list[i] != NULL; i++) {
|
||||
if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
|
||||
dbg(udev, "delaying: %s\n", syspath);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For devices that should just be moved a little bit later, just
|
||||
@ -394,16 +397,12 @@ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, co
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_sysattr_value(struct udev *udev, const char *syspath, const char *sysattr, const char *match_val)
|
||||
static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
|
||||
{
|
||||
struct udev_device *device;
|
||||
const char *val = NULL;
|
||||
bool match = false;
|
||||
|
||||
device = udev_device_new_from_syspath(udev, syspath);
|
||||
if (device == NULL)
|
||||
return -EINVAL;
|
||||
val = udev_device_get_sysattr_value(device, sysattr);
|
||||
val = udev_device_get_sysattr_value(dev, sysattr);
|
||||
if (val == NULL)
|
||||
goto exit;
|
||||
if (match_val == NULL) {
|
||||
@ -415,7 +414,6 @@ static int match_sysattr_value(struct udev *udev, const char *syspath, const cha
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
udev_device_unref(device);
|
||||
return match;
|
||||
}
|
||||
|
||||
@ -439,6 +437,25 @@ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, con
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_enumerate_add_match_tag:
|
||||
* @udev_enumerate: context
|
||||
* @tag: filter for a tag of the device to include in the list
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (tag == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
|
||||
&udev_enumerate->tags_match_list, tag, NULL, 1, 0) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_enumerate_add_match_sysname:
|
||||
* @udev_enumerate: context
|
||||
@ -458,46 +475,37 @@ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_sysattr(struct udev_enumerate *udev_enumerate, const char *syspath)
|
||||
static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
/* skip list */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
|
||||
if (match_sysattr_value(udev, syspath,
|
||||
udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return 0;
|
||||
if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return false;
|
||||
}
|
||||
/* include list */
|
||||
if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
|
||||
/* anything that does not match, will make it FALSE */
|
||||
if (!match_sysattr_value(udev, syspath,
|
||||
udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return 0;
|
||||
if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int match_property(struct udev_enumerate *udev_enumerate, const char *syspath)
|
||||
static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev_device *dev;
|
||||
struct udev_list_entry *list_entry;
|
||||
int match = false;
|
||||
bool match = false;
|
||||
|
||||
/* no match always matches */
|
||||
if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
|
||||
return 1;
|
||||
|
||||
/* no device does not match */
|
||||
dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
|
||||
if (dev == NULL)
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
/* loop over matches */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
|
||||
@ -525,23 +533,38 @@ static int match_property(struct udev_enumerate *udev_enumerate, const char *sys
|
||||
}
|
||||
}
|
||||
out:
|
||||
udev_device_unref(dev);
|
||||
return match;
|
||||
}
|
||||
|
||||
static int match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
|
||||
static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
/* no match always matches */
|
||||
if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
|
||||
return true;
|
||||
|
||||
/* loop over matches */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
|
||||
if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
|
||||
continue;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
|
||||
@ -562,54 +585,53 @@ static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
|
||||
util_strpcpyl(&s, l, "/", subdir2, NULL);
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
return -1;
|
||||
return -ENOENT;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char syspath[UTIL_PATH_SIZE];
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
struct stat statbuf;
|
||||
struct udev_device *dev;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!match_sysname(udev_enumerate, dent->d_name))
|
||||
continue;
|
||||
|
||||
util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
|
||||
if (!match_property(udev_enumerate, syspath))
|
||||
dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
if (lstat(syspath, &statbuf) != 0)
|
||||
continue;
|
||||
if (S_ISREG(statbuf.st_mode))
|
||||
continue;
|
||||
if (S_ISLNK(statbuf.st_mode))
|
||||
util_resolve_sys_link(udev, syspath, sizeof(syspath));
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
|
||||
if (stat(filename, &statbuf) != 0)
|
||||
continue;
|
||||
if (!match_sysattr(udev_enumerate, syspath))
|
||||
continue;
|
||||
syspath_add(udev_enumerate, syspath);
|
||||
if (!match_tag(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_property(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_sysattr(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
|
||||
syspath_add(udev_enumerate, udev_device_get_syspath(dev));
|
||||
nomatch:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
|
||||
static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
|
||||
@ -675,17 +697,59 @@ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
|
||||
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
|
||||
if (stat(base, &statbuf) == 0) {
|
||||
/* we have /subsystem/, forget all the old stuff */
|
||||
dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
|
||||
scan_dir(udev_enumerate, "subsystem", "devices", NULL);
|
||||
|
||||
if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) {
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
/* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
char path[UTIL_PATH_SIZE];
|
||||
|
||||
util_strscpyl(path, sizeof(path), udev_get_dev_path(udev), "/.udev/tags/",
|
||||
udev_list_entry_get_name(list_entry), NULL);
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
continue;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
struct udev_device *dev;
|
||||
char syspath[UTIL_PATH_SIZE];
|
||||
char *s;
|
||||
size_t l;
|
||||
ssize_t len;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
s = syspath;
|
||||
l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev), NULL);
|
||||
len = readlinkat(dirfd(dir), dent->d_name, s, l);
|
||||
if (len <= 0 || (size_t)len == l)
|
||||
continue;
|
||||
s[len] = '\0';
|
||||
|
||||
dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
syspath_add(udev_enumerate, udev_device_get_syspath(dev));
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
|
||||
if (stat(base, &statbuf) == 0) {
|
||||
/* we have /subsystem/, forget all the old stuff */
|
||||
dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
|
||||
scan_dir(udev_enumerate, "subsystem", "devices", NULL);
|
||||
} else {
|
||||
dbg(udev, "searching '/bus/*/devices/*' dir\n");
|
||||
scan_dir(udev_enumerate, "bus", "devices", NULL);
|
||||
dbg(udev, "searching '/class/*' dir\n");
|
||||
scan_dir(udev_enumerate, "class", NULL, NULL);
|
||||
scan_dir(udev_enumerate, "bus", "devices", NULL);
|
||||
dbg(udev, "searching '/class/*' dir\n");
|
||||
scan_dir(udev_enumerate, "class", NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -704,6 +768,7 @@ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
|
||||
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
|
||||
if (stat(base, &statbuf) == 0)
|
||||
subsysdir = "subsystem";
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libudev - interface to udev device information
|
||||
*
|
||||
* Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
|
||||
* Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -49,6 +49,7 @@ struct udev_monitor {
|
||||
struct sockaddr_un sun;
|
||||
socklen_t addrlen;
|
||||
struct udev_list_node filter_subsystem_list;
|
||||
struct udev_list_node filter_tag_list;
|
||||
};
|
||||
|
||||
enum udev_monitor_netlink_group {
|
||||
@ -57,25 +58,28 @@ enum udev_monitor_netlink_group {
|
||||
UDEV_MONITOR_UDEV,
|
||||
};
|
||||
|
||||
#define UDEV_MONITOR_MAGIC 0xcafe1dea
|
||||
#define UDEV_MONITOR_MAGIC 0xfeedcafe
|
||||
struct udev_monitor_netlink_header {
|
||||
/* udev version text */
|
||||
char version[16];
|
||||
/* "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 int magic;
|
||||
/* properties buffer */
|
||||
unsigned short properties_off;
|
||||
unsigned short properties_len;
|
||||
/* total length of header structure known to the sender */
|
||||
unsigned int header_size;
|
||||
/* properties string buffer */
|
||||
unsigned int properties_off;
|
||||
unsigned int properties_len;
|
||||
/*
|
||||
* hashes of some common device properties strings to filter with socket filters in
|
||||
* the client used in the kernel from socket filter rules; needs to be stored in
|
||||
* network order
|
||||
* hashes of primary device properties strings, to let libudev subscribers
|
||||
* use in-kernel socket filters; values need to be stored in network order
|
||||
*/
|
||||
unsigned int filter_subsystem;
|
||||
unsigned int filter_devtype;
|
||||
unsigned int filter_subsystem_hash;
|
||||
unsigned int filter_devtype_hash;
|
||||
unsigned int filter_tag_bloom_hi;
|
||||
unsigned int filter_tag_bloom_lo;
|
||||
};
|
||||
|
||||
static struct udev_monitor *udev_monitor_new(struct udev *udev)
|
||||
@ -88,6 +92,7 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev)
|
||||
udev_monitor->refcount = 1;
|
||||
udev_monitor->udev = udev;
|
||||
udev_list_init(&udev_monitor->filter_subsystem_list);
|
||||
udev_list_init(&udev_monitor->filter_tag_list);
|
||||
return udev_monitor;
|
||||
}
|
||||
|
||||
@ -247,13 +252,14 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
|
||||
*/
|
||||
int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
static struct sock_filter ins[256];
|
||||
static struct sock_fprog filter;
|
||||
struct sock_filter ins[512];
|
||||
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)
|
||||
if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
|
||||
udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
|
||||
return 0;
|
||||
|
||||
memset(ins, 0x00, sizeof(ins));
|
||||
@ -266,35 +272,74 @@ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
|
||||
/* wrong magic, pass packet */
|
||||
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
|
||||
|
||||
/* add all subsystem match values */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
|
||||
unsigned int hash;
|
||||
if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
|
||||
int tag_matches;
|
||||
|
||||
/* load filter_subsystem value in A */
|
||||
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem));
|
||||
hash = util_string_hash32(udev_list_entry_get_name(list_entry));
|
||||
if (udev_list_entry_get_value(list_entry) == NULL) {
|
||||
/* jump if subsystem does not match */
|
||||
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
|
||||
} else {
|
||||
/* jump if subsystem does not match */
|
||||
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
|
||||
/* count tag matches, to calculate end of tag match block */
|
||||
tag_matches = 0;
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
|
||||
tag_matches++;
|
||||
|
||||
/* load filter_devtype value in A */
|
||||
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype));
|
||||
/* jump if value does not match */
|
||||
hash = util_string_hash32(udev_list_entry_get_value(list_entry));
|
||||
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
|
||||
/* add all tags matches */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
|
||||
uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
/* nothing matched, drop packet */
|
||||
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
|
||||
|
||||
/* add all subsystem matches */
|
||||
if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
|
||||
unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry));
|
||||
|
||||
/* 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 (udev_list_entry_get_value(list_entry) == NULL) {
|
||||
/* jump if subsystem does not match */
|
||||
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
|
||||
} else {
|
||||
/* 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 */
|
||||
hash = util_string_hash32(udev_list_entry_get_value(list_entry));
|
||||
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 >= ARRAY_SIZE(ins))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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.len = i;
|
||||
@ -406,6 +451,7 @@ void udev_monitor_unref(struct udev_monitor *udev_monitor)
|
||||
if (udev_monitor->sock >= 0)
|
||||
close(udev_monitor->sock);
|
||||
udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list);
|
||||
udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_tag_list);
|
||||
dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
|
||||
free(udev_monitor);
|
||||
}
|
||||
@ -445,8 +491,7 @@ static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
|
||||
return 1;
|
||||
|
||||
goto tag;
|
||||
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);
|
||||
const char *dsubsys = udev_device_get_subsystem(udev_device);
|
||||
@ -458,11 +503,22 @@ static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *
|
||||
|
||||
devtype = udev_list_entry_get_value(list_entry);
|
||||
if (devtype == NULL)
|
||||
return 1;
|
||||
goto tag;
|
||||
ddevtype = udev_device_get_devtype(udev_device);
|
||||
if (ddevtype == NULL)
|
||||
continue;
|
||||
if (strcmp(ddevtype, devtype) == 0)
|
||||
goto tag;
|
||||
}
|
||||
return 0;
|
||||
|
||||
tag:
|
||||
if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
|
||||
return 1;
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
|
||||
const char *tag = udev_list_entry_get_name(list_entry);
|
||||
|
||||
if (udev_device_has_tag(udev_device, tag))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -556,13 +612,11 @@ retry:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "udev-", 5) == 0) {
|
||||
if (memcmp(buf, "libudev", 8) == 0) {
|
||||
/* udev message needs proper version magic */
|
||||
nlh = (struct udev_monitor_netlink_header *) buf;
|
||||
if (nlh->magic != htonl(UDEV_MONITOR_MAGIC))
|
||||
return NULL;
|
||||
if (nlh->properties_off < sizeof(struct udev_monitor_netlink_header))
|
||||
return NULL;
|
||||
if (nlh->properties_off+32 > buflen)
|
||||
return NULL;
|
||||
bufpos = nlh->properties_off;
|
||||
@ -626,17 +680,17 @@ retry:
|
||||
int udev_monitor_send_device(struct udev_monitor *udev_monitor,
|
||||
struct udev_monitor *destination, struct udev_device *udev_device)
|
||||
{
|
||||
struct msghdr smsg;
|
||||
struct iovec iov[2];
|
||||
const char *buf;
|
||||
ssize_t blen;
|
||||
ssize_t count;
|
||||
|
||||
blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
|
||||
if (blen < 32)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
if (udev_monitor->sun.sun_family != 0) {
|
||||
struct msghdr smsg;
|
||||
struct iovec iov[2];
|
||||
const char *action;
|
||||
char header[2048];
|
||||
char *s;
|
||||
@ -660,23 +714,41 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
|
||||
smsg.msg_iovlen = 2;
|
||||
smsg.msg_name = &udev_monitor->sun;
|
||||
smsg.msg_namelen = udev_monitor->addrlen;
|
||||
} else if (udev_monitor->snl.nl_family != 0) {
|
||||
count = sendmsg(udev_monitor->sock, &smsg, 0);
|
||||
info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor);
|
||||
return count;
|
||||
}
|
||||
|
||||
if (udev_monitor->snl.nl_family != 0) {
|
||||
struct msghdr smsg;
|
||||
struct iovec iov[2];
|
||||
const char *val;
|
||||
struct udev_monitor_netlink_header nlh;
|
||||
|
||||
struct udev_list_entry *list_entry;
|
||||
uint64_t tag_bloom_bits;
|
||||
|
||||
/* add versioned header */
|
||||
memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header));
|
||||
util_strscpy(nlh.version, sizeof(nlh.version), "udev-" VERSION);
|
||||
memcpy(nlh.prefix, "libudev", 8);
|
||||
nlh.magic = htonl(UDEV_MONITOR_MAGIC);
|
||||
nlh.header_size = sizeof(struct udev_monitor_netlink_header);
|
||||
val = udev_device_get_subsystem(udev_device);
|
||||
nlh.filter_subsystem = htonl(util_string_hash32(val));
|
||||
nlh.filter_subsystem_hash = htonl(util_string_hash32(val));
|
||||
val = udev_device_get_devtype(udev_device);
|
||||
if (val != NULL)
|
||||
nlh.filter_devtype = htonl(util_string_hash32(val));
|
||||
nlh.filter_devtype_hash = htonl(util_string_hash32(val));
|
||||
iov[0].iov_base = &nlh;
|
||||
iov[0].iov_len = sizeof(struct udev_monitor_netlink_header);
|
||||
|
||||
/* add tag bloom filter */
|
||||
tag_bloom_bits = 0;
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
|
||||
tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
|
||||
if (tag_bloom_bits > 0) {
|
||||
nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32);
|
||||
nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff);
|
||||
}
|
||||
|
||||
/* add properties list */
|
||||
nlh.properties_off = iov[0].iov_len;
|
||||
nlh.properties_len = blen;
|
||||
@ -697,13 +769,12 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
|
||||
else
|
||||
smsg.msg_name = &udev_monitor->snl_destination;
|
||||
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 netlink monitor %p\n", count, udev_monitor);
|
||||
return count;
|
||||
}
|
||||
|
||||
count = sendmsg(udev_monitor->sock, &smsg, 0);
|
||||
info(udev_monitor->udev, "passed %zi bytes to monitor %p\n", count, udev_monitor);
|
||||
return count;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -712,6 +783,9 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
|
||||
* @subsystem: the subsystem value to match the incoming devices against
|
||||
* @devtype: the devtype value to match the incoming devices against
|
||||
*
|
||||
* This filer is efficiently executed inside the kernel, and libudev subscribers
|
||||
* will usually not be woken up for devices which do not match.
|
||||
*
|
||||
* The filter must be installed before the monitor is switched to listening mode.
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
@ -721,13 +795,37 @@ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_mo
|
||||
if (udev_monitor == NULL)
|
||||
return -EINVAL;
|
||||
if (subsystem == NULL)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
if (udev_list_entry_add(udev_monitor->udev,
|
||||
&udev_monitor->filter_subsystem_list, subsystem, devtype, 0, 0) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_monitor_filter_add_match_tag:
|
||||
* @udev_monitor: the monitor
|
||||
* @tag: the name of a tag
|
||||
*
|
||||
* This filer is efficiently executed inside the kernel, and libudev subscribers
|
||||
* will usually not be woken up for devices which do not match.
|
||||
*
|
||||
* The filter must be installed before the monitor is switched to listening mode.
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
|
||||
{
|
||||
if (udev_monitor == NULL)
|
||||
return -EINVAL;
|
||||
if (tag == NULL)
|
||||
return -EINVAL;
|
||||
if (udev_list_entry_add(udev_monitor->udev,
|
||||
&udev_monitor->filter_tag_list, tag, NULL, 0, 0) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_monitor_filter_remove:
|
||||
* @udev_monitor: monitor
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "libudev.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
@ -84,7 +86,8 @@ const char *udev_device_get_sysname_old(struct udev_device *udev_device);
|
||||
int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
|
||||
const char *udev_device_get_knodename(struct udev_device *udev_device);
|
||||
int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
|
||||
struct udev_list_entry *udev_device_get_tag_list_entry(struct udev_device *udev_device);
|
||||
void udev_device_cleanup_tags_list(struct udev_device *udev_device);
|
||||
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
|
||||
int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
|
||||
int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename);
|
||||
int udev_device_get_timeout(struct udev_device *udev_device);
|
||||
@ -203,7 +206,8 @@ size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute_
|
||||
int udev_util_replace_whitespace(const char *str, char *to, size_t len);
|
||||
int udev_util_replace_chars(char *str, const char *white);
|
||||
int udev_util_encode_string(const char *str, char *str_enc, size_t len);
|
||||
unsigned int util_string_hash32(const char *str);
|
||||
unsigned int util_string_hash32(const char *key);
|
||||
uint64_t util_string_bloom64(const char *str);
|
||||
|
||||
/* libudev-util-private.c */
|
||||
int util_create_path(struct udev *udev, const char *path);
|
||||
|
@ -481,15 +481,74 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* http://sites.google.com/site/murmurhash/
|
||||
*
|
||||
* All code is released to the public domain. For business purposes,
|
||||
* Murmurhash is under the MIT license.
|
||||
*
|
||||
*/
|
||||
static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
|
||||
{
|
||||
/*
|
||||
* 'm' and 'r' are mixing constants generated offline.
|
||||
* They're not really 'magic', they just happen to work well.
|
||||
*/
|
||||
const unsigned int m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
/* initialize the hash to a 'random' value */
|
||||
unsigned int h = seed ^ len;
|
||||
|
||||
/* mix 4 bytes at a time into the hash */
|
||||
const unsigned char * data = (const unsigned char *)key;
|
||||
|
||||
while(len >= 4) {
|
||||
unsigned int k = *(unsigned int *)data;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h *= m;
|
||||
h ^= k;
|
||||
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
/* handle the last few bytes of the input array */
|
||||
switch(len) {
|
||||
case 3:
|
||||
h ^= data[2] << 16;
|
||||
case 2:
|
||||
h ^= data[1] << 8;
|
||||
case 1:
|
||||
h ^= data[0];
|
||||
h *= m;
|
||||
};
|
||||
|
||||
/* do a few final mixes of the hash to ensure the last few bytes are well-incorporated */
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
unsigned int util_string_hash32(const char *str)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (str[0] != '\0') {
|
||||
hash += str[0] << 4;
|
||||
hash += str[0] >> 4;
|
||||
hash *= 11;
|
||||
str++;
|
||||
}
|
||||
return hash;
|
||||
return murmur_hash2(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;
|
||||
unsigned int 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;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libudev - interface to udev device information
|
||||
*
|
||||
* Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
|
||||
* Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -118,6 +118,7 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito
|
||||
/* in-kernel socket filters to select messages that get delivered to a listener */
|
||||
int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
|
||||
const char *subsystem, const char *devtype);
|
||||
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
|
||||
int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
|
||||
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
|
||||
|
||||
@ -138,6 +139,7 @@ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, cons
|
||||
int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
|
||||
int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
|
||||
int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
|
||||
int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
|
||||
int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
|
||||
/* run enumeration with active filters */
|
||||
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
|
||||
|
@ -543,7 +543,6 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
|
||||
|
||||
if (strcmp(udev_device_get_action(dev), "remove") == 0) {
|
||||
udev_device_read_db(dev);
|
||||
udev_device_set_info_loaded(dev);
|
||||
udev_device_delete_db(dev);
|
||||
|
||||
if (major(udev_device_get_devnum(dev)) != 0)
|
||||
|
@ -157,6 +157,7 @@ enum token_type {
|
||||
TK_A_GROUP_ID, /* gid_t */
|
||||
TK_A_MODE_ID, /* mode_t */
|
||||
TK_A_ENV, /* val, attr */
|
||||
TK_A_TAG, /* val */
|
||||
TK_A_NAME, /* val */
|
||||
TK_A_DEVLINK, /* val */
|
||||
TK_A_EVENT_TIMEOUT, /* int */
|
||||
@ -285,6 +286,7 @@ static const char *token_str(enum token_type type)
|
||||
[TK_A_GROUP_ID] = "A GROUP_ID",
|
||||
[TK_A_MODE_ID] = "A MODE_ID",
|
||||
[TK_A_ENV] = "A ENV",
|
||||
[TK_A_TAG] = "A ENV",
|
||||
[TK_A_NAME] = "A NAME",
|
||||
[TK_A_DEVLINK] = "A DEVLINK",
|
||||
[TK_A_EVENT_TIMEOUT] = "A EVENT_TIMEOUT",
|
||||
@ -354,6 +356,9 @@ static void dump_token(struct udev_rules *rules, struct token *token)
|
||||
dbg(rules->udev, "%s %s '%s' '%s'(%s)\n",
|
||||
token_str(type), operation_str(op), attr, value, string_glob_str(glob));
|
||||
break;
|
||||
case TK_A_TAG:
|
||||
dbg(rules->udev, "%s %s '%s'\n", token_str(type), operation_str(op), value);
|
||||
break;
|
||||
case TK_A_STRING_ESCAPE_NONE:
|
||||
case TK_A_STRING_ESCAPE_REPLACE:
|
||||
dbg(rules->udev, "%s\n", token_str(type));
|
||||
@ -1003,6 +1008,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
|
||||
case TK_A_MODE:
|
||||
case TK_A_NAME:
|
||||
case TK_A_GOTO:
|
||||
case TK_A_TAG:
|
||||
token->key.value_off = add_string(rule_tmp->rules, value);
|
||||
break;
|
||||
case TK_M_ENV:
|
||||
@ -1350,6 +1356,11 @@ static int add_rule(struct udev_rules *rules, char *line,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(key, "TAG") == 0) {
|
||||
rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(key, "PROGRAM") == 0) {
|
||||
rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
|
||||
continue;
|
||||
@ -2408,6 +2419,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_A_TAG:
|
||||
udev_device_add_tag(event->dev, &rules->buf[cur->key.value_off]);
|
||||
break;
|
||||
case TK_A_NAME:
|
||||
{
|
||||
const char *name = &rules->buf[cur->key.value_off];
|
||||
|
@ -348,6 +348,19 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>TAG</option></term>
|
||||
<listitem>
|
||||
<para>Attach a tag to a device. This is used to filter events for users
|
||||
of libudev's monitor functionality, or to enumerate a group of tagged
|
||||
devices. The implementation can only work efficiently if only a few
|
||||
tags are attached to a device. It is only meant to be used in
|
||||
contexts with specific device filter requirements, and not as a
|
||||
general-purpose flag. Excessive use might result in inefficient event
|
||||
handling.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>RUN</option></term>
|
||||
<listitem>
|
||||
|
@ -73,6 +73,7 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
|
||||
int print_kernel = 0;
|
||||
int print_udev = 0;
|
||||
struct udev_list_node subsystem_match_list;
|
||||
struct udev_list_node tag_match_list;
|
||||
struct udev_monitor *udev_monitor = NULL;
|
||||
struct udev_monitor *kernel_monitor = NULL;
|
||||
fd_set readfds;
|
||||
@ -84,13 +85,15 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
|
||||
{ "kernel", no_argument, NULL, 'k' },
|
||||
{ "udev", no_argument, NULL, 'u' },
|
||||
{ "subsystem-match", required_argument, NULL, 's' },
|
||||
{ "tag-match", required_argument, NULL, 't' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{}
|
||||
};
|
||||
|
||||
udev_list_init(&subsystem_match_list);
|
||||
udev_list_init(&tag_match_list);
|
||||
while (1) {
|
||||
option = getopt_long(argc, argv, "epkus:h", options, NULL);
|
||||
option = getopt_long(argc, argv, "pekus:t:h", options, NULL);
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
@ -119,12 +122,16 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
|
||||
udev_list_entry_add(udev, &subsystem_match_list, subsys, devtype, 0, 0);
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
udev_list_entry_add(udev, &tag_match_list, optarg, NULL, 0, 0);
|
||||
break;
|
||||
case 'h':
|
||||
printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n"
|
||||
" --property print the event properties\n"
|
||||
" --kernel print kernel uevents\n"
|
||||
" --udev print udev events\n"
|
||||
" --subsystem-match=<subsystem[/devtype]> filter events by subsystem\n"
|
||||
" --tag-match=<tag> filter events by tag\n"
|
||||
" --help\n\n");
|
||||
default:
|
||||
goto out;
|
||||
@ -168,6 +175,13 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
|
||||
fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys);
|
||||
}
|
||||
|
||||
udev_list_entry_foreach(entry, udev_list_get_entry(&tag_match_list)) {
|
||||
const char *tag = udev_list_entry_get_name(entry);
|
||||
|
||||
if (udev_monitor_filter_add_match_tag(udev_monitor, tag) < 0)
|
||||
fprintf(stderr, "error: unable to apply tag filter '%s'\n", tag);
|
||||
}
|
||||
|
||||
if (udev_monitor_enable_receiving(udev_monitor) < 0) {
|
||||
fprintf(stderr, "error: unable to subscribe to udev events\n");
|
||||
rc = 2;
|
||||
@ -244,5 +258,6 @@ out:
|
||||
udev_monitor_unref(udev_monitor);
|
||||
udev_monitor_unref(kernel_monitor);
|
||||
udev_list_cleanup_entries(udev, &subsystem_match_list);
|
||||
udev_list_cleanup_entries(udev, &tag_match_list);
|
||||
return rc;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ int udevadm_trigger(struct udev *udev, int argc, char *argv[])
|
||||
{ "attr-match", required_argument, NULL, 'a' },
|
||||
{ "attr-nomatch", required_argument, NULL, 'A' },
|
||||
{ "property-match", required_argument, NULL, 'p' },
|
||||
{ "tag-match", required_argument, NULL, 'g' },
|
||||
{ "sysname-match", required_argument, NULL, 'y' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{}
|
||||
@ -127,7 +128,7 @@ int udevadm_trigger(struct udev *udev, int argc, char *argv[])
|
||||
const char *val;
|
||||
char buf[UTIL_PATH_SIZE];
|
||||
|
||||
option = getopt_long(argc, argv, "vnFo:t:hcp:s:S:a:A:y:", options, NULL);
|
||||
option = getopt_long(argc, argv, "vng:o:t:hcp:s:S:a:A:y:", options, NULL);
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
@ -172,6 +173,9 @@ int udevadm_trigger(struct udev *udev, int argc, char *argv[])
|
||||
key = keyval(optarg, &val, buf, sizeof(buf));
|
||||
udev_enumerate_add_match_property(udev_enumerate, key, val);
|
||||
break;
|
||||
case 'g':
|
||||
udev_enumerate_add_match_tag(udev_enumerate, optarg);
|
||||
break;
|
||||
case 'y':
|
||||
udev_enumerate_add_match_sysname(udev_enumerate, optarg);
|
||||
break;
|
||||
@ -190,6 +194,7 @@ int udevadm_trigger(struct udev *udev, int argc, char *argv[])
|
||||
" --attr-match=<file[=<value>]> trigger devices with a matching attribute\n"
|
||||
" --attr-nomatch=<file[=<value>]> exclude devices with a matching attribute\n"
|
||||
" --property-match=<key>=<value> trigger devices with a matching property\n"
|
||||
" --tag-match=<key>=<value> trigger devices with a matching property\n"
|
||||
" --sysname-match=<name> trigger devices with a matching name\n"
|
||||
" --help\n\n");
|
||||
goto exit;
|
||||
|
@ -216,6 +216,13 @@
|
||||
specified multiple times and supports shell style pattern matching.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--tag-match=<replaceable>property</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices with a matching tag. This option can be
|
||||
specified multiple times.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--sysname-match=<replaceable>name</replaceable></option></term>
|
||||
<listitem>
|
||||
@ -355,6 +362,12 @@
|
||||
<para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--tag-match=<replaceable>string</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Filter events by property. Only udev events with a given tag attached will pass.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
|
Loading…
Reference in New Issue
Block a user