From: Kay Sievers Date: Sun, 5 Jun 2005 02:44:07 +0000 (+0200) Subject: udevd: add initsend X-Git-Tag: 059~13^2~21 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=0590abd720f0ddc8204539feef4df8987d7a1f8c;ds=sidebyside udevd: add initsend Transfer stored events from initramfs to the running udevd to replay events after userspace is ready. Signed-off-by: Kay Sievers --- diff --git a/Makefile b/Makefile index 896a58a30..2a832f705 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ V=false ROOT = udev DAEMON = udevd SENDER = udevsend +INITSENDER = udevinitsend CONTROL = udevcontrol INFO = udevinfo TESTER = udevtest @@ -206,7 +207,7 @@ endif # config files automatically generated GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf -all: $(ROOT) $(SENDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) +all: $(ROOT) $(SENDER) $(INITSENDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ $(MAKE) prefix=$(prefix) \ @@ -264,16 +265,17 @@ GEN_MANPAGESIN = udev.8.in $(GEN_MANPAGES): $(GEN_MANPAGESIN) sed -e "s:@udevdir@:$(udevdir):" < $@.in > $@ -$(UDEV_OBJS): $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(SYSFS_OBJS): $(HOST_PROGS) $(KLCC) -$(OBJS): $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(ROOT).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(TESTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(INFO).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(DAEMON).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(SENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(CONTROL).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) -$(STARTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(UDEV_OBJS): $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(SYSFS_OBJS): $(HEADERS) $(HOST_PROGS) $(KLCC) +$(OBJS): $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(ROOT).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(TESTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(INFO).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(DAEMON).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(SENDER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(INITSENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(CONTROL).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC) +$(STARTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(ROOT): $(KLCC) $(ROOT).o $(OBJS) $(HEADERS) $(GEN_MANPAGES) $(QUIET) $(LD) $(LDFLAGS) -o $@ $(ROOT).o $(OBJS) $(LIB_OBJS) @@ -295,6 +297,10 @@ $(SENDER): $(KLCC) $(SENDER).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(SENDER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ +$(INITSENDER): $(KLCC) $(INITSENDER).o $(OBJS) udevd.h + $(QUIET) $(LD) $(LDFLAGS) -o $@ $(INITSENDER).o $(OBJS) $(LIB_OBJS) + $(QUIET) $(STRIPCMD) $@ + $(CONTROL): $(KLCC) $(CONTROL).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CONTROL).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ @@ -310,7 +316,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) $(CONTROL) $(TESTER) $(STARTER) + $(SENDER) $(INITSENDER) $(CONTROL) $(TESTER) $(STARTER) -rm -f ccdv $(MAKE) -C klibc SUBDIRS=klibc clean @extras="$(EXTRAS)" ; for target in $$extras ; do \ @@ -370,6 +376,7 @@ install: install-config install-man install-dev.d all $(INSTALL_PROGRAM) -D $(ROOT) $(DESTDIR)$(sbindir)/$(ROOT) $(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON) $(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER) + $(INSTALL_PROGRAM) -D $(INITSENDER) $(DESTDIR)$(sbindir)/$(INITSENDER) $(INSTALL_PROGRAM) -D $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL) $(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO) $(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER) @@ -394,6 +401,7 @@ uninstall: uninstall-man uninstall-dev.d - rm $(sbindir)/$(ROOT) - rm $(sbindir)/$(DAEMON) - rm $(sbindir)/$(SENDER) + - rm $(sbindir)/$(INITSENDER) - rm $(sbindir)/$(CONTROL) - rm $(sbindir)/$(STARTER) - rm $(usrbindir)/$(INFO) diff --git a/udev.8.in b/udev.8.in index 5be9308af..79c4a83d1 100644 --- a/udev.8.in +++ b/udev.8.in @@ -158,7 +158,8 @@ The following keys can get values assigned: .TP .B NAME The name of the node to be created, or the name, the network interface -should be renamed to. +should be renamed to. Only one rule can set the a name, all later rules +with a NAME key will be ignored. .TP .B SYMLINK The name of a symlink targeting the node. Every matching rule can add diff --git a/udevinitsend.c b/udevinitsend.c new file mode 100644 index 000000000..05c39b99b --- /dev/null +++ b/udevinitsend.c @@ -0,0 +1,231 @@ +/* + * udevinitsend.c + * + * Userspace devfs + * + * Copyright (C) 2004, 2005 Hannes Reinecke + * + * 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 +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev_version.h" +#include "udevd.h" +#include "logging.h" + + +#ifdef USE_LOG +void log_message (int level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsyslog(level, format, args); + va_end(args); +} +#endif + +/* + * udevsend + * + * Scan a file, write all variables into the msgbuf and + * fires the message to udevd. + */ +static int udevsend(char *filename, int sock, int ignore_loops) +{ + struct stat statbuf; + int fd, bufpos; + char *fdmap, *ls, *le, *ch; + struct udevd_msg usend_msg; + int retval = 0; + int usend_msg_len; + struct sockaddr_un saddr; + socklen_t addrlen; + + if (stat(filename,&statbuf) < 0) { + dbg("cannot stat %s: %s\n", filename, strerror(errno)); + return 1; + } + fd = open(filename,O_RDONLY); + if (fd < 0) + return 1; + + fdmap = mmap(0, statbuf.st_size, + PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (fdmap == MAP_FAILED) { + dbg("mmap failed, errno %d\n", errno); + return 1; + } + + 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; + + memset(usend_msg.envbuf, 0, UEVENT_BUFFER_SIZE+256); + bufpos = 0; + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); + strcpy(usend_msg.magic, UDEV_MAGIC); + + ls = fdmap; + ch = le = ls; + while (*ch && ch < fdmap + statbuf.st_size) { + le = strchr(ch,'\n'); + if (!le) + break; + ch = strchr(ch,'='); + if (!ch) + break; + + /* prevent loops in the scripts we execute */ + if (strncmp(ls, "UDEVD_EVENT=", 12) == 0) { + if (!ignore_loops) { + dbg("event already handled by udev\n"); + retval = -1; + break; + } + goto loop_end; + } + + /* omit shell-generated keys */ + if (ls[0] == '_' && ls[1] == '=') { + goto loop_end; + } + + if (ch < le) { + + strncpy(&usend_msg.envbuf[bufpos],ls,(ch - ls) + 1); + bufpos += (ch - ls) + 1; + if (ch[1] == '\'' && le[-1] == '\'') { + strncpy(&usend_msg.envbuf[bufpos],ch + 2, (le - ch) -3); + bufpos += (le - ch) - 3; + } else { + strncpy(&usend_msg.envbuf[bufpos],ch, (le - ch)); + bufpos += (le - ch); + } + bufpos++; + } +loop_end: + ch = le + 1; + ls = ch; + } + munmap(fdmap, statbuf.st_size); + + usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos; + dbg("usend_msg_len=%i", usend_msg_len); + + if (!retval) { + retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen); + if (retval < 0) { + dbg("error sending message (%s)", strerror(errno)); + } + } + + return retval; +} + +int main(int argc, char *argv[], char *envp[]) +{ + static const char short_options[] = "d:f:lVh"; + int option; + char *event_dir = NULL; + char *event_file = NULL; + DIR *dirstream; + struct dirent *direntry; + int retval = 1, ignore_loops = 0; + int sock; + + logging_init("udevinitsend"); + dbg("version %s", UDEV_VERSION); + + /* get command line options */ + while (1) { + option = getopt(argc, argv, short_options); + if (option == -1) + break; + + dbg("option '%c': ", option); + switch (option) { + case 'd': + dbg("scan directory %s\n", optarg); + event_dir = optarg; + break; + + case 'f': + dbg("use event file %s\n", optarg); + event_file = optarg; + break; + + case 'l': + dbg("ignoring loops\n"); + ignore_loops = 1; + break; + + case 'V': + printf("udevinitsend, version 0.1\n"); + return 0; + + case 'h': + retval = 0; + } + } + + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sock == -1) { + dbg("error getting socket"); + return 1; + } + + if (event_dir) { + dirstream = opendir(event_dir); + if (!dirstream) { + info("error opening directory %s: %s\n", + event_dir, strerror(errno)); + return 1; + } + chdir(event_dir); + while ((direntry = readdir(dirstream)) != NULL) { + if (!strcmp(direntry->d_name,".") || + !strcmp(direntry->d_name,"..")) + continue; + retval = udevsend(direntry->d_name, sock, ignore_loops); + } + closedir(dirstream); + } else if (event_file) { + retval = udevsend(event_file, sock, ignore_loops); + } + + if (sock != -1) + close(sock); + + return retval; +}