diff --git a/Makefile b/Makefile index c315d099ef3..e2c7e429882 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ DAEMON = udevd SENDER = udevsend HELPER = udevinfo TESTER = udevtest +STARTER = udevstart VERSION = 019_bk INSTALL_DIR = /usr/local/bin RELEASE_NAME = $(ROOT)-$(VERSION) @@ -172,7 +173,7 @@ endif CFLAGS += -I$(PWD)/libsysfs -all: $(ROOT) $(SENDER) $(DAEMON) $(HELPER) $(TESTER) +all: $(ROOT) $(SENDER) $(DAEMON) $(HELPER) $(TESTER) $(STARTER) @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ $(MAKE) prefix=$(prefix) \ @@ -265,6 +266,7 @@ $(TESTER).o: $(GEN_HEADERS) $(HELPER).o: $(GEN_HEADERS) $(DAEMON).o: $(GEN_HEADERS) $(SENDER).o: $(GEN_HEADERS) +$(STARTER).o: $(GEN_HEADERS) $(ROOT): $(ROOT).o $(OBJS) $(HEADERS) $(LIBC) $(LD) $(LDFLAGS) -o $@ $(CRT0) udev.o $(OBJS) $(LIB_OBJS) $(ARCH_LIB_OBJS) @@ -286,10 +288,14 @@ $(SENDER): $(SENDER).o udevd.h $(LIBC) $(LD) $(LDFLAGS) -o $@ $(CRT0) udevsend.o $(LIB_OBJS) $(ARCH_LIB_OBJS) $(STRIPCMD) $@ +$(STARTER): $(STARTER).o $(HEADERS) $(LIBC) + $(LD) $(LDFLAGS) -o $@ $(CRT0) udevstart.o $(LIB_OBJS) $(ARCH_LIB_OBJS) + $(STRIPCMD) $@ + clean: -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | xargs rm -f - -rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(HELPER) $(DAEMON) $(SENDER) $(TESTER) + -rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(HELPER) $(DAEMON) $(SENDER) $(TESTER) $(STARTER) $(MAKE) -C klibc clean @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ diff --git a/udevstart.c b/udevstart.c new file mode 100644 index 00000000000..867919972ad --- /dev/null +++ b/udevstart.c @@ -0,0 +1,247 @@ +/* + * udevstart.c + * + * Copyright (C) 2004 Greg Kroah-Hartman + * + * Quick and dirty way to populate a /dev with udev if your system + * does not have access to a shell. Based originally on a patch to udev + * from Harald Hoyer + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "logging.h" + + +#ifdef LOG +unsigned char logname[42]; +void log_message(int level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsyslog(level, format, args); + va_end(args); +} +#endif + + +#define MAX_PATHLEN 1024 +#define SYSBLOCK "/sys/block" +#define SYSCLASS "/sys/class" + +static int execute_udev(char *path, char *value, int len) +{ + int retval; + int res; + int status; + int fds[2]; + pid_t pid; + int value_set = 0; + char buffer[255]; + char *pos; + + retval = pipe(fds); + if (retval != 0) { + dbg("pipe failed"); + return -1; + } + pid = fork(); + switch(pid) { + case 0: + /* child */ + close(STDOUT_FILENO); + + /* dup write side of pipe to STDOUT */ + dup(fds[1]); + + dbg("executing /sbin/udev '%s'", path); + retval = execl("/sbin/udev", "/sbin/udev", path, NULL); + + info("execution of '%s' failed", path); + exit(1); + case -1: + dbg("fork failed"); + return -1; + default: + /* parent reads from fds[0] */ + close(fds[1]); + retval = 0; + while (1) { + res = read(fds[0], buffer, sizeof(buffer) - 1); + if (res <= 0) + break; + buffer[res] = '\0'; + if (res > len) { + dbg("result len %d too short", len); + retval = -1; + } + if (value_set) { + dbg("result value already set"); + retval = -1; + } else { + value_set = 1; + strncpy(value, buffer, len); + pos = value + strlen(value)-1; + if (pos[0] == '\n') + pos[0] = '\0'; + dbg("result is '%s'", value); + } + } + close(fds[0]); + res = wait(&status); + if (res < 0) { + dbg("wait failed result %d", res); + retval = -1; + } + + if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { + dbg("exec program status 0x%x", status); + retval = -1; + } + } + return retval; +} + +static int udev_scan(void) +{ + char *devpath; + DIR *dir; + struct dirent *dent; + int retval = -EINVAL; + char scratch[200]; + + devpath = "block"; + dir = opendir(SYSBLOCK); + if (dir) { + for (dent = readdir(dir); dent; dent = readdir(dir)) { + char dirname[MAX_PATHLEN]; + DIR *dir2; + struct dirent *dent2; + if ((strcmp(dent->d_name, ".") == 0) + || (strcmp(dent->d_name, "..") == 0)) + continue; + + snprintf(dirname, MAX_PATHLEN, "/block/%s", dent->d_name); + + setenv("DEVPATH", dirname, 1); + dbg("udev block, 'DEVPATH' = '%s'", dirname); + execute_udev("block", scratch, sizeof(scratch)); + + snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSBLOCK, dent->d_name); + + dir2 = opendir(dirname); + if (dir2) { + for (dent2 = readdir(dir2); dent2; dent2 = readdir(dir2)) { + char dirname2[MAX_PATHLEN]; + DIR *dir3; + struct dirent *dent3; + + if ((strcmp(dent2->d_name, ".") == 0) || + (strcmp(dent2->d_name, "..") == 0)) + continue; + + snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); + + dir3 = opendir(dirname2); + if (dir3) { + for (dent3 = readdir(dir3); dent3; dent3 = readdir(dir3)) { + char filename[MAX_PATHLEN]; + + if (strcmp(dent3->d_name, "dev") == 0) { + snprintf(filename, MAX_PATHLEN, "/block/%s/%s", dent->d_name, dent2->d_name); + setenv("DEVPATH", filename, 1); + dbg("udev block, 'DEVPATH' = '%s'", filename); + execute_udev("block", scratch, sizeof(scratch)); + } + } + } + } + } + } + } + + devpath = "class"; + dir = opendir(SYSCLASS); + if (dir) { + for (dent = readdir(dir); dent; dent = readdir(dir)) { + char dirname[MAX_PATHLEN]; + DIR *dir2; + struct dirent *dent2; + if ((strcmp(dent->d_name, ".") == 0) + || (strcmp(dent->d_name, "..") == 0)) + continue; + + snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSCLASS, dent->d_name); + + dir2 = opendir(dirname); + if (dir2) { + for (dent2 = readdir(dir2); dent2; dent2 = readdir(dir2)) { + char dirname2[MAX_PATHLEN]; + DIR *dir3; + struct dirent *dent3; + + if ((strcmp(dent2->d_name, ".") == 0) || (strcmp(dent2->d_name, "..") == 0)) + continue; + + snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); + + dir3 = opendir(dirname2); + if (dir3) { + for (dent3 = readdir(dir3); dent3; dent3 = readdir(dir3)) { + char + filename[MAX_PATHLEN]; + + if (strcmp(dent3->d_name, "dev") == 0) { + snprintf + (filename, + MAX_PATHLEN, + "/class/%s/%s", dent->d_name, dent2->d_name); + setenv("DEVPATH", filename, 1); + dbg("udev '%s', 'DEVPATH' = '%s'", dent->d_name, filename); + execute_udev(dent->d_name, scratch, sizeof(scratch)); + } + } + } + } + } + } + } + + if (retval > 0) + retval = 0; + + return -retval; +} + + +int main(int argc, char **argv, char **envp) +{ + init_logging("udevstart"); + + setenv("ACTION", "add", 1); + setenv("UDEV_NO_SLEEP", "1", 1); + + return udev_scan(); +}