1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

udevtrigger: options to filter by subsystem and sysfs attribute

This commit is contained in:
Kay Sievers 2006-09-03 03:04:20 +02:00
parent 3c2081fcb7
commit fc89fe7edf
4 changed files with 228 additions and 27 deletions

12
udevd.c
View File

@ -926,12 +926,6 @@ int main(int argc, char *argv[], char *envp[])
selinux_init();
dbg("version %s", UDEV_VERSION);
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
err("root privileges required");
goto exit;
}
/* parse commandline options */
for (i = 1 ; i < argc; i++) {
char *arg = argv[i];
@ -946,6 +940,12 @@ int main(int argc, char *argv[], char *envp[])
}
}
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
err("root privileges required");
goto exit;
}
/* init sockets to receive events */
if (init_udevd_socket() < 0) {
if (errno == EADDRINUSE) {

View File

@ -14,20 +14,32 @@
udevtrigger \- request kernel devices events for coldplug
.SH "SYNOPSIS"
.HP 12
\fBudevtrigger\fR [\fB\-\-verbose\fR] [\fB\-\-dry\-run\fR] [\fB\-\-retry\-failed\fR]
\fBudevtrigger\fR [\fB\-\-verbose\fR] [\fB\-\-dry\-run\fR] [\fB\-\-retry\-failed\fR] [\fB\-\-help\fR] [\fB\-\-subsystem\-match=\fR\fB\fIsubsystem\fR\fR] [\fB\-\-subsystem\-nomatch=\fR\fB\fIsubsystem\fR\fR] [\fB\-\-attr\-match=\fR\fB\fIattribute=value\fR\fR] [\fB\-\-attr\-nomatch=\fR\fB\fIattribute=value\fR\fR]
.SH "DESCRIPTION"
.PP
Trigger kernel device uevents to replay missing events at system coldplug.
.SH "OPTIONS"
.TP 3n
\fB\-\-verbose\fR
Print the list of devices found in sysfs.
Print the list of devices which will be triggered.
.TP 3n
\fB\-\-dry\-run\fR
Do not actually trigger the event.
.TP 3n
\fB\-\-retry\-failed\fR
Trigger events which are failed during a previous run.
Trigger only the events which are failed during a previous run.
.TP 3n
\fB\-\-subsystem\-match=\fR\fB\fIsubsystem\fR\fR
Trigger events for devices which belong to a matching subsystem. This option can be specified multiple times and supports shell style pattern matching.
.TP 3n
\fB\-\-subsystem\-nomatch=\fR\fB\fIsubsystem\fR\fR
Do not trigger events for devices which belong to a matching subsystem. This option can be specified multiple times and supports shell style pattern matching.
.TP 3n
\fB\-\-attr\-match=\fR\fB\fIattribute=value\fR\fR
Trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the attribute is matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is checked. This option can be specified multiple times.
.TP 3n
\fB\-\-attr\-nomatch\fR\fB\fIattribute=value\fR\fR
Do not trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the attribute is matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is checked. This option can be specified multiple times.
.SH "ENVIRONMENT"
.TP 3n
\fBUDEV_LOG\fR

View File

@ -22,19 +22,18 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <syslog.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "udev.h"
#include "udevd.h"
static int verbose;
static int dry_run;
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
{
@ -49,6 +48,9 @@ void log_message(int priority, const char *format, ...)
}
#endif
static int verbose;
static int dry_run;
/* list of devices that we should run last due to any one of a number of reasons */
static char *last_list[] = {
"/class/block/md",
@ -69,6 +71,11 @@ LIST_HEAD(device_first_list);
LIST_HEAD(device_default_list);
LIST_HEAD(device_last_list);
LIST_HEAD(filter_subsytem_match_list);
LIST_HEAD(filter_subsytem_nomatch_list);
LIST_HEAD(filter_attr_match_list);
LIST_HEAD(filter_attr_nomatch_list);
static int device_list_insert(const char *path)
{
struct list_head *device_list = &device_default_list;
@ -164,6 +171,93 @@ static int is_device(const char *path)
return 1;
}
static int subsystem_filtered(const char *subsystem)
{
struct name_entry *loop_name;
/* skip devices matching the listed subsystems */
list_for_each_entry(loop_name, &filter_subsytem_nomatch_list, node)
if (fnmatch(subsystem, loop_name->name, 0) == 0)
return 1;
/* skip devices not matching the listed subsystems */
if (!list_empty(&filter_subsytem_match_list)) {
list_for_each_entry(loop_name, &filter_subsytem_match_list, node)
if (fnmatch(subsystem, loop_name->name, 0) == 0)
return 0;
return 1;
}
return 0;
}
static int attr_match(const char *path, const char *attr_value)
{
char attr[NAME_SIZE];
char file[PATH_SIZE];
char *match_value;
strlcpy(attr, attr_value, sizeof(attr));
/* separate attr and match value */
match_value = strchr(attr, '=');
if (match_value != NULL) {
match_value[0] = '\0';
match_value = &match_value[1];
}
strlcpy(file, path, sizeof(file));
strlcat(file, "/", sizeof(file));
strlcat(file, attr, sizeof(file));
if (match_value != NULL) {
/* match file content */
char value[NAME_SIZE];
int fd;
ssize_t size;
fd = open(file, O_RDONLY);
if (fd < 0)
return 0;
size = read(fd, value, sizeof(value));
close(fd);
if (size < 0)
return 0;
value[size] = '\0';
remove_trailing_chars(value, '\n');
/* match if attribute value matches */
if (fnmatch(match_value, value, 0) == 0)
return 1;
} else {
/* match if attribute exists */
struct stat statbuf;
if (stat(file, &statbuf) == 0)
return 1;
}
return 0;
}
static int attr_filtered(const char *path)
{
struct name_entry *loop_name;
/* skip devices matching the listed sysfs attributes */
list_for_each_entry(loop_name, &filter_attr_nomatch_list, node)
if (attr_match(path, loop_name->name))
return 1;
/* skip devices not matching the listed sysfs attributes */
if (!list_empty(&filter_attr_match_list)) {
list_for_each_entry(loop_name, &filter_attr_match_list, node)
if (attr_match(path, loop_name->name))
return 0;
return 1;
}
return 0;
}
static void scan_bus(void)
{
char base[PATH_SIZE];
@ -183,6 +277,9 @@ static void scan_bus(void)
if (dent->d_name[0] == '.')
continue;
if (subsystem_filtered(dent->d_name))
continue;
strlcpy(dirname, base, sizeof(dirname));
strlcat(dirname, "/", sizeof(dirname));
strlcat(dirname, dent->d_name, sizeof(dirname));
@ -200,7 +297,8 @@ static void scan_bus(void)
strlcpy(dirname2, dirname, sizeof(dirname2));
strlcat(dirname2, "/", sizeof(dirname2));
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
if (attr_filtered(dirname2))
continue;
if (is_device(dirname2))
device_list_insert(dirname2);
}
@ -224,6 +322,9 @@ static void scan_block(void)
if (stat(base, &statbuf) == 0)
return;
if (subsystem_filtered("block"))
return;
strlcpy(base, sysfs_path, sizeof(base));
strlcat(base, "/block", sizeof(base));
@ -240,6 +341,8 @@ static void scan_block(void)
strlcpy(dirname, base, sizeof(dirname));
strlcat(dirname, "/", sizeof(dirname));
strlcat(dirname, dent->d_name, sizeof(dirname));
if (attr_filtered(dirname))
continue;
if (is_device(dirname))
device_list_insert(dirname);
else
@ -260,6 +363,8 @@ static void scan_block(void)
strlcpy(dirname2, dirname, sizeof(dirname2));
strlcat(dirname2, "/", sizeof(dirname2));
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
if (attr_filtered(dirname2))
continue;
if (is_device(dirname2))
device_list_insert(dirname2);
}
@ -289,6 +394,9 @@ static void scan_class(void)
if (dent->d_name[0] == '.')
continue;
if (subsystem_filtered(dent->d_name))
continue;
strlcpy(dirname, base, sizeof(dirname));
strlcat(dirname, "/", sizeof(dirname));
strlcat(dirname, dent->d_name, sizeof(dirname));
@ -306,6 +414,8 @@ static void scan_class(void)
strlcpy(dirname2, dirname, sizeof(dirname2));
strlcat(dirname2, "/", sizeof(dirname2));
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
if (attr_filtered(dirname2))
continue;
if (is_device(dirname2))
device_list_insert(dirname2);
}
@ -356,36 +466,73 @@ static void scan_failed(void)
int main(int argc, char *argv[], char *envp[])
{
int i;
int failed = 0;
int option;
int longindex;
struct option options[] = {
{ "verbose", 0, NULL, 'v' },
{ "dry-run", 0, NULL, 'n' },
{ "retry-failed", 0, NULL, 'F' },
{ "help", 0, NULL, 'h' },
{ "subsystem-match", 1, NULL, 's' },
{ "subsystem-nomatch", 1, NULL, 'S' },
{ "attr-match", 1, NULL, 'a' },
{ "attr-nomatch", 1, NULL, 'A' },
{}
};
logging_init("udevtrigger");
udev_config_init();
dbg("version %s", UDEV_VERSION);
sysfs_init();
for (i = 1 ; i < argc; i++) {
char *arg = argv[i];
while (1) {
option = getopt_long(argc, argv, "vnFhs:S:a:A:", options, &longindex);
if (option == -1)
break;
if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0) {
switch (option) {
case 'v':
verbose = 1;
} else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0) {
break;
case 'n':
dry_run = 1;
} else if (strcmp(arg, "--retry-failed") == 0 || strcmp(arg, "-F") == 0) {
break;
case 'F':
failed = 1;
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
printf("Usage: udevtrigger [--help] [--verbose] [--dry-run] [--retry-failed]\n");
break;
case 's':
name_list_add(&filter_subsytem_match_list, optarg, 0);
break;
case 'S':
name_list_add(&filter_subsytem_nomatch_list, optarg, 0);
break;
case 'a':
name_list_add(&filter_attr_match_list, optarg, 0);
break;
case 'A':
name_list_add(&filter_attr_nomatch_list, optarg, 0);
break;
case 'h':
printf("Usage: udevtrigger OPTIONS\n"
" --verbose print the list of devices which will be triggered\n"
" --dry-run do not actually trigger the event\n"
" --retry-failed trigger only the events which are failed during a previous run\n"
" --subsystem-match select only devices from the specified subystem\n"
" --subsystem-nomatch exclude devices from the specified subystem\n"
" --attr-match=<file[=<value>]> select only devices with a matching sysfs attribute\n"
" --attr-nomatch=<file[=<value>]> exclude devices with a matching sysfs attribute\n"
" --help print this text\n"
"\n");
goto exit;
default:
goto exit;
} else {
fprintf(stderr, "unrecognized option '%s'\n", arg);
err("unrecognized option '%s'\n", arg);
}
}
if (failed)
scan_failed();
else {
/* default action */
scan_bus();
scan_class();
scan_block();
@ -393,6 +540,11 @@ int main(int argc, char *argv[], char *envp[])
exec_lists();
exit:
name_list_cleanup(&filter_subsytem_match_list);
name_list_cleanup(&filter_subsytem_nomatch_list);
name_list_cleanup(&filter_attr_match_list);
name_list_cleanup(&filter_attr_nomatch_list);
sysfs_cleanup();
logging_close();
return 0;

View File

@ -28,6 +28,11 @@
<arg><option>--verbose</option></arg>
<arg><option>--dry-run</option></arg>
<arg><option>--retry-failed</option></arg>
<arg><option>--help</option></arg>
<arg><option>--subsystem-match=<replaceable>subsystem</replaceable></option></arg>
<arg><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></arg>
<arg><option>--attr-match=<replaceable>attribute=value</replaceable></option></arg>
<arg><option>--attr-nomatch=<replaceable>attribute=value</replaceable></option></arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -40,7 +45,7 @@
<varlistentry>
<term><option>--verbose</option></term>
<listitem>
<para>Print the list of devices found in sysfs.</para>
<para>Print the list of devices which will be triggered.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -52,7 +57,39 @@
<varlistentry>
<term><option>--retry-failed</option></term>
<listitem>
<para>Trigger events which are failed during a previous run.</para>
<para>Trigger only the events which are failed during a previous run.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--subsystem-match=<replaceable>subsystem</replaceable></option></term>
<listitem>
<para>Trigger events for devices which belong to a matching subsystem. This option
can be specified multiple times and supports shell style pattern matching.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></term>
<listitem>
<para>Do not trigger events for devices which belong to a matching subsystem. This option
can be specified multiple times and supports shell style pattern matching.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--attr-match=<replaceable>attribute=value</replaceable></option></term>
<listitem>
<para>Trigger events for devices with a matching sysfs attribute. If a value is specified
along with the attribute name, the content of the attribute is matched against the given
value using shell style pattern matching. If no value is specified, the existence of the
sysfs attribute is checked. This option can be specified multiple times.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--attr-nomatch<replaceable>attribute=value</replaceable></option></term>
<listitem>
<para>Do not trigger events for devices with a matching sysfs attribute. If a value is
specified along with the attribute name, the content of the attribute is matched against
the given value using shell style pattern matching. If no value is specified, the existence
of the sysfs attribute is checked. This option can be specified multiple times.</para>
</listitem>
</varlistentry>
</variablelist>