From: Kay Sievers <kay.sievers@vrfy.org>
To: linux-hotplug@vger.kernel.org
Subject: udevsynthesize as a udevstart+coldplug replacement
Date: Tue, 23 Aug 2005 19:15:42 +0000 [thread overview]
Message-ID: <20050823191542.GA29091@vrfy.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 1132 bytes --]
Here is "udevsynthesize" a possible replacement for the udevstart/coldplug
combination we currently have. Usually very early in the boot process, it
gets all available devices from sysfs and synthesizes the events these
devices would have generated at creation time.
The events are directly passed to the udevd daemom socket. udevd does all the
work and runs all the events asynchronously. udevsynthesize itself does
not read any udev rule.
It scans block and class devices to create the the device nodes for already
available devices, which obsoletes the run of udevstart.
After that, it scans for bus devices, which events may load modules or
configure the device. If the bus type is known, the usual bus-specific
values are added to the event environment.
With the "rules-in-daemon" patch, the whole udevstart/coldplug handling
(700 events) takes less than a second CPU time on a 1.7Ghz laptop.
A typical boot script would do:
prepare tmpfs on /dev
create /dev/null
start /sbin/udevd
disable /proc/sys/kernel/hotplug (the input layer is still broken and needs a kernel patch)
run /sbin/udevsynthesize
Have fun,
Kay
[-- Attachment #2: udev-synthesize-01.patch --]
[-- Type: text/plain, Size: 20424 bytes --]
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,8 @@ MONITOR = udevmonitor
INFO = udevinfo
TESTER = udevtest
STARTER = udevstart
+SYTHESIZER = udevsynthesize
+
RELEASE_NAME = $(ROOT)-$(VERSION)
LOCAL_CFG_DIR = etc/udev
DESTDIR =
@@ -209,7 +211,7 @@ endif
GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf
all: $(ROOT) $(SENDER) $(COMPILE) $(INITSENDER) $(RECORDER) $(CONTROL) $(MONITOR)\
- $(DAEMON) $(COMPILE) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC)
+ $(DAEMON) $(COMPILE) $(INFO) $(TESTER) $(STARTER) $(SYTHESIZER) $(GEN_CONFIGS) $(KLCC)
@extras="$(EXTRAS)" ; for target in $$extras ; do \
echo $$target ; \
$(MAKE) prefix=$(prefix) \
@@ -281,6 +283,7 @@ $(RECORDER).o: $(GEN_HEADERS) $(HOST_PRO
$(CONTROL).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(MONITOR).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(STARTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
+$(SYTHESIZER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(ROOT): $(KLCC) $(ROOT).o $(OBJS) $(HEADERS) $(GEN_MANPAGES)
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(ROOT).o $(OBJS) $(LIB_OBJS)
@@ -326,6 +329,10 @@ $(STARTER): $(KLCC) $(STARTER).o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(STARTER).o $(OBJS) $(LIB_OBJS)
$(QUIET) $(STRIPCMD) $@
+$(SYTHESIZER): $(KLCC) $(SYTHESIZER).o $(OBJS)
+ $(QUIET) $(LD) $(LDFLAGS) -o $@ $(SYTHESIZER).o $(OBJS) $(LIB_OBJS)
+ $(QUIET) $(STRIPCMD) $@
+
.c.o:
$(QUIET) $(CC) $(CFLAGS) -c -o $@ $<
@@ -333,7 +340,7 @@ clean:
-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
| xargs rm -f
-rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(GEN_MANPAGES) $(INFO) $(DAEMON) \
- $(SENDER) $(COMPILE) $(INITSENDER) $(RECORDER) $(CONTROL) $(MONITOR) $(TESTER) $(STARTER)
+ $(SENDER) $(COMPILE) $(INITSENDER) $(RECORDER) $(CONTROL) $(MONITOR) $(TESTER) $(STARTER) $(SYTHESIZER)
-rm -f ccdv
$(MAKE) -C klibc SUBDIRS=klibc clean
@extras="$(EXTRAS)" ; for target in $$extras ; do \
diff --git a/udevsynthesize.c b/udevsynthesize.c
new file mode 100644
--- /dev/null
+++ b/udevsynthesize.c
@@ -0,0 +1,708 @@
+/*
+ * udevsynthesize.c
+ *
+ * Copyright (C) 2005 SUSE Linux Products GmbH
+ *
+ * Author:
+ * Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * Synthesize kernel events from sysfs information and pass them
+ * to the udevd daemon.
+ *
+ * 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 <ctype.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <signal.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev_libc_wrapper.h"
+#include "udev.h"
+#include "udevd.h"
+#include "udev_version.h"
+#include "logging.h"
+#include "udev_utils.h"
+#include "list.h"
+
+#ifndef DT_DIR
+#define DT_DIR 4
+#endif
+
+static const char *udev_log_str;
+static int udevd_sock = -1;
+
+#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
+
+struct device {
+ struct list_head node;
+ struct udevd_msg msg;
+ size_t bufpos;
+ char *path;
+};
+
+static dev_t read_devt(const char *path)
+{
+ char filename[PATH_SIZE];
+ char majorminor[64];
+ unsigned int major, minor;
+ ssize_t count;
+ int fd;
+
+ snprintf(filename, sizeof(filename), "%s/%s", path, "dev");
+ filename[sizeof(filename)-1] = '\0';
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ count = read(fd, majorminor, sizeof(majorminor));
+ close(fd);
+ majorminor[count] = '\0';
+ if (sscanf(majorminor, "%u:%u", &major, &minor) != 2)
+ return 0;
+ dbg("found major=%d, minor=%d", major, minor);
+
+ return makedev(major, minor);
+}
+
+static ssize_t read_file(const char *directory, const char *file, char *str, size_t len)
+{
+ char filename[PATH_SIZE];
+ ssize_t count;
+ int fd;
+
+ memset(filename, 0, sizeof(filename));
+ snprintf(filename, sizeof(filename), "%s/%s", directory, file);
+ filename[sizeof(filename)-1] = '\0';
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ count = read(fd, str, len-1);
+ close(fd);
+
+ if (count > (ssize_t)len)
+ count = len;
+ str[count-1] = '\0';
+
+ return count;
+}
+
+static ssize_t read_link(const char *directory, const char *file, char *str, size_t size)
+{
+ char filename[PATH_SIZE];
+ char target[PATH_SIZE];
+ int len;
+ char *back;
+ char *strip;
+ int level = 1;
+
+ snprintf(filename, sizeof(filename), "%s/%s", directory, file);
+ filename[sizeof(filename)-1] = '\0';
+
+ len = readlink(filename, target, sizeof(target)-1);
+ if (len < 0)
+ return -1;
+ target[len] = '\0';
+
+ back = target;
+ while (strncmp(back, "../", 3) == 0) {
+ back += 3;
+ level++;
+ }
+ while(level--) {
+ strip = strrchr(filename, '/');
+ if (!strip)
+ return -1;
+ strip[0] = '\0';
+ }
+
+ snprintf(str, size, "%s/%s", filename, back);
+ str[size-1] = '\0';
+
+ return len;
+}
+
+static char *add_env_key(struct device *device, const char *key, const char *value)
+{
+ size_t pos = device->bufpos;
+ device->bufpos += sprintf(&device->msg.envbuf[device->bufpos], "%s=%s", key, value)+1;
+ return &device->msg.envbuf[pos];
+}
+
+static struct device *device_create(const char *path, const char *subsystem, dev_t devt)
+{
+ struct device *device;
+ const char *devpath = &path[strlen(sysfs_path)];
+ char target[PATH_SIZE];
+
+ device = malloc(sizeof(struct device));
+ if (device == NULL) {
+ dbg("error malloc");
+ return NULL;
+ }
+ memset(device, 0x00, sizeof(struct device));
+
+ device->path = add_env_key(device, "DEVPATH", devpath);
+ device->path += strlen("DEVPATH=");
+ add_env_key(device, "SUBSYSTEM", subsystem);
+ add_env_key(device, "ACTION", "add");
+ add_env_key(device, "UDEV_SYNTHESIZE", "1");
+
+ if (major(devt)) {
+ char number[32];
+ sprintf(number, "%u", major(devt));
+ add_env_key(device, "MAJOR", number);
+ sprintf(number, "%u", minor(devt));
+ add_env_key(device, "MINOR", number);
+ }
+
+ if (strncmp(devpath, "/block/", strlen("/block/")) == 0 ||
+ strncmp(devpath, "/class/", strlen("/class/")) == 0) {
+ char physpath[PATH_SIZE];
+
+ if (read_link(path, "device", physpath, sizeof(physpath)) > (ssize_t)strlen(sysfs_path)) {
+ add_env_key(device, "PHYSDEVPATH", &physpath[strlen(sysfs_path)]);
+ if (read_link(physpath, "driver", target, sizeof(target)) > (ssize_t)strlen(sysfs_path)) {
+ char *pos = strrchr(target, '/');
+ if (pos)
+ add_env_key(device, "PHYSDEVDRIVER", &pos[1]);
+ }
+ if (read_link(physpath, "bus", target, sizeof(target)) > (ssize_t)strlen(sysfs_path)) {
+ char *pos = strrchr(target, '/');
+ if (pos)
+ add_env_key(device, "PHYSDEVBUS", &pos[1]);
+ }
+ }
+ } else if (strncmp(devpath, "/devices/", strlen("/devices/")) == 0) {
+ if (read_link(path, "driver", target, sizeof(target)) > (ssize_t)strlen(sysfs_path)) {
+ char *pos = strrchr(target, '/');
+ if (pos)
+ add_env_key(device, "PHYSDEVDRIVER", &pos[1]);
+ }
+ if (read_link(path, "bus", target, sizeof(target)) > (ssize_t)strlen(sysfs_path)) {
+ char *pos = strrchr(target, '/');
+ if (pos)
+ add_env_key(device, "PHYSDEVBUS", &pos[1]);
+ }
+ }
+
+ return device;
+}
+
+static int device_list_insert(struct list_head *device_list, struct device *device)
+{
+ struct device *loop_device;
+
+ dbg("insert: '%s'", device->path);
+
+ /* sort files in lexical order */
+ list_for_each_entry(loop_device, device_list, node)
+ if (strcmp(loop_device->path, device->path) > 0)
+ break;
+
+ list_add_tail(&device->node, &loop_device->node);
+
+ return 0;
+}
+
+static int add_device_udevd(struct device *device)
+{
+ size_t msg_len;
+ struct sockaddr_un saddr;
+ socklen_t addrlen;
+ int retval;
+
+ memset(&saddr, 0x00, sizeof(struct sockaddr_un));
+ saddr.sun_family = AF_LOCAL;
+ /* use abstract namespace for socket path */
+ strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+
+ strcpy(device->msg.magic, UDEV_MAGIC);
+ device->msg.type = UDEVD_UEVENT_UDEVSEND;
+
+ msg_len = offsetof(struct udevd_msg, envbuf) + device->bufpos;
+ dbg("msg_len=%i", msg_len);
+
+ retval = sendto(udevd_sock, &device->msg, msg_len, 0, (struct sockaddr *)&saddr, addrlen);
+ if (retval < 0)
+ return -1;
+
+ return 0;
+}
+
+static void exec_list(struct list_head *device_list, const char *first[], const char *last[])
+{
+ struct device *loop_device;
+ struct device *tmp_device;
+ int i;
+
+ /* handle the "first" type devices first */
+ if (first)
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ for (i = 0; first[i] != NULL; i++) {
+ if (strncmp(loop_device->path, first[i], strlen(first[i])) == 0) {
+ add_device_udevd(loop_device);
+ list_del(&loop_device->node);
+ free(loop_device);
+ break;
+ }
+ }
+ }
+
+ /* handle the devices we are allowed to, excluding the "last" type devices */
+ if (last)
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ int found = 0;
+ for (i = 0; last[i] != NULL; i++) {
+ if (strncmp(loop_device->path, last[i], strlen(last[i])) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ add_device_udevd(loop_device);
+ list_del(&loop_device->node);
+ free(loop_device);
+ }
+
+ /* handle the rest of the devices */
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ add_device_udevd(loop_device);
+ list_del(&loop_device->node);
+ free(loop_device);
+ }
+}
+
+static int udev_scan_class(void)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+ LIST_HEAD(device_list);
+
+ /* we want /dev/null and /dev/console first */
+ const char *first[] = {
+ "/class/mem",
+ "/class/tty",
+ NULL,
+ };
+
+ snprintf(base, sizeof(base), "%s/class", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (!dir)
+ return -1;
+
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[PATH_SIZE];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
+ dirname[sizeof(dirname)-1] = '\0';
+
+ dir2 = opendir(dirname);
+ if (!dir2)
+ continue;
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[PATH_SIZE];
+ struct device *device;
+ dev_t devt;
+
+ if (dent2->d_name[0] == '.')
+ continue;
+ if (dent2->d_type != DT_DIR)
+ continue;
+
+ snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
+ dirname2[sizeof(dirname2)-1] = '\0';
+ devt = read_devt(dirname2);
+ device = device_create(dirname2, dent->d_name, devt);
+ device_list_insert(&device_list, device);
+ }
+ closedir(dir2);
+ }
+ closedir(dir);
+ exec_list(&device_list, first, NULL);
+
+ return 0;
+}
+
+static int udev_scan_block(void)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+ LIST_HEAD(device_list);
+
+ /* dm wants to have the block devices around before it */
+ const char *last[] = {
+ "/block/dm",
+ NULL,
+ };
+
+ snprintf(base, sizeof(base), "%s/block", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (!dir)
+ return -1;
+
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[PATH_SIZE];
+ struct device *device;
+ struct dirent *dent2;
+ DIR *dir2;
+ dev_t devt;
+
+ if (dent->d_name[0] == '.')
+ continue;
+ if (dent->d_type != DT_DIR)
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
+ dirname[sizeof(dirname)-1] = '\0';
+ devt = read_devt(dirname);
+ if (major(devt)) {
+ device = device_create(dirname, "block", devt);
+ device_list_insert(&device_list, device);
+ }
+
+ /* look for partitions */
+ dir2 = opendir(dirname);
+ if (!dir2)
+ continue;
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[PATH_SIZE];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+ if (dent2->d_type != DT_DIR)
+ continue;
+
+ snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
+ dirname2[sizeof(dirname2)-1] = '\0';
+ devt = read_devt(dirname2);
+ if (major(devt)) {
+ device = device_create(dirname2, "block", devt);
+ device_list_insert(&device_list, device);
+ continue;
+ }
+ }
+ closedir(dir2);
+ }
+ closedir(dir);
+ exec_list(&device_list, NULL, last);
+
+ return 0;
+}
+
+static int pci_handler(struct device *device)
+{
+ char path[PATH_SIZE];
+ char value[PATH_SIZE];
+ char vendor[PATH_SIZE];
+ char product[PATH_SIZE];
+ const char *name;
+
+ snprintf(path, sizeof(path), "%s%s", sysfs_path, device->path);
+ path[sizeof(path)-1] = '\0';
+
+ if (read_file(path, "modalias", value, sizeof(value)) < 5)
+ return -1;
+ add_env_key(device, "MODALIAS", value);
+
+ name = strrchr(device->path, '/');
+ if (name)
+ add_env_key(device, "PCI_SLOT_NAME", &name[1]);
+
+ if (read_file(path, "class", value, sizeof(value)) > 0)
+ add_env_key(device, "PCI_CLASS", &value[2]);
+
+ if (read_file(path, "vendor", vendor, sizeof(vendor)) > 0 &&
+ read_file(path, "device", product, sizeof(product)) > 0) {
+ snprintf(value, sizeof(value), "%s:%s", &vendor[2], &product[2]);
+ path[sizeof(value)-1] = '\0';
+ add_env_key(device, "PCI_ID", value);
+ }
+
+ if (read_file(path, "subsystem_vendor", vendor, sizeof(vendor)) > 0 &&
+ read_file(path, "subsystem_device", product, sizeof(product)) > 0) {
+ snprintf(value, sizeof(value), "%s:%s", &vendor[2], &product[2]);
+ path[sizeof(value)-1] = '\0';
+ add_env_key(device, "PCI_SUBSYS_ID", value);
+ }
+
+ return 0;
+}
+
+static int usb_handler(struct device *device)
+{
+ char path[PATH_SIZE];
+ char value[PATH_SIZE];
+ char str1[PATH_SIZE];
+ char str2[PATH_SIZE];
+ char str3[PATH_SIZE];
+ unsigned int int1;
+ unsigned int int2;
+ unsigned int int3;
+ char *pos;
+
+ snprintf(path, sizeof(path), "%s%s", sysfs_path, device->path);
+ path[sizeof(path)-1] = '\0';
+
+ if (read_file(path, "modalias", value, sizeof(value)) < 5)
+ return -1;
+ add_env_key(device, "MODALIAS", value);
+
+ if (read_file(path, "bInterfaceClass", str1, sizeof(str1)) > 0 &&
+ read_file(path, "bInterfaceSubClass", str2, sizeof(str2)) > 0 &&
+ read_file(path, "bInterfaceProtocol", str3, sizeof(str3)) > 0) {
+ int1 = (int) strtol(str1, NULL, 16);
+ int2 = (int) strtol(str2, NULL, 16);
+ int3 = (int) strtol(str3, NULL, 16);
+ snprintf(value, sizeof(value), "%u/%u/%u", int1, int2, int3);
+ path[sizeof(value)-1] = '\0';
+ add_env_key(device, "INTERFACE", value);
+ }
+
+ pos = strrchr(path, '/');
+ pos[0] = '\0';
+
+ if (read_file(path, "idVendor", str1, sizeof(str1)) > 0 &&
+ read_file(path, "idProduct", str2, sizeof(str2)) > 0 &&
+ read_file(path, "bcdDevice", str3, sizeof(str3)) > 0) {
+ int1 = (int) strtol(str1, NULL, 16);
+ int2 = (int) strtol(str2, NULL, 16);
+ int3 = (int) strtol(str3, NULL, 16);
+ snprintf(value, sizeof(value), "%x/%x/%x", int1, int2, int3);
+ path[sizeof(value)-1] = '\0';
+ add_env_key(device, "PRODUCT", value);
+ }
+
+ if (read_file(path, "bDeviceClass", str1, sizeof(str1)) > 0 &&
+ read_file(path, "bDeviceSubClass", str2, sizeof(str2)) > 0 &&
+ read_file(path, "bDeviceProtocol", str3, sizeof(str3)) > 0) {
+ int1 = (int) strtol(str1, NULL, 16);
+ int2 = (int) strtol(str2, NULL, 16);
+ int3 = (int) strtol(str3, NULL, 16);
+ snprintf(value, sizeof(value), "%u/%u/%u", int1, int2, int3);
+ path[sizeof(value)-1] = '\0';
+ add_env_key(device, "TYPE", value);
+ }
+
+ return 0;
+}
+
+static int serio_handler(struct device *device)
+{
+ char path[PATH_SIZE];
+ char value[PATH_SIZE];
+
+ snprintf(path, sizeof(path), "%s%s", sysfs_path, device->path);
+ path[sizeof(path)-1] = '\0';
+
+ if (read_file(path, "modalias", value, sizeof(value)) < 5)
+ return -1;
+ add_env_key(device, "MODALIAS", value);
+
+ if (read_file(path, "id/type", value, sizeof(value)) > 0)
+ add_env_key(device, "SERIO_TYPE", value);
+
+ if (read_file(path, "id/proto", value, sizeof(value)) > 0)
+ add_env_key(device, "SERIO_PROTO", value);
+
+ if (read_file(path, "id/id", value, sizeof(value)) > 0)
+ add_env_key(device, "SERIO_ID", value);
+
+ if (read_file(path, "id/extra", value, sizeof(value)) > 0)
+ add_env_key(device, "SERIO_EXTRA", value);
+
+ return 0;
+}
+
+static int modalias_handler(struct device *device)
+{
+ char path[PATH_SIZE];
+ char value[PATH_SIZE];
+
+ snprintf(path, sizeof(path), "%s%s", sysfs_path, device->path);
+ path[sizeof(path)-1] = '\0';
+
+ if (read_file(path, "modalias", value, sizeof(value)) < 5)
+ return -1;
+ add_env_key(device, "MODALIAS", value);
+
+ return 0;
+}
+
+static int udev_scan_bus(const char *bus, int bus_handler(struct device *device))
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+ LIST_HEAD(device_list);
+
+ snprintf(base, sizeof(base), "%s/bus/%s/devices", sysfs_path, bus);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (!dir)
+ return -1;
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char devpath[PATH_SIZE];
+ struct device *device;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (read_link(base, dent->d_name, devpath, sizeof(devpath)) < 0)
+ continue;
+
+ device = device_create(devpath, bus, makedev(0, 0));
+ if (bus_handler) {
+ if (bus_handler(device) < 0) {
+ dbg("'%s' bus handler skipped event", devpath);
+ free(device);
+ continue;
+ }
+ }
+
+ device_list_insert(&device_list, device);
+ }
+ closedir(dir);
+ exec_list(&device_list, NULL, NULL);
+
+ return 0;
+}
+
+static int udev_scan_devices(void)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+
+ snprintf(base, sizeof(base), "%s/bus", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (!dir)
+ return -1;
+
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ if (dent->d_name[0] == '.')
+ continue;
+ if (dent->d_type != DT_DIR)
+ continue;
+
+ /* add bus specific env values */
+ if (strcmp(dent->d_name, "pci") == 0)
+ udev_scan_bus("pci", pci_handler);
+ else if (strcmp(dent->d_name, "usb") == 0)
+ udev_scan_bus("usb", usb_handler);
+ else if (strcmp(dent->d_name, "serio") == 0)
+ udev_scan_bus("serio", serio_handler);
+ else if (strcmp(dent->d_name, "pcmcia") == 0)
+ udev_scan_bus("pcmcia", modalias_handler);
+ else
+ udev_scan_bus(dent->d_name, NULL);
+ }
+ closedir(dir);
+
+ return 0;
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ LIST_HEAD(device_list);
+ int i;
+
+ logging_init("udevsynthesize");
+ udev_init_config();
+ dbg("version %s", UDEV_VERSION);
+
+ udev_log_str = getenv("UDEV_LOG");
+
+ /* disable all logging if not explicitely requested */
+ if (udev_log_str == NULL)
+ udev_log_priority = 0;
+
+ for (i = 1 ; i < argc; i++) {
+ char *arg = argv[i];
+
+ if (strcmp(arg, "help") == 0 || strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
+ printf("Usage: udevsynthesize \n"
+ " --help print this help text\n\n");
+ exit(0);
+ } else {
+ fprintf(stderr, "unknown option\n\n");
+ exit(1);
+ }
+ }
+
+ udevd_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (udevd_sock < 0) {
+ err("error getting socket");
+ return 1;
+ }
+
+ /* create nodes for already available devices */
+ udev_scan_class();
+ udev_scan_block();
+
+ /* synthesize events for bus devices
+ * may load modules or configure the device */
+ udev_scan_devices();
+
+ if (udevd_sock >= 0)
+ close(udevd_sock);
+ logging_close();
+
+ return 0;
+}
next reply other threads:[~2005-08-23 19:15 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-08-23 19:15 Kay Sievers [this message]
2005-08-23 19:46 ` udevsynthesize as a udevstart+coldplug replacement Mika Penttilä
2005-08-23 20:03 ` Kay Sievers
2005-08-23 20:09 ` Mika Penttilä
2005-08-23 20:47 ` Per Svennerbrandt
2005-08-24 3:50 ` Alexander E. Patrakov
2005-08-24 9:29 ` Marco d'Itri
2005-08-24 9:31 ` Marco d'Itri
2005-08-24 11:14 ` Olivier Blin
2005-08-24 19:37 ` Kay Sievers
2005-08-24 19:52 ` Olivier Blin
2005-08-24 20:05 ` Kay Sievers
2005-08-24 20:09 ` Kay Sievers
2005-08-24 20:18 ` Marco d'Itri
2005-08-24 20:18 ` Thierry Vignaud
2005-08-24 20:24 ` Kay Sievers
2005-08-24 20:27 ` Kay Sievers
2005-08-24 20:36 ` Kay Sievers
2005-08-24 20:40 ` Marco d'Itri
2005-08-24 20:42 ` Olivier Blin
2005-08-24 21:19 ` Thierry Vignaud
2005-08-25 6:43 ` Christian Zoz
2005-08-25 8:24 ` Marco d'Itri
2005-08-25 10:31 ` Christian Zoz
2005-08-25 10:36 ` Marco d'Itri
2005-08-25 18:20 ` Bill Nottingham
2005-08-25 18:33 ` Marco d'Itri
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050823191542.GA29091@vrfy.org \
--to=kay.sievers@vrfy.org \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).