add udevtrigger to request events for coldplug
The shell script can't handle 1000's of devices.
This commit is contained in:
@@ -49,6 +49,7 @@ V =
|
||||
PROGRAMS = \
|
||||
udev \
|
||||
udevd \
|
||||
udevtrigger \
|
||||
udevsend \
|
||||
udevcontrol \
|
||||
udevmonitor \
|
||||
@@ -84,6 +85,7 @@ MAN_PAGES = \
|
||||
udev.7 \
|
||||
udevmonitor.8 \
|
||||
udevd.8 \
|
||||
udevtrigger.8 \
|
||||
udevsend.8 \
|
||||
udevtest.8 \
|
||||
udevinfo.8 \
|
||||
@@ -265,6 +267,7 @@ install-man:
|
||||
$(INSTALL_DATA) -D udevinfo.8 $(DESTDIR)$(mandir)/man8/udevinfo.8
|
||||
$(INSTALL_DATA) -D udevtest.8 $(DESTDIR)$(mandir)/man8/udevtest.8
|
||||
$(INSTALL_DATA) -D udevd.8 $(DESTDIR)$(mandir)/man8/udevd.8
|
||||
$(INSTALL_DATA) -D udevtrigger.8 $(DESTDIR)$(mandir)/man8/udevtrigger.8
|
||||
$(INSTALL_DATA) -D udevmonitor.8 $(DESTDIR)$(mandir)/man8/udevmonitor.8
|
||||
- ln -f -s udevd.8 $(DESTDIR)$(mandir)/man8/udevcontrol.8
|
||||
@extras="$(EXTRAS)"; for target in $$extras; do \
|
||||
@@ -277,6 +280,7 @@ uninstall-man:
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevinfo.8
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevtest.8
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevd.8
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevtrigger.8
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevmonitor.8
|
||||
- rm -f $(DESTDIR)$(mandir)/man8/udevcontrol.8
|
||||
@ extras="$(EXTRAS)"; for target in $$extras; do \
|
||||
@@ -287,6 +291,7 @@ uninstall-man:
|
||||
install-bin:
|
||||
$(INSTALL) -d $(DESTDIR)$(udevdir)
|
||||
$(INSTALL_PROGRAM) -D udevd $(DESTDIR)$(sbindir)/udevd
|
||||
$(INSTALL_PROGRAM) -D udevtrigger $(DESTDIR)$(sbindir)/udevtrigger
|
||||
$(INSTALL_PROGRAM) -D udevcontrol $(DESTDIR)$(sbindir)/udevcontrol
|
||||
$(INSTALL_PROGRAM) -D udevmonitor $(DESTDIR)$(usrsbindir)/udevmonitor
|
||||
$(INSTALL_PROGRAM) -D udevinfo $(DESTDIR)$(usrbindir)/udevinfo
|
||||
@@ -303,6 +308,7 @@ endif
|
||||
|
||||
uninstall-bin:
|
||||
- rm -f $(DESTDIR)$(sbindir)/udevd
|
||||
- rm -f $(DESTDIR)$(sbindir)/udevtrigger
|
||||
- rm -f $(DESTDIR)$(sbindir)/udevcontrol
|
||||
- rm -f $(DESTDIR)$(usrsbindir)/udevmonitor
|
||||
- rm -f $(DESTDIR)$(usrbindir)/udevinfo
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
.\" ** You probably do not want to edit this file directly **
|
||||
.\" It was generated using the DocBook XSL Stylesheets (version 1.69.1).
|
||||
.\" Instead of manually editing it, you probably should edit the DocBook XML
|
||||
.\" source for it and then use the DocBook XSL Stylesheets to regenerate it.
|
||||
.TH "UDEVTRIGGER" "8" "March 2006" "udev" "udevtrigger"
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
udevtrigger \- request kernel devices events for coldplug
|
||||
.SH "SYNOPSIS"
|
||||
.HP 12
|
||||
\fBudevtrigger\fR [\fB\-\-verbose\fR] [\fB\-\-dry\-run\fR]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
Trigger kernel device uevents to replay missing events at system coldplug.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
\fB\-\-verbose\fR
|
||||
print out the devices found in sysfs.
|
||||
.TP
|
||||
\fB\-\-dry\-run\fR
|
||||
don't actually trigger the event.
|
||||
.SH "ENVIRONMENT"
|
||||
.TP
|
||||
\fBUDEV_LOG\fR
|
||||
Overrides the syslog priority specified in the config file.
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
Written by Kay Sievers
|
||||
<kay.sievers@vrfy.org>
|
||||
and Hannes Reinecke
|
||||
<hare@suse.de>.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBudev\fR(8)
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* udevtrigger.c
|
||||
*
|
||||
* Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "udev.h"
|
||||
|
||||
static const char *udev_log_str;
|
||||
static int verbose;
|
||||
static int dry_run;
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message(int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (priority > udev_log_priority)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* list of devices that we should run last due to any one of a number of reasons */
|
||||
static char *last_list[] = {
|
||||
"/class/block/md",
|
||||
"/class/block/dm-",
|
||||
"/block/md",
|
||||
"/block/dm-",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* list of devices that we should run first due to any one of a number of reasons */
|
||||
static char *first_list[] = {
|
||||
"/class/mem",
|
||||
"/class/tty",
|
||||
NULL
|
||||
};
|
||||
|
||||
LIST_HEAD(device_first_list);
|
||||
LIST_HEAD(device_default_list);
|
||||
LIST_HEAD(device_last_list);
|
||||
|
||||
static int device_list_insert(const char *path)
|
||||
{
|
||||
struct list_head *device_list = &device_default_list;
|
||||
int i;
|
||||
|
||||
for (i = 0; first_list[i] != NULL; i++) {
|
||||
if (strncmp(path, first_list[i], strlen(first_list[i])) == 0) {
|
||||
device_list = &device_first_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; last_list[i] != NULL; i++) {
|
||||
if (strncmp(path, last_list[i], strlen(last_list[i])) == 0) {
|
||||
device_list = &device_last_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbg("add '%s'" , path);
|
||||
/* double entries will be ignored */
|
||||
name_list_add(device_list, path, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trigger_uevent(const char *path)
|
||||
{
|
||||
char filename[PATH_SIZE];
|
||||
int fd;
|
||||
|
||||
strlcpy(filename, path, sizeof(filename));
|
||||
strlcat(filename, "/uevent", sizeof(filename));
|
||||
|
||||
if (verbose)
|
||||
printf("%s\n", path);
|
||||
|
||||
if (dry_run)
|
||||
return;
|
||||
|
||||
fd = open(filename, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
dbg("error on opening %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (write(fd, "add", 3) < 0)
|
||||
info("error on triggering %s: %s\n", filename, strerror(errno));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void exec_lists(void)
|
||||
{
|
||||
struct name_entry *loop_device;
|
||||
struct name_entry *tmp_device;
|
||||
|
||||
/* handle the devices on the "first" list first */
|
||||
list_for_each_entry_safe(loop_device, tmp_device, &device_first_list, node) {
|
||||
trigger_uevent(loop_device->name);
|
||||
list_del(&loop_device->node);
|
||||
free(loop_device);
|
||||
}
|
||||
|
||||
/* handle the devices on the "default" list next */
|
||||
list_for_each_entry_safe(loop_device, tmp_device, &device_default_list, node) {
|
||||
trigger_uevent(loop_device->name);
|
||||
list_del(&loop_device->node);
|
||||
free(loop_device);
|
||||
}
|
||||
|
||||
/* handle devices on the "last" list, if any */
|
||||
list_for_each_entry_safe(loop_device, tmp_device, &device_last_list, node) {
|
||||
trigger_uevent(loop_device->name);
|
||||
list_del(&loop_device->node);
|
||||
free(loop_device);
|
||||
}
|
||||
}
|
||||
|
||||
static int is_device(const char *path)
|
||||
{
|
||||
char filename[PATH_SIZE];
|
||||
struct stat statbuf;
|
||||
|
||||
/* look for the uevent file of the kobject */
|
||||
strlcpy(filename, path, sizeof(filename));
|
||||
strlcat(filename, "/uevent", sizeof(filename));
|
||||
if (stat(filename, &statbuf) < 0)
|
||||
return 0;
|
||||
|
||||
if (!(statbuf.st_mode & S_IWUSR))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void udev_scan_bus(void)
|
||||
{
|
||||
char base[PATH_SIZE];
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
||||
strlcpy(base, sysfs_path, sizeof(base));
|
||||
strlcat(base, "/bus", sizeof(base));
|
||||
|
||||
dir = opendir(base);
|
||||
if (dir != NULL) {
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char dirname[PATH_SIZE];
|
||||
DIR *dir2;
|
||||
struct dirent *dent2;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strlcpy(dirname, base, sizeof(dirname));
|
||||
strlcat(dirname, "/", sizeof(dirname));
|
||||
strlcat(dirname, dent->d_name, sizeof(dirname));
|
||||
strlcat(dirname, "/devices", sizeof(dirname));
|
||||
|
||||
/* look for devices */
|
||||
dir2 = opendir(dirname);
|
||||
if (dir2 != NULL) {
|
||||
for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
|
||||
char dirname2[PATH_SIZE];
|
||||
|
||||
if (dent2->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strlcpy(dirname2, dirname, sizeof(dirname2));
|
||||
strlcat(dirname2, "/", sizeof(dirname2));
|
||||
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
|
||||
|
||||
if (is_device(dirname2))
|
||||
device_list_insert(dirname2);
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void udev_scan_block(void)
|
||||
{
|
||||
char base[PATH_SIZE];
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
struct stat statbuf;
|
||||
|
||||
/* skip if "block" is already a "class" */
|
||||
strlcpy(base, sysfs_path, sizeof(base));
|
||||
strlcat(base, "/class/block", sizeof(base));
|
||||
if (stat(base, &statbuf) == 0)
|
||||
return;
|
||||
|
||||
strlcpy(base, sysfs_path, sizeof(base));
|
||||
strlcat(base, "/block", sizeof(base));
|
||||
|
||||
dir = opendir(base);
|
||||
if (dir != NULL) {
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char dirname[PATH_SIZE];
|
||||
DIR *dir2;
|
||||
struct dirent *dent2;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strlcpy(dirname, base, sizeof(dirname));
|
||||
strlcat(dirname, "/", sizeof(dirname));
|
||||
strlcat(dirname, dent->d_name, sizeof(dirname));
|
||||
if (is_device(dirname))
|
||||
device_list_insert(dirname);
|
||||
else
|
||||
continue;
|
||||
|
||||
/* look for partitions */
|
||||
dir2 = opendir(dirname);
|
||||
if (dir2 != NULL) {
|
||||
for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
|
||||
char dirname2[PATH_SIZE];
|
||||
|
||||
if (dent2->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!strcmp(dent2->d_name,"device"))
|
||||
continue;
|
||||
|
||||
strlcpy(dirname2, dirname, sizeof(dirname2));
|
||||
strlcat(dirname2, "/", sizeof(dirname2));
|
||||
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
|
||||
if (is_device(dirname2))
|
||||
device_list_insert(dirname2);
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void udev_scan_class(void)
|
||||
{
|
||||
char base[PATH_SIZE];
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
||||
strlcpy(base, sysfs_path, sizeof(base));
|
||||
strlcat(base, "/class", sizeof(base));
|
||||
|
||||
dir = opendir(base);
|
||||
if (dir != NULL) {
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char dirname[PATH_SIZE];
|
||||
DIR *dir2;
|
||||
struct dirent *dent2;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strlcpy(dirname, base, sizeof(dirname));
|
||||
strlcat(dirname, "/", sizeof(dirname));
|
||||
strlcat(dirname, dent->d_name, sizeof(dirname));
|
||||
dir2 = opendir(dirname);
|
||||
if (dir2 != NULL) {
|
||||
for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
|
||||
char dirname2[PATH_SIZE];
|
||||
|
||||
if (dent2->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!strcmp(dent2->d_name, "device"))
|
||||
continue;
|
||||
|
||||
strlcpy(dirname2, dirname, sizeof(dirname2));
|
||||
strlcat(dirname2, "/", sizeof(dirname2));
|
||||
strlcat(dirname2, dent2->d_name, sizeof(dirname2));
|
||||
if (is_device(dirname2))
|
||||
device_list_insert(dirname2);
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
int i;
|
||||
|
||||
logging_init("udevtrigger");
|
||||
udev_config_init();
|
||||
dbg("version %s", UDEV_VERSION);
|
||||
|
||||
udev_log_str = getenv("UDEV_LOG");
|
||||
|
||||
for (i = 1 ; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
|
||||
if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0)
|
||||
verbose = 1;
|
||||
else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0)
|
||||
dry_run = 1;
|
||||
else {
|
||||
fprintf(stderr, "Usage: udevtrigger [--verbose] [--dry-run]\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
sysfs_init();
|
||||
|
||||
udev_scan_bus();
|
||||
udev_scan_class();
|
||||
udev_scan_block();
|
||||
exec_lists();
|
||||
|
||||
sysfs_cleanup();
|
||||
exit:
|
||||
logging_close();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<article>
|
||||
<articleinfo>
|
||||
<title>xmlto</title>
|
||||
<author>
|
||||
<firstname>Kay</firstname>
|
||||
<surname>Sievers</surname>
|
||||
<email>kay.sievers@vrfy.org</email>
|
||||
</author>
|
||||
<copyright>
|
||||
<year>2006</year>
|
||||
<holder>Kay Sievers</holder>
|
||||
</copyright>
|
||||
</articleinfo>
|
||||
|
||||
<section>
|
||||
<title>udevtrigger</title>
|
||||
<refentry>
|
||||
<refentryinfo>
|
||||
<title>udevtrigger</title>
|
||||
<date>March 2006</date>
|
||||
<productname>udev</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>udevtrigger</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>udevtrigger</refname><refpurpose>request kernel devices events for coldplug</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>udevtrigger</command>
|
||||
<arg><option>--verbose</option></arg>
|
||||
<arg><option>--dry-run</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>DESCRIPTION</title>
|
||||
<para>Trigger kernel device uevents to replay missing events at system coldplug.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>OPTIONS</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--verbose</option></term>
|
||||
<listitem>
|
||||
<para>print out the devices found in sysfs.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>don't actually trigger the event.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>ENVIRONMENT</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>UDEV_LOG</option></term>
|
||||
<listitem>
|
||||
<para>Overrides the syslog priority specified in the config file.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>AUTHOR</title>
|
||||
<para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email> and
|
||||
Hannes Reinecke <email>hare@suse.de</email>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para><citerefentry>
|
||||
<refentrytitle>udev</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
</section>
|
||||
</article>
|
||||
Reference in New Issue
Block a user