From 88f4b6485e2a551de55fd9d39aeef89debf3121c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:38:10 +0200 Subject: [PATCH 01/24] udevd: listen for netlink events After the first valid netlink-event all event with a serial number received on the udevsend socket will be ignored. Signed-off-by: Kay Sievers --- udev.c | 10 ++- udevd.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 160 insertions(+), 36 deletions(-) diff --git a/udev.c b/udev.c index ce9b42f30d..2be4c35740 100644 --- a/udev.c +++ b/udev.c @@ -54,8 +54,10 @@ void log_message(int priority, const char *format, ...) } #endif -/* decide if we should manage the whole hotplug event - * for now look if the kernel calls udevsend instead of /sbin/hotplug +/* Decide if we should manage the whole uevent, including multiplexing + * of the hotplug directories. + * For now look if the kernel calls udevsend instead of /sbin/hotplug, + * or the uevent-helper in /proc/sys/kernel/hotplug is empty. */ static int manage_hotplug_event(void) { char helper[256]; @@ -70,13 +72,15 @@ static int manage_hotplug_event(void) { if (fd < 0) return 0; - len = read(fd, helper, 256); + len = read(fd, helper, sizeof(helper)-1); close(fd); if (len < 0) return 0; helper[len] = '\0'; + if (helper[0] == '\0' || helper[0] == '\n') + return 1; if (strstr(helper, "udevsend")) return 1; diff --git a/udevd.c b/udevd.c index 91033b0688..68e3a75f33 100644 --- a/udevd.c +++ b/udevd.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "list.h" #include "udev_libc_wrapper.h" @@ -49,6 +50,7 @@ /* global variables*/ static int udevsendsock; +static int ueventsock; static pid_t sid; static int pipefds[2]; @@ -126,7 +128,8 @@ static void msg_queue_insert(struct hotplug_msg *msg) break; if (loop_msg->seqnum == msg->seqnum) { - info("ignoring duplicate message seq %llu", msg->seqnum); + dbg("ignoring duplicate message seq %llu", msg->seqnum); + free(msg); return; } } @@ -154,6 +157,8 @@ static void execute_udev(struct hotplug_msg *msg) switch (pid) { case 0: /* child */ + if (ueventsock != -1) + close(ueventsock); close(udevsendsock); logging_close(); @@ -416,13 +421,60 @@ recheck: } } +static struct hotplug_msg *get_msg_from_envbuf(const char *buf, int buf_size) +{ + int bufpos; + int i; + struct hotplug_msg *msg; + + msg = malloc(sizeof(struct hotplug_msg) + buf_size); + if (msg == NULL) + return NULL; + memset(msg, 0x00, sizeof(struct hotplug_msg) + buf_size); + + /* copy environment buffer and reconstruct envp */ + memcpy(msg->envbuf, buf, buf_size); + bufpos = 0; + for (i = 0; (bufpos < buf_size) && (i < HOTPLUG_NUM_ENVP-2); i++) { + int keylen; + char *key; + + key = &msg->envbuf[bufpos]; + keylen = strlen(key); + msg->envp[i] = key; + bufpos += keylen + 1; + dbg("add '%s' to msg.envp[%i]", msg->envp[i], i); + + /* remember some keys for further processing */ + if (strncmp(key, "ACTION=", 7) == 0) + msg->action = &key[7]; + + if (strncmp(key, "DEVPATH=", 8) == 0) + msg->devpath = &key[8]; + + if (strncmp(key, "SUBSYSTEM=", 10) == 0) + msg->subsystem = &key[10]; + + if (strncmp(key, "SEQNUM=", 7) == 0) + msg->seqnum = strtoull(&key[7], NULL, 10); + + if (strncmp(key, "PHYSDEVPATH=", 12) == 0) + msg->physdevpath = &key[12]; + + if (strncmp(key, "TIMEOUT=", 8) == 0) + msg->timeout = strtoull(&key[8], NULL, 10); + } + msg->envp[i++] = "UDEVD_EVENT=1"; + msg->envp[i] = NULL; + + return msg; +} + /* receive the udevsend message and do some sanity checks */ static struct hotplug_msg *get_udevsend_msg(void) { static struct udevsend_msg usend_msg; struct hotplug_msg *msg; - int bufpos; - int i; ssize_t size; struct msghdr smsg; struct cmsghdr *cmsg; @@ -467,46 +519,60 @@ static struct hotplug_msg *get_udevsend_msg(void) envbuf_size = size - offsetof(struct udevsend_msg, envbuf); dbg("envbuf_size=%i", envbuf_size); - msg = malloc(sizeof(struct hotplug_msg) + envbuf_size); + msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); if (msg == NULL) return NULL; - memset(msg, 0x00, sizeof(struct hotplug_msg) + envbuf_size); + return msg; +} - /* copy environment buffer and reconstruct envp */ - memcpy(msg->envbuf, usend_msg.envbuf, envbuf_size); - bufpos = 0; - for (i = 0; (bufpos < envbuf_size) && (i < HOTPLUG_NUM_ENVP-2); i++) { - int keylen; - char *key; +/* receive the kernel user event message and do some sanity checks */ +static struct hotplug_msg *get_uevent_msg(void) +{ + struct hotplug_msg *msg; + int bufpos; + ssize_t size; + static char buffer[HOTPLUG_BUFFER_SIZE + 512]; + char *pos; - key = &msg->envbuf[bufpos]; - keylen = strlen(key); - msg->envp[i] = key; - bufpos += keylen + 1; - dbg("add '%s' to msg.envp[%i]", msg->envp[i], i); + size = recv(ueventsock, &buffer, sizeof(buffer), 0); + if (size < 0) { + if (errno != EINTR) + dbg("unable to receive udevsend message"); + return NULL; + } - /* remember some keys for further processing */ - if (strncmp(key, "ACTION=", 7) == 0) - msg->action = &key[7]; + if ((size_t)size > sizeof(buffer)-1) + size = sizeof(buffer)-1; + buffer[size] = '\0'; + dbg("uevent_size=%i", size); - if (strncmp(key, "DEVPATH=", 8) == 0) - msg->devpath = &key[8]; + /* start of event payload */ + bufpos = strlen(buffer)+1; + msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos); + if (msg == NULL) + return NULL; - if (strncmp(key, "SUBSYSTEM=", 10) == 0) - msg->subsystem = &key[10]; + /* validate message */ + pos = strchr(buffer, '@'); + if (pos == NULL) { + dbg("invalid uevent '%s'", buffer); + free(msg); + return NULL; + } + pos[0] = '\0'; - if (strncmp(key, "SEQNUM=", 7) == 0) - msg->seqnum = strtoull(&key[7], NULL, 10); + if (msg->action == NULL) { + dbg("no ACTION in payload found, skip event '%s'", buffer); + free(msg); + return NULL; + } - if (strncmp(key, "PHYSDEVPATH=", 12) == 0) - msg->physdevpath = &key[12]; - - if (strncmp(key, "TIMEOUT=", 8) == 0) - msg->timeout = strtoull(&key[8], NULL, 10); + if (strcmp(msg->action, buffer) != 0) { + dbg("ACTION in payload does not match uevent, skip event '%s'", buffer); + free(msg); + return NULL; } - msg->envp[i++] = "UDEVD_EVENT=1"; - msg->envp[i] = NULL; return msg; } @@ -622,6 +688,34 @@ static int init_udevsend_socket(void) return 0; } +static int init_uevent_socket(void) +{ + struct sockaddr_nl snl; + int retval; + + memset(&snl, 0x00, sizeof(struct sockaddr_nl)); + snl.nl_family = AF_NETLINK; + snl.nl_pid = getpid(); + snl.nl_groups = 0xffffffff; + + ueventsock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (ueventsock == -1) { + dbg("error getting socket, %s", strerror(errno)); + return -1; + } + + retval = bind(ueventsock, (struct sockaddr *) &snl, + sizeof(struct sockaddr_nl)); + if (retval < 0) { + dbg("bind failed, %s", strerror(errno)); + close(ueventsock); + ueventsock = -1; + return -1; + } + + return 0; +} + int main(int argc, char *argv[], char *envp[]) { struct sysinfo info; @@ -631,6 +725,7 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *udevd_expected_seqnum; + int uevent_active = 0; logging_init("udevd"); udev_init_config(); @@ -716,6 +811,10 @@ int main(int argc, char *argv[], char *envp[]) sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); + if (init_uevent_socket() < 0) { + dbg("uevent socket not available"); + } + if (init_udevsend_socket() < 0) { if (errno == EADDRINUSE) dbg("another udevd running, exit"); @@ -745,6 +844,8 @@ int main(int argc, char *argv[], char *envp[]) FD_ZERO(&readfds); FD_SET(udevsendsock, &readfds); + if (ueventsock != -1) + FD_SET(ueventsock, &readfds); FD_SET(pipefds[0], &readfds); maxsockplus = udevsendsock+1; while (1) { @@ -761,8 +862,27 @@ int main(int argc, char *argv[], char *envp[]) if (FD_ISSET(udevsendsock, &workreadfds)) { msg = get_udevsend_msg(); - if (msg) + if (msg) { + /* discard kernel messages if netlink is active */ + if (uevent_active && msg->seqnum != 0) { + dbg("skip kernel udevsend message, netlink is active"); + free(msg); + continue; + } msg_queue_insert(msg); + } + } + + if (FD_ISSET(ueventsock, &workreadfds)) { + msg = get_uevent_msg(); + if (msg) { + msg_queue_insert(msg); + /* disable udevsend with first netlink message */ + if (!uevent_active) { + info("netlink message received, disable kernel udevsend messages"); + uevent_active = 1; + } + } } if (FD_ISSET(pipefds[0], &workreadfds)) From 3b47c7394d042b8a3fcf426920a926d4ffedacad Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:41:09 +0200 Subject: [PATCH 02/24] udevd: add udevcontrol Controls the behavior of the running daemon. Currently only stopping and starting of the execution queue is supported. Signed-off-by: Kay Sievers --- Makefile | 12 +++- udevcontrol.c | 107 ++++++++++++++++++++++++++++++++ udevd.c | 167 +++++++++++++++++++++++++++----------------------- udevd.h | 23 ++++--- udevsend.c | 9 +-- 5 files changed, 230 insertions(+), 88 deletions(-) create mode 100644 udevcontrol.c diff --git a/Makefile b/Makefile index dc3930b46b..896a58a306 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ V=false ROOT = udev DAEMON = udevd SENDER = udevsend +CONTROL = udevcontrol INFO = udevinfo TESTER = udevtest STARTER = udevstart @@ -205,7 +206,7 @@ endif # config files automatically generated GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf -all: $(ROOT) $(SENDER) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) +all: $(ROOT) $(SENDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ $(MAKE) prefix=$(prefix) \ @@ -271,6 +272,7 @@ $(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) $(ROOT): $(KLCC) $(ROOT).o $(OBJS) $(HEADERS) $(GEN_MANPAGES) @@ -293,6 +295,10 @@ $(SENDER): $(KLCC) $(SENDER).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(SENDER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ +$(CONTROL): $(KLCC) $(CONTROL).o $(OBJS) udevd.h + $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CONTROL).o $(OBJS) $(LIB_OBJS) + $(QUIET) $(STRIPCMD) $@ + $(STARTER): $(KLCC) $(STARTER).o $(OBJS) $(QUIET) $(LD) $(LDFLAGS) -o $@ $(STARTER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ @@ -304,7 +310,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) $(TESTER) $(STARTER) + $(SENDER) $(CONTROL) $(TESTER) $(STARTER) -rm -f ccdv $(MAKE) -C klibc SUBDIRS=klibc clean @extras="$(EXTRAS)" ; for target in $$extras ; do \ @@ -364,6 +370,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 $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL) $(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO) $(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER) $(INSTALL_PROGRAM) -D $(STARTER) $(DESTDIR)$(sbindir)/$(STARTER) @@ -387,6 +394,7 @@ uninstall: uninstall-man uninstall-dev.d - rm $(sbindir)/$(ROOT) - rm $(sbindir)/$(DAEMON) - rm $(sbindir)/$(SENDER) + - rm $(sbindir)/$(CONTROL) - rm $(sbindir)/$(STARTER) - rm $(usrbindir)/$(INFO) - rm $(usrbindir)/$(TESTER) diff --git a/udevcontrol.c b/udevcontrol.c new file mode 100644 index 0000000000..6a278a04c1 --- /dev/null +++ b/udevcontrol.c @@ -0,0 +1,107 @@ +/* + * udevcontrol.c + * + * Userspace devfs + * + * Copyright (C) 2005 Kay Sievers + * + * + * 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 "udev.h" +#include "udev_version.h" +#include "udevd.h" +#include "logging.h" + +/* global variables */ +static int sock = -1; + +#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 + + +int main(int argc, char *argv[], char *envp[]) +{ + static struct udevd_msg usend_msg; + struct sockaddr_un saddr; + socklen_t addrlen; + int retval = 1; + + logging_init("udevcontrol"); + dbg("version %s", UDEV_VERSION); + + if (argc != 2) { + info("usage: udevcontrol \n"); + goto exit; + } + + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); + strcpy(usend_msg.magic, UDEV_MAGIC); + + if (strstr(argv[1], "stop_exec_queue")) + usend_msg.type = UDEVD_STOP_EXEC_QUEUE; + else if (strstr(argv[1], "start_exec_queue")) + usend_msg.type = UDEVD_START_EXEC_QUEUE; + else { + info("unknown command\n"); + goto exit; + } + + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sock == -1) { + info("error getting socket"); + goto exit; + } + + 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; + + + retval = sendto(sock, &usend_msg, sizeof(usend_msg), 0, (struct sockaddr *)&saddr, addrlen); + if (retval == -1) + info("error sending message (%s)", strerror(errno)); + + close(sock); + +exit: + logging_close(); + + return retval; +} diff --git a/udevd.c b/udevd.c index 68e3a75f33..371d715716 100644 --- a/udevd.c +++ b/udevd.c @@ -49,17 +49,18 @@ #include "logging.h" /* global variables*/ -static int udevsendsock; -static int ueventsock; +static int udevd_sock; +static int uevent_nl_sock; static pid_t sid; static int pipefds[2]; static long startup_time; -static unsigned long long expected_seqnum = 0; +static unsigned long long expected_seqnum; static volatile int sigchilds_waiting; static volatile int run_msg_q; static volatile int sig_flag; static int run_exec_q; +static int stop_exec_q; static LIST_HEAD(msg_list); static LIST_HEAD(exec_list); @@ -88,23 +89,23 @@ void log_message (int priority, const char *format, ...) static void msg_dump_queue(void) { #ifdef DEBUG - struct hotplug_msg *msg; + struct uevent_msg *msg; list_for_each_entry(msg, &msg_list, node) dbg("sequence %llu in queue", msg->seqnum); #endif } -static void run_queue_delete(struct hotplug_msg *msg) +static void run_queue_delete(struct uevent_msg *msg) { list_del(&msg->node); free(msg); } /* orders the message in the queue by sequence number */ -static void msg_queue_insert(struct hotplug_msg *msg) +static void msg_queue_insert(struct uevent_msg *msg) { - struct hotplug_msg *loop_msg; + struct uevent_msg *loop_msg; struct sysinfo info; if (msg->seqnum == 0) { @@ -148,7 +149,7 @@ static void msg_queue_insert(struct hotplug_msg *msg) } /* forks event and removes event from run queue when finished */ -static void execute_udev(struct hotplug_msg *msg) +static void execute_udev(struct uevent_msg *msg) { char *const argv[] = { "udev", msg->subsystem, NULL }; pid_t pid; @@ -157,9 +158,9 @@ static void execute_udev(struct hotplug_msg *msg) switch (pid) { case 0: /* child */ - if (ueventsock != -1) - close(ueventsock); - close(udevsendsock); + if (uevent_nl_sock != -1) + close(uevent_nl_sock); + close(udevd_sock); logging_close(); setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); @@ -298,9 +299,9 @@ static int compare_devpath(const char *running, const char *waiting) } /* returns still running task for the same device, its parent or its physical device */ -static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg) +static struct uevent_msg *running_with_devpath(struct uevent_msg *msg) { - struct hotplug_msg *loop_msg; + struct uevent_msg *loop_msg; if (msg->devpath == NULL) return NULL; @@ -329,9 +330,9 @@ static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg) /* exec queue management routine executes the events and serializes events in the same sequence */ static void exec_queue_manager(void) { - struct hotplug_msg *loop_msg; - struct hotplug_msg *tmp_msg; - struct hotplug_msg *msg; + struct uevent_msg *loop_msg; + struct uevent_msg *tmp_msg; + struct uevent_msg *msg; int running; running = running_processes(); @@ -364,7 +365,7 @@ static void exec_queue_manager(void) } } -static void msg_move_exec(struct hotplug_msg *msg) +static void msg_move_exec(struct uevent_msg *msg) { list_move_tail(&msg->node, &exec_list); run_exec_q = 1; @@ -376,8 +377,8 @@ static void msg_move_exec(struct hotplug_msg *msg) /* msg queue management routine handles the timeouts and dispatches the events */ static void msg_queue_manager(void) { - struct hotplug_msg *loop_msg; - struct hotplug_msg *tmp_msg; + struct uevent_msg *loop_msg; + struct uevent_msg *tmp_msg; struct sysinfo info; long msg_age = 0; static int timeout = EVENT_INIT_TIMEOUT_SEC; @@ -421,21 +422,21 @@ recheck: } } -static struct hotplug_msg *get_msg_from_envbuf(const char *buf, int buf_size) +static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size) { int bufpos; int i; - struct hotplug_msg *msg; + struct uevent_msg *msg; - msg = malloc(sizeof(struct hotplug_msg) + buf_size); + msg = malloc(sizeof(struct uevent_msg) + buf_size); if (msg == NULL) return NULL; - memset(msg, 0x00, sizeof(struct hotplug_msg) + buf_size); + memset(msg, 0x00, sizeof(struct uevent_msg) + buf_size); /* copy environment buffer and reconstruct envp */ memcpy(msg->envbuf, buf, buf_size); bufpos = 0; - for (i = 0; (bufpos < buf_size) && (i < HOTPLUG_NUM_ENVP-2); i++) { + for (i = 0; (bufpos < buf_size) && (i < UEVENT_NUM_ENVP-2); i++) { int keylen; char *key; @@ -470,11 +471,11 @@ static struct hotplug_msg *get_msg_from_envbuf(const char *buf, int buf_size) return msg; } -/* receive the udevsend message and do some sanity checks */ -static struct hotplug_msg *get_udevsend_msg(void) +/* receive the udevd message from userspace */ +static struct uevent_msg *get_udevd_msg(void) { - static struct udevsend_msg usend_msg; - struct hotplug_msg *msg; + static struct udevd_msg usend_msg; + struct uevent_msg *msg; ssize_t size; struct msghdr smsg; struct cmsghdr *cmsg; @@ -483,9 +484,9 @@ static struct hotplug_msg *get_udevsend_msg(void) char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; int envbuf_size; - memset(&usend_msg, 0x00, sizeof(struct udevsend_msg)); + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); iov.iov_base = &usend_msg; - iov.iov_len = sizeof(struct udevsend_msg); + iov.iov_len = sizeof(struct udevd_msg); memset(&smsg, 0x00, sizeof(struct msghdr)); smsg.msg_iov = &iov; @@ -493,10 +494,10 @@ static struct hotplug_msg *get_udevsend_msg(void) smsg.msg_control = cred_msg; smsg.msg_controllen = sizeof(cred_msg); - size = recvmsg(udevsendsock, &smsg, 0); + size = recvmsg(udevd_sock, &smsg, 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevsend message"); + dbg("unable to receive udevd message"); return NULL; } cmsg = CMSG_FIRSTHDR(&smsg); @@ -517,28 +518,43 @@ static struct hotplug_msg *get_udevsend_msg(void) return NULL; } - envbuf_size = size - offsetof(struct udevsend_msg, envbuf); - dbg("envbuf_size=%i", envbuf_size); - msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); - if (msg == NULL) - return NULL; - - return msg; +switch (usend_msg.type) { + case UDEVD_UEVENT: + dbg("udevd message (UEVENT) received"); + envbuf_size = size - offsetof(struct udevd_msg, envbuf); + dbg("envbuf_size=%i", envbuf_size); + msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); + if (msg == NULL) + return NULL; + return msg; + case UDEVD_STOP_EXEC_QUEUE: + dbg("udevd message (STOP_EXEC_QUEUE) received"); + stop_exec_q = 1; + break; + case UDEVD_START_EXEC_QUEUE: + dbg("udevd message (START_EXEC_QUEUE) received"); + stop_exec_q = 0; + exec_queue_manager(); + break; + default: + dbg("unknown message type"); + } + return NULL; } /* receive the kernel user event message and do some sanity checks */ -static struct hotplug_msg *get_uevent_msg(void) +static struct uevent_msg *get_uevent_msg(void) { - struct hotplug_msg *msg; + struct uevent_msg *msg; int bufpos; ssize_t size; - static char buffer[HOTPLUG_BUFFER_SIZE + 512]; + static char buffer[UEVENT_BUFFER_SIZE + 512]; char *pos; - size = recv(ueventsock, &buffer, sizeof(buffer), 0); + size = recv(uevent_nl_sock, &buffer, sizeof(buffer), 0); if (size < 0) { if (errno != EINTR) - dbg("unable to receive udevsend message"); + dbg("unable to receive udevd message"); return NULL; } @@ -612,7 +628,7 @@ do_write: static void udev_done(int pid) { /* find msg associated with pid and delete it */ - struct hotplug_msg *msg; + struct uevent_msg *msg; list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { @@ -655,7 +671,7 @@ static void user_sighandler(void) } } -static int init_udevsend_socket(void) +static int init_udevd_socket(void) { struct sockaddr_un saddr; socklen_t addrlen; @@ -668,27 +684,27 @@ static int init_udevsend_socket(void) strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH); addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1; - udevsendsock = socket(AF_LOCAL, SOCK_DGRAM, 0); - if (udevsendsock == -1) { + udevd_sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (udevd_sock == -1) { err("error getting socket, %s", strerror(errno)); return -1; } /* the bind takes care of ensuring only one copy running */ - retval = bind(udevsendsock, (struct sockaddr *) &saddr, addrlen); + retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen); if (retval < 0) { err("bind failed, %s", strerror(errno)); - close(udevsendsock); + close(udevd_sock); return -1; } /* enable receiving of the sender credentials */ - setsockopt(udevsendsock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); + setsockopt(udevd_sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); return 0; } -static int init_uevent_socket(void) +static int init_uevent_nl_sock(void) { struct sockaddr_nl snl; int retval; @@ -698,18 +714,18 @@ static int init_uevent_socket(void) snl.nl_pid = getpid(); snl.nl_groups = 0xffffffff; - ueventsock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (ueventsock == -1) { + uevent_nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (uevent_nl_sock == -1) { dbg("error getting socket, %s", strerror(errno)); return -1; } - retval = bind(ueventsock, (struct sockaddr *) &snl, + retval = bind(uevent_nl_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl)); if (retval < 0) { dbg("bind failed, %s", strerror(errno)); - close(ueventsock); - ueventsock = -1; + close(uevent_nl_sock); + uevent_nl_sock = -1; return -1; } @@ -725,7 +741,7 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *udevd_expected_seqnum; - int uevent_active = 0; + int uevent_nl_active = 0; logging_init("udevd"); udev_init_config(); @@ -811,15 +827,15 @@ int main(int argc, char *argv[], char *envp[]) sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); - if (init_uevent_socket() < 0) { + if (init_uevent_nl_sock() < 0) { dbg("uevent socket not available"); } - if (init_udevsend_socket() < 0) { + if (init_udevd_socket() < 0) { if (errno == EADDRINUSE) dbg("another udevd running, exit"); else - dbg("error initialising udevsend socket: %s", strerror(errno)); + dbg("error initialising udevd socket: %s", strerror(errno)); goto exit; } @@ -843,13 +859,13 @@ int main(int argc, char *argv[], char *envp[]) startup_time = info.uptime; FD_ZERO(&readfds); - FD_SET(udevsendsock, &readfds); - if (ueventsock != -1) - FD_SET(ueventsock, &readfds); + FD_SET(udevd_sock, &readfds); + if (uevent_nl_sock != -1) + FD_SET(uevent_nl_sock, &readfds); FD_SET(pipefds[0], &readfds); - maxsockplus = udevsendsock+1; + maxsockplus = udevd_sock+1; while (1) { - struct hotplug_msg *msg; + struct uevent_msg *msg; fd_set workreadfds = readfds; retval = select(maxsockplus, &workreadfds, NULL, NULL, NULL); @@ -860,12 +876,12 @@ int main(int argc, char *argv[], char *envp[]) continue; } - if (FD_ISSET(udevsendsock, &workreadfds)) { - msg = get_udevsend_msg(); + if (FD_ISSET(udevd_sock, &workreadfds)) { + msg = get_udevd_msg(); if (msg) { /* discard kernel messages if netlink is active */ - if (uevent_active && msg->seqnum != 0) { - dbg("skip kernel udevsend message, netlink is active"); + if (uevent_nl_active && msg->seqnum != 0) { + dbg("skip uevent_helper message, netlink is active"); free(msg); continue; } @@ -873,14 +889,14 @@ int main(int argc, char *argv[], char *envp[]) } } - if (FD_ISSET(ueventsock, &workreadfds)) { + if (FD_ISSET(uevent_nl_sock, &workreadfds)) { msg = get_uevent_msg(); if (msg) { msg_queue_insert(msg); /* disable udevsend with first netlink message */ - if (!uevent_active) { - info("netlink message received, disable kernel udevsend messages"); - uevent_active = 1; + if (!uevent_nl_active) { + info("uevent_nl message received, disable uevent_helper messages"); + uevent_nl_active = 1; } } } @@ -906,7 +922,8 @@ int main(int argc, char *argv[], char *envp[]) } run_exec_q = 0; - exec_queue_manager(); + if (!stop_exec_q) + exec_queue_manager(); } } diff --git a/udevd.h b/udevd.h index b3e998b04c..b782d7aacd 100644 --- a/udevd.h +++ b/udevd.h @@ -43,15 +43,24 @@ #define THROTTLE_MAX_RUNNING_CHILDS 10 /* environment buffer, should match the kernel's size in lib/kobject_uevent.h */ -#define HOTPLUG_BUFFER_SIZE 1024 -#define HOTPLUG_NUM_ENVP 32 +#define UEVENT_BUFFER_SIZE 1024 +#define UEVENT_NUM_ENVP 32 -struct udevsend_msg { - char magic[20]; - char envbuf[HOTPLUG_BUFFER_SIZE+256]; +enum udevd_msg_type { + UDEVD_UNKNOWN, + UDEVD_UEVENT, + UDEVD_STOP_EXEC_QUEUE, + UDEVD_START_EXEC_QUEUE, }; -struct hotplug_msg { + +struct udevd_msg { + char magic[32]; + enum udevd_msg_type type; + char envbuf[UEVENT_BUFFER_SIZE+512]; +}; + +struct uevent_msg { struct list_head node; pid_t pid; long queue_time; @@ -61,6 +70,6 @@ struct hotplug_msg { unsigned long long seqnum; char *physdevpath; unsigned int timeout; - char *envp[HOTPLUG_NUM_ENVP+1]; + char *envp[UEVENT_NUM_ENVP+1]; char envbuf[]; }; diff --git a/udevsend.c b/udevsend.c index 8915edacc8..2b92e659e2 100644 --- a/udevsend.c +++ b/udevsend.c @@ -115,7 +115,7 @@ static void run_udev(const char *subsystem) int main(int argc, char *argv[], char *envp[]) { - static struct udevsend_msg usend_msg; + static struct udevd_msg usend_msg; int usend_msg_len; int i; int loop; @@ -144,8 +144,9 @@ int main(int argc, char *argv[], char *envp[]) strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH); addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1; - memset(&usend_msg, 0x00, sizeof(struct udevsend_msg)); + memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); + usend_msg.type = UDEVD_UEVENT; /* copy all keys to send buffer */ for (i = 0; envp[i]; i++) { @@ -161,7 +162,7 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } - if (bufpos + keylen >= HOTPLUG_BUFFER_SIZE-1) { + if (bufpos + keylen >= UEVENT_BUFFER_SIZE-1) { err("environment buffer too small, probably not called by the kernel"); continue; } @@ -180,7 +181,7 @@ int main(int argc, char *argv[], char *envp[]) dbg("add 'SUBSYSTEM=%s' to env[%i] buffer from argv", argv[1], i); } - usend_msg_len = offsetof(struct udevsend_msg, envbuf) + bufpos; + usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos; dbg("usend_msg_len=%i", usend_msg_len); /* If we can't send, try to start daemon and resend message */ From 0590abd720f0ddc8204539feef4df8987d7a1f8c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:44:07 +0200 Subject: [PATCH 03/24] udevd: add initsend Transfer stored events from initramfs to the running udevd to replay events after userspace is ready. Signed-off-by: Kay Sievers --- Makefile | 32 ++++--- udev.8.in | 3 +- udevinitsend.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 13 deletions(-) create mode 100644 udevinitsend.c diff --git a/Makefile b/Makefile index 896a58a306..2a832f7054 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 5be9308af4..79c4a83d16 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 0000000000..05c39b99b3 --- /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; +} From 1682c8c4a3909f9d80f17544bcfc6fb73379bc7e Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:48:09 +0200 Subject: [PATCH 04/24] Makefile: fix DESTDIR Patch from: Vassilis Virvilis Signed-off-by: Kay Sievers --- Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2a832f7054..1cf3e54fb7 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,6 @@ INFO = udevinfo TESTER = udevtest STARTER = udevstart VERSION = 058 -INSTALL_DIR = /usr/local/bin RELEASE_NAME = $(ROOT)-$(VERSION) LOCAL_CFG_DIR = etc/udev DESTDIR = @@ -180,7 +179,6 @@ ifeq ($(strip $(USE_KLIBC)),true) KLCC = $(KLIBC_INSTALL)/bin/klcc CC = $(KLCC) LD = $(KLCC) - LDFLAGS += -static else CFLAGS += -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations endif @@ -252,8 +250,8 @@ udev_version.h: @echo \#define UDEV_CONFIG_DIR \"$(configdir)\" >> $@ @echo \#define UDEV_CONFIG_FILE \"$(configdir)/udev.conf\" >> $@ @echo \#define UDEV_RULES_FILE \"$(configdir)/rules.d\" >> $@ - @echo \#define UDEV_BIN \"$(DESTDIR)$(sbindir)/udev\" >> $@ - @echo \#define UDEVD_BIN \"$(DESTDIR)$(sbindir)/udevd\" >> $@ + @echo \#define UDEV_BIN \"$(sbindir)/udev\" >> $@ + @echo \#define UDEVD_BIN \"$(sbindir)/udevd\" >> $@ # Rules on how to create the generated config files $(LOCAL_CFG_DIR)/udev.conf: From a15f42c46a7b9ceb5850ea4334c95f099ce74a6f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:53:17 +0200 Subject: [PATCH 05/24] udevd: improve timeout handling Allow to override some parameters by environment keys. Signed-off-by: Kay Sievers --- udevd.c | 149 ++++++++++++++++++++++++++++++++++------------------- udevd.h | 14 ++--- udevsend.c | 6 +-- 3 files changed, 107 insertions(+), 62 deletions(-) diff --git a/udevd.c b/udevd.c index 371d715716..b5597eab40 100644 --- a/udevd.c +++ b/udevd.c @@ -54,11 +54,10 @@ static int uevent_nl_sock; static pid_t sid; static int pipefds[2]; -static long startup_time; -static unsigned long long expected_seqnum; static volatile int sigchilds_waiting; static volatile int run_msg_q; static volatile int sig_flag; +static int init_phase = 1; static int run_exec_q; static int stop_exec_q; @@ -70,7 +69,13 @@ static void exec_queue_manager(void); static void msg_queue_manager(void); static void user_sighandler(void); static void reap_sigchilds(void); -char *udev_bin; + +static char *udev_bin; +static unsigned long long expected_seqnum; +static int event_timeout; +static int max_childs; +static int max_childs_running; + #ifdef USE_LOG void log_message (int priority, const char *format, ...) @@ -115,6 +120,20 @@ static void msg_queue_insert(struct uevent_msg *msg) return; } + /* store timestamp of queuing */ + sysinfo(&info); + msg->queue_time = info.uptime; + + /* with the first event we provide a phase of shorter timeout */ + if (init_phase) { + static long init_time; + + if (init_time == 0) + init_time = info.uptime; + if (info.uptime - init_time >= UDEVD_INIT_TIME) + init_phase = 0; + } + /* don't delay messages with timeout set */ if (msg->timeout) { dbg("move seq %llu with timeout %u to exec queue", msg->seqnum, msg->timeout); @@ -134,13 +153,8 @@ static void msg_queue_insert(struct uevent_msg *msg) return; } } - - /* store timestamp of queuing */ - sysinfo(&info); - msg->queue_time = info.uptime; - list_add(&msg->node, &loop_msg->node); - dbg("queued message seq %llu", msg->seqnum); + info("seq %llu queued, devpath '%s'", msg->seqnum, msg->devpath); /* run msg queue manager */ run_msg_q = 1; @@ -153,6 +167,7 @@ static void execute_udev(struct uevent_msg *msg) { char *const argv[] = { "udev", msg->subsystem, NULL }; pid_t pid; + struct sysinfo info; pid = fork(); switch (pid) { @@ -174,7 +189,9 @@ static void execute_udev(struct uevent_msg *msg) break; default: /* get SIGCHLD in main loop */ - dbg("==> exec seq %llu [%d] working at '%s'", msg->seqnum, pid, msg->devpath); + sysinfo(&info); + info("seq %llu forked, pid %d, %ld seconds old", + msg->seqnum, pid, info.uptime - msg->queue_time); msg->pid = pid; } } @@ -299,32 +316,43 @@ static int compare_devpath(const char *running, const char *waiting) } /* returns still running task for the same device, its parent or its physical device */ -static struct uevent_msg *running_with_devpath(struct uevent_msg *msg) +static int running_with_devpath(struct uevent_msg *msg, int limit) { struct uevent_msg *loop_msg; + int childs_count = 0; if (msg->devpath == NULL) - return NULL; + return 0; /* skip any events with a timeout set */ - if (msg->timeout) - return NULL; + if (msg->timeout != 0) + return 0; list_for_each_entry(loop_msg, &running_list, node) { + if (limit && childs_count++ > limit) { + dbg("%llu, maximum number (%i) of child reached", msg->seqnum, childs_count); + return 1; + } if (loop_msg->devpath == NULL) continue; /* return running parent/child device event */ - if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) - return loop_msg; + if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) { + dbg("%llu, child device event still running %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 2; + } /* return running physical device event */ if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0) - if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) - return loop_msg; + if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) { + dbg("%llu, physical device event still running %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 3; + } } - return NULL; + return 0; } /* exec queue management routine executes the events and serializes events in the same sequence */ @@ -332,36 +360,33 @@ static void exec_queue_manager(void) { struct uevent_msg *loop_msg; struct uevent_msg *tmp_msg; - struct uevent_msg *msg; int running; running = running_processes(); dbg("%d processes runnning on system", running); if (running < 0) - running = THROTTLE_MAX_RUNNING_CHILDS; + running = max_childs_running; list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, node) { /* check running processes in our session and possibly throttle */ - if (running >= THROTTLE_MAX_RUNNING_CHILDS) { - running = running_processes_in_session(sid, THROTTLE_MAX_RUNNING_CHILDS+10); - dbg("%d processes running in session", running); - if (running >= THROTTLE_MAX_RUNNING_CHILDS) { - dbg("delay seq %llu, cause too many processes already running", loop_msg->seqnum); + if (running >= max_childs_running) { + running = running_processes_in_session(sid, max_childs_running+10); + dbg("at least %d processes running in session", running); + if (running >= max_childs_running) { + dbg("delay seq %llu, cause too many processes already running", + loop_msg->seqnum); return; } } - msg = running_with_devpath(loop_msg); - if (!msg) { + if (running_with_devpath(loop_msg, max_childs) == 0) { /* move event to run list */ list_move_tail(&loop_msg->node, &running_list); execute_udev(loop_msg); running++; dbg("moved seq %llu to running list", loop_msg->seqnum); - } else { - dbg("delay seq %llu (%s), cause seq %llu (%s) is still running", - loop_msg->seqnum, loop_msg->devpath, msg->seqnum, msg->devpath); - } + } else + dbg("delay seq %llu (%s)", loop_msg->seqnum, loop_msg->devpath); } } @@ -381,11 +406,11 @@ static void msg_queue_manager(void) struct uevent_msg *tmp_msg; struct sysinfo info; long msg_age = 0; - static int timeout = EVENT_INIT_TIMEOUT_SEC; - static int init = 1; + int timeout = event_timeout; dbg("msg queue manager, next expected is %llu", expected_seqnum); recheck: + sysinfo(&info); list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, node) { /* move event with expected sequence to the exec list */ if (loop_msg->seqnum == expected_seqnum) { @@ -393,15 +418,13 @@ recheck: continue; } - /* see if we are in the initialization phase and wait for the very first events */ - if (init && (info.uptime - startup_time >= INIT_TIME_SEC)) { - init = 0; - timeout = EVENT_TIMEOUT_SEC; - dbg("initialization phase passed, set timeout to %i seconds", EVENT_TIMEOUT_SEC); + /* limit timeout during initialization phase */ + if (init_phase) { + timeout = UDEVD_INIT_EVENT_TIMEOUT; + dbg("initialization phase, limit timeout to %i seconds", UDEVD_INIT_EVENT_TIMEOUT); } /* move event with expired timeout to the exec list */ - sysinfo(&info); msg_age = info.uptime - loop_msg->queue_time; dbg("seq %llu is %li seconds old", loop_msg->seqnum, msg_age); if (msg_age >= timeout) { @@ -629,10 +652,12 @@ static void udev_done(int pid) { /* find msg associated with pid and delete it */ struct uevent_msg *msg; + struct sysinfo info; list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { - dbg("<== exec seq %llu came back", msg->seqnum); + sysinfo(&info); + info("seq %llu exit, %ld sec old", msg->seqnum, info.uptime - msg->queue_time); run_queue_delete(msg); /* we want to run the exec queue manager since there may @@ -734,13 +759,12 @@ static int init_uevent_nl_sock(void) int main(int argc, char *argv[], char *envp[]) { - struct sysinfo info; int maxsockplus; int retval; int fd; struct sigaction act; fd_set readfds; - const char *udevd_expected_seqnum; + const char *value; int uevent_nl_active = 0; logging_init("udevd"); @@ -774,7 +798,6 @@ int main(int argc, char *argv[], char *envp[]) sid = setsid(); dbg("our session is %d", sid); - /* make sure we don't lock any path */ chdir("/"); umask(umask(077) | 022); @@ -840,23 +863,43 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } - /* possible override of udev binary, used for testing */ + /* override of forked udev binary, used for testing */ udev_bin = getenv("UDEV_BIN"); if (udev_bin != NULL) info("udev binary is set to '%s'", udev_bin); else udev_bin = UDEV_BIN; - /* possible init of expected_seqnum value */ - udevd_expected_seqnum = getenv("UDEVD_EXPECTED_SEQNUM"); - if (udevd_expected_seqnum != NULL) { - expected_seqnum = strtoull(udevd_expected_seqnum, NULL, 10); + /* init of expected_seqnum value */ + value = getenv("UDEVD_EXPECTED_SEQNUM"); + if (value) { + expected_seqnum = strtoull(value, NULL, 10); info("initialize expected_seqnum to %llu", expected_seqnum); } - /* get current time to provide shorter timeout on startup */ - sysinfo(&info); - startup_time = info.uptime; + /* timeout to wait for missing events */ + value = getenv("UDEVD_EVENT_TIMEOUT"); + if (value) + event_timeout = strtoul(value, NULL, 10); + else + event_timeout = UDEVD_EVENT_TIMEOUT; + info("initialize event_timeout to %u", event_timeout); + + /* maximum limit of forked childs */ + value = getenv("UDEVD_MAX_CHILDS"); + if (value) + max_childs = strtoul(value, NULL, 10); + else + max_childs = UDEVD_MAX_CHILDS; + info("initialize max_childs to %u", max_childs); + + /* start to throttle forking if maximum number of _running_ childs is reached */ + value = getenv("UDEVD_MAX_CHILDS_RUNNING"); + if (value) + max_childs_running = strtoull(value, NULL, 10); + else + max_childs_running = UDEVD_MAX_CHILDS_RUNNING; + info("initialize max_childs_running to %u", max_childs_running); FD_ZERO(&readfds); FD_SET(udevd_sock, &readfds); @@ -893,7 +936,7 @@ int main(int argc, char *argv[], char *envp[]) msg = get_uevent_msg(); if (msg) { msg_queue_insert(msg); - /* disable udevsend with first netlink message */ + /* disable kernel uevent_helper with first netlink message */ if (!uevent_nl_active) { info("uevent_nl message received, disable uevent_helper messages"); uevent_nl_active = 1; diff --git a/udevd.h b/udevd.h index b782d7aacd..60732fe052 100644 --- a/udevd.h +++ b/udevd.h @@ -26,21 +26,23 @@ #define UDEV_MAGIC "udevd_" UDEV_VERSION #define UDEVD_SOCK_PATH "udevd" -#define SEND_WAIT_MAX_SECONDS 3 -#define SEND_WAIT_LOOP_PER_SECOND 10 +#define UDEVSEND_WAIT_MAX_SECONDS 3 +#define UDEVSEND_WAIT_LOOP_PER_SECOND 10 #define UDEVD_PRIORITY -4 #define UDEV_PRIORITY -2 /* duration of initialization phase with shorter timeout */ -#define INIT_TIME_SEC 5 -#define EVENT_INIT_TIMEOUT_SEC 2 +#define UDEVD_INIT_TIME 5 +#define UDEVD_INIT_EVENT_TIMEOUT 2 /* timeout to wait for missing events */ -#define EVENT_TIMEOUT_SEC 10 +#define UDEVD_EVENT_TIMEOUT 5 +/* maximum limit of runnig childs */ +#define UDEVD_MAX_CHILDS 64 /* start to throttle forking if maximum number of running childs in our session is reached */ -#define THROTTLE_MAX_RUNNING_CHILDS 10 +#define UDEVD_MAX_CHILDS_RUNNING 8 /* environment buffer, should match the kernel's size in lib/kobject_uevent.h */ #define UEVENT_BUFFER_SIZE 1024 diff --git a/udevsend.c b/udevsend.c index 2b92e659e2..888a88daa0 100644 --- a/udevsend.c +++ b/udevsend.c @@ -185,7 +185,7 @@ int main(int argc, char *argv[], char *envp[]) dbg("usend_msg_len=%i", usend_msg_len); /* If we can't send, try to start daemon and resend message */ - loop = SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND; + loop = UDEVSEND_WAIT_MAX_SECONDS * UDEVSEND_WAIT_LOOP_PER_SECOND; while (--loop) { retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen); if (retval != -1) { @@ -208,8 +208,8 @@ int main(int argc, char *argv[], char *envp[]) dbg("udevd daemon started"); started_daemon = 1; } else { - dbg("retry to connect %d", SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND - loop); - usleep(1000 * 1000 / SEND_WAIT_LOOP_PER_SECOND); + dbg("retry to connect %d", UDEVSEND_WAIT_MAX_SECONDS * UDEVSEND_WAIT_LOOP_PER_SECOND - loop); + usleep(1000 * 1000 / UDEVSEND_WAIT_LOOP_PER_SECOND); } } From c974742bf4d6d8fab1e1c90e2e57dae0a2f297a1 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 04:57:03 +0200 Subject: [PATCH 06/24] udev: allow final assignments := The use of KEY:= will make the key unchangeable by later rules. Signed-off-by: Kay Sievers --- test/udev-test.pl | 23 +++++++++++++++++++++++ udev.h | 5 +++++ udev_rules.c | 20 +++++++++++++++----- udev_rules.h | 6 ++++++ udev_rules_parse.c | 11 +++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/test/udev-test.pl b/test/udev-test.pl index 3172d3302f..27fe35456e 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -1304,6 +1304,29 @@ EOF KERNEL=="sda", NAME="ok2", RUN+="/bin/ln -s ok2 %r/testsymlink2" KERNEL=="sda", ACTION=="remove", RUN+="/bin/rm -f %r/testsymlink2" KERNEL=="sda", NAME="not-ok2" +EOF + }, + { + desc => "final assignment", + subsys => "block", + devpath => "/block/sda", + exp_name => "ok", + exp_perms => "root:nobody:0640", + rules => < "final assignment", + subsys => "block", + devpath => "/block/sda", + exp_name => "ok", + exp_perms => "root:nobody:0640", + rules => <mode != 0000) { + if (!udev->mode_final && rule->mode != 0000) { + if (rule->mode_operation == KEY_OP_ASSIGN_FINAL) + udev->mode_final = 1; udev->mode = rule->mode; dbg("applied mode=%#o to '%s'", udev->mode, udev->kernel_name); } - if (rule->owner[0] != '\0') { + if (!udev->owner_final && rule->owner[0] != '\0') { + if (rule->owner_operation == KEY_OP_ASSIGN_FINAL) + udev->owner_final = 1; strlcpy(udev->owner, rule->owner, sizeof(udev->owner)); apply_format(udev, udev->owner, sizeof(udev->owner), class_dev, sysfs_device); dbg("applied owner='%s' to '%s'", udev->owner, udev->kernel_name); } - if (rule->group[0] != '\0') { + if (!udev->group_final && rule->group[0] != '\0') { + if (rule->group_operation == KEY_OP_ASSIGN_FINAL) + udev->group_final = 1; strlcpy(udev->group, rule->group, sizeof(udev->group)); apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device); dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name); } /* collect symlinks */ - if (rule->symlink[0] != '\0') { + if (!udev->symlink_final && rule->symlink[0] != '\0') { char temp[PATH_SIZE]; char *pos, *next; + if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL) + udev->symlink_final = 1; info("configured rule in '%s[%i]' applied, added symlink '%s'", rule->config_file, rule->config_line, rule->symlink); strlcpy(temp, rule->symlink, sizeof(temp)); @@ -808,9 +816,11 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d udev->name, udev->owner, udev->group, udev->mode, udev->partitions); } - if (rule->run[0] != '\0') { + if (!udev->run_final && rule->run[0] != '\0') { char program[PATH_SIZE]; + if (rule->run_operation == KEY_OP_ASSIGN_FINAL) + udev->run_final = 1; strlcpy(program, rule->run, sizeof(program)); apply_format(udev, program, sizeof(program), class_dev, sysfs_device); dbg("add run '%s'", program); diff --git a/udev_rules.h b/udev_rules.h index 5fba2d5571..f4a74bba45 100644 --- a/udev_rules.h +++ b/udev_rules.h @@ -62,6 +62,7 @@ enum key_operation { KEY_OP_NOMATCH, KEY_OP_ADD, KEY_OP_ASSIGN, + KEY_OP_ASSIGN_FINAL, }; struct key_pair { @@ -96,10 +97,15 @@ struct udev_rule { char name[PATH_SIZE]; char symlink[PATH_SIZE]; + enum key_operation symlink_operation; char owner[USER_SIZE]; + enum key_operation owner_operation; char group[USER_SIZE]; + enum key_operation group_operation; mode_t mode; + enum key_operation mode_operation; char run[PATH_SIZE]; + enum key_operation run_operation; int last_rule; int ignore_device; diff --git a/udev_rules_parse.c b/udev_rules_parse.c index e665957b81..3f07521ccb 100644 --- a/udev_rules_parse.c +++ b/udev_rules_parse.c @@ -89,6 +89,8 @@ static int get_key(char **line, char **key, enum key_operation *operation, char break; if (linepos[0] == '!') break; + if (linepos[0] == ':') + break; } /* remember end of key */ @@ -115,6 +117,10 @@ static int get_key(char **line, char **key, enum key_operation *operation, char *operation = KEY_OP_ASSIGN; linepos++; dbg("operator=assign"); + } else if (linepos[0] == ':' && linepos[1] == '=') { + *operation = KEY_OP_ASSIGN_FINAL; + linepos += 2; + dbg("operator=assign_final"); } else return -1; @@ -364,30 +370,35 @@ static int rules_parse(const char *filename) if (strcasecmp(key, KEY_SYMLINK) == 0) { strlcpy(rule.symlink, value, sizeof(rule.symlink)); + rule.symlink_operation = operation; valid = 1; continue; } if (strcasecmp(key, KEY_OWNER) == 0) { strlcpy(rule.owner, value, sizeof(rule.owner)); + rule.owner_operation = operation; valid = 1; continue; } if (strcasecmp(key, KEY_GROUP) == 0) { strlcpy(rule.group, value, sizeof(rule.group)); + rule.group_operation = operation; valid = 1; continue; } if (strcasecmp(key, KEY_MODE) == 0) { rule.mode = strtol(value, NULL, 8); + rule.mode_operation = operation; valid = 1; continue; } if (strcasecmp(key, KEY_RUN) == 0) { strlcpy(rule.run, value, sizeof(rule.run)); + rule.run_operation = operation; valid = 1; continue; } From 6a522681e1438bbd9c317654cc35d5d206d378ad Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 05:11:29 +0200 Subject: [PATCH 07/24] udev: move dev.d/ handling to external helper Modern rules are expected to call notification and postprocessing with the RUN key. For compatibility the current behavior can be emulated with an external helper. Signed-off-by: Kay Sievers --- etc/udev/udev.rules | 51 ++++++++------- etc/udev/udev.rules.examples | 63 ++++++++----------- extras/run_directory/Makefile | 55 +++++++++++++++++ extras/run_directory/run_directory.c | 79 ++++++++++++++++++++++++ extras/run_directory/udev_run_devd.c | 78 +++++++++++++++++++++++ extras/run_directory/udev_run_hotplugd.c | 79 ++++++++++++++++++++++++ test/simple-build-check.sh | 2 +- udev.c | 4 -- udev.h | 1 - udev_config.c | 37 ----------- udev_utils.c | 32 ++++++++++ udev_utils.h | 2 + udevstart.c | 4 -- 13 files changed, 378 insertions(+), 109 deletions(-) create mode 100644 extras/run_directory/Makefile create mode 100644 extras/run_directory/run_directory.c create mode 100644 extras/run_directory/udev_run_devd.c create mode 100644 extras/run_directory/udev_run_hotplugd.c diff --git a/etc/udev/udev.rules b/etc/udev/udev.rules index bc8c8bdd6c..bebf74802f 100644 --- a/etc/udev/udev.rules +++ b/etc/udev/udev.rules @@ -5,43 +5,42 @@ # # if this is a ide cdrom, name it the default name, and create a symlink to cdrom -BUS="ide", KERNEL="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom" - -# create a symlink named after the device map name -# note devmap_name comes with extras/multipath -KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", NAME="%k", SYMLINK="%c" +BUS=="ide", KERNEL=="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK+="cdrom" # DRI devices always go into a subdirectory (as per the LSB spec) -KERNEL="card*", NAME="dri/card%n" +KERNEL=="card*", NAME="dri/card%n" # alsa devices -KERNEL="controlC[0-9]*", NAME="snd/%k" -KERNEL="hw[CD0-9]*", NAME="snd/%k" -KERNEL="pcm[CD0-9cp]*", NAME="snd/%k" -KERNEL="midiC[D0-9]*", NAME="snd/%k" -KERNEL="timer", NAME="snd/%k" -KERNEL="seq", NAME="snd/%k" +KERNEL=="controlC[0-9]*", NAME="snd/%k" +KERNEL=="hw[CD0-9]*", NAME="snd/%k" +KERNEL=="pcm[CD0-9cp]*", NAME="snd/%k" +KERNEL=="midiC[D0-9]*", NAME="snd/%k" +KERNEL=="timer", NAME="snd/%k" +KERNEL=="seq", NAME="snd/%k" # input devices -KERNEL="mice", NAME="input/%k" -KERNEL="mouse*", NAME="input/%k" -KERNEL="event*", NAME="input/%k" -KERNEL="js*", NAME="input/%k" -KERNEL="ts*", NAME="input/%k" +KERNEL=="mice", NAME="input/%k" +KERNEL=="mouse*", NAME="input/%k" +KERNEL=="event*", NAME="input/%k" +KERNEL=="js*", NAME="input/%k" +KERNEL=="ts*", NAME="input/%k" # USB devices -KERNEL="hiddev*", NAME="usb/%k" -KERNEL="auer*", NAME="usb/%k" -KERNEL="legousbtower*", NAME="usb/%k" -KERNEL="dabusb*", NAME="usb/%k" -BUS="usb", KERNEL="lp[0-9]*", NAME="usb/%k" +KERNEL=="hiddev*", NAME="usb/%k" +KERNEL=="auer*", NAME="usb/%k" +KERNEL=="legousbtower*", NAME="usb/%k" +KERNEL=="dabusb*", NAME="usb/%k" +BUS=="usb", KERNEL=="lp[0-9]*", NAME="usb/%k" # CAPI devices -KERNEL="capi", NAME="capi20", SYMLINK="isdn/capi20" -KERNEL="capi*", NAME="capi/%n" +KERNEL=="capi", NAME="capi20", SYMLINK+="isdn/capi20" +KERNEL=="capi*", NAME="capi/%n" # Network devices -KERNEL="tun", NAME="net/%k" +KERNEL=="tun", NAME="net/%k" # raw devices -KERNEL="raw[0-9]*", NAME="raw/%k" +KERNEL=="raw[0-9]*", NAME="raw/%k" + +# emulate dev.d/ +RUN="/sbin/udev_run_devd" diff --git a/etc/udev/udev.rules.examples b/etc/udev/udev.rules.examples index a464b6ba57..1c4527891a 100644 --- a/etc/udev/udev.rules.examples +++ b/etc/udev/udev.rules.examples @@ -9,64 +9,55 @@ # # Looking for scsi bus id 42:0:0:1 -BUS="scsi", PROGRAM="/bin/echo -n test-%b", RESULT="test-42:0:0:1", NAME="%c" +BUS=="scsi", PROGRAM="/bin/echo -n test-%b", RESULT=="test-42:0:0:1", NAME="%c" # A usb camera. -BUS="usb", SYSFS{vendor}="FUJIFILM", SYSFS{model}="M100", NAME="camera%n" +BUS=="usb", SYSFS{vendor}=="FUJIFILM", SYSFS{model}=="M100", NAME="camera%n" # USB Epson printer to be called lp_epson -BUS="usb", SYSFS_serial="HXOLL0012202323480", NAME="lp_epson" +BUS=="usb", SYSFS_serial=="HXOLL0012202323480", NAME="lp_epson" # USB HP printer to be called lp_hp -BUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_hp" +BUS=="usb", SYSFS{serial}=="W09090207101241330", NAME="lp_hp" # sound card with PCI bus id 00:0b.0 to be the first sound card -BUS="pci", ID="00:0b.0", NAME="dsp" +BUS=="pci", ID=="00:0b.0", NAME="dsp" # sound card with PCI bus id 00:07.1 to be the second sound card -BUS="pci", ID="00:07.1", NAME="dsp1" - -# USB mouse plugged into the third port of the first hub to be called mouse0 -BUS="usb", PLACE="1.3", NAME="mouse0" - -# USB tablet plugged into the third port of the second hub to be called mouse1 -BUS="usb", PLACE="2.3", NAME="mouse1" -BUS="usb", PLACE="2.4", NAME="mouse2" +BUS=="pci", ID=="00:07.1", NAME="dsp1" # ttyUSB1 should always be called visor -KERNEL="ttyUSB1", NAME="visor" -KERNEL="ttyUSB0", NAME="pl2303" +KERNEL=="ttyUSB1", NAME="visor" +KERNEL=="ttyUSB0", NAME="pl2303" # a devfs like way to name some tty devices -KERNEL="ttyS*", NAME="tts/%n" -KERNEL="tty*", NAME="vc/%n" +KERNEL=="ttyS*", NAME="tts/%n" +KERNEL=="tty*", NAME="vc/%n" # if this is a ide cdrom, name it the default name, and create a symlink to cdrom -BUS="ide", KERNEL="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom" - -# create a symlink named after the device map name -# note devmap_name comes with extras/multipath -KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", NAME="%k", SYMLINK="%c" +BUS=="ide", KERNEL=="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT=="cdrom", NAME="%k", SYMLINK+="cdrom" # DRI devices always go into a subdirectory (as per the LSB spec) -KERNEL="card*", NAME="dri/card%n" +KERNEL=="card*", NAME="dri/card%n" # create all 15 partitions of a USB flash card reader -# note the trailing spaces in the attribute, use udevinfo(8) to examine your device -BUS="scsi", SYSFS{model}="CF/MD ", NAME{all_partitions}="compactflash" +BUS=="scsi", SYSFS{model}=="CF/MD", NAME{all_partitions}="compactflash" # alsa devices -KERNEL="controlC[0-9]*", NAME="snd/%k" -KERNEL="hw[CD0-9]*", NAME="snd/%k" -KERNEL="pcm[CD0-9cp]*", NAME="snd/%k" -KERNEL="midi[CD0-9]*", NAME="snd/%k" -KERNEL="timer", NAME="snd/%k" -KERNEL="seq", NAME="snd/%k" +KERNEL=="controlC[0-9]*", NAME="snd/%k" +KERNEL=="hw[CD0-9]*", NAME="snd/%k" +KERNEL=="pcm[CD0-9cp]*", NAME="snd/%k" +KERNEL=="midi[CD0-9]*", NAME="snd/%k" +KERNEL=="timer", NAME="snd/%k" +KERNEL=="seq", NAME="snd/%k" # input devices -KERNEL="mice", NAME="input/%k" -KERNEL="mouse*", NAME="input/%k" -KERNEL="event*", NAME="input/%k" -KERNEL="js*", NAME="input/%k" -KERNEL="ts*", NAME="input/%k" +KERNEL=="mice", NAME="input/%k" +KERNEL=="mouse*", NAME="input/%k" +KERNEL=="event*", NAME="input/%k" +KERNEL=="js*", NAME="input/%k" +KERNEL=="ts*", NAME="input/%k" + +# emulate dev.d/ +RUN="/sbin/udev_run_devd" diff --git a/extras/run_directory/Makefile b/extras/run_directory/Makefile new file mode 100644 index 0000000000..12dccf0749 --- /dev/null +++ b/extras/run_directory/Makefile @@ -0,0 +1,55 @@ +# Makefile for udev_volume_id +# +# Copyright (C) 2004 Kay Sievers +# +# 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. +# + +DEVD = udev_run_devd +HOTPLUGD = udev_run_hotplugd + +all: $(DEVD) $(HOTPLUGD) + +prefix = +exec_prefix = ${prefix} +etcdir = ${prefix}/etc +sbindir = ${exec_prefix}/sbin +usrbindir = ${exec_prefix}/usr/bin +usrsbindir = ${exec_prefix}/usr/sbin +mandir = ${prefix}/usr/share/man +devddir = ${etcdir}/dev.d/default +configdir = ${etcdir}/udev/ +initdir = ${etcdir}/init.d/ +srcdir = . + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL_PROGRAM} + +override CFLAGS+=-D_FILE_OFFSET_BITS=64 + +OBJS = ../../udev.a ../../libsysfs/sysfs.a + +.c.o: + $(QUIET) $(CC) $(CFLAGS) -c -o $@ $< + +$(DEVD): $(HEADERS) $(DEVD).o run_directory.o + $(QUIET) $(LD) $(LDFLAGS) -o $(DEVD) $(DEVD).o run_directory.o $(OBJS) + +$(HOTPLUGD): $(HEADERS) $(HOTPLUGD).o run_directory.o + $(QUIET) $(LD) $(LDFLAGS) -o $(HOTPLUGD) $(HOTPLUGD).o run_directory.o $(OBJS) + +clean: + rm -f $(DEVD) $(HOTPLUGD) run_directory.o + +spotless: clean + +install: all + $(INSTALL_PROGRAM) $(DEVD) $(DESTDIR)$(sbindir)/$(DEVD) + $(INSTALL_PROGRAM) $(HOTPLUGD) $(DESTDIR)$(sbindir)/$(HOTPLUGD) + +uninstall: + - rm $(DESTDIR)$(sbindir)/$(DEVD) diff --git a/extras/run_directory/run_directory.c b/extras/run_directory/run_directory.c new file mode 100644 index 0000000000..e6c6173eca --- /dev/null +++ b/extras/run_directory/run_directory.c @@ -0,0 +1,79 @@ +/* + * udev_run_directory.c - directory multiplexer + * + * Copyright (C) 2005 Kay Sievers + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../udev_utils.h" +#include "../../list.h" +#include "../../logging.h" + +int run_directory(const char *dir, const char *suffix, const char *subsystem); + +static int run_program(const char *filename, const char *subsystem) +{ + pid_t pid; + + dbg("running %s", filename); + pid = fork(); + switch (pid) { + case 0: + /* child */ + execl(filename, filename, subsystem, NULL); + dbg("exec of child failed"); + _exit(1); + case -1: + dbg("fork of child failed"); + break; + return -1; + default: + waitpid(pid, NULL, 0); + } + + return 0; +} + +int run_directory(const char *dir, const char *suffix, const char *subsystem) +{ + char dirname[NAME_SIZE]; + struct name_entry *name_loop, *name_tmp; + LIST_HEAD(name_list); + + if (subsystem) { + snprintf(dirname, sizeof(dirname), "%s/%s", dir, subsystem); + dirname[sizeof(dirname)-1] = '\0'; + dbg("looking at '%s'", dirname); + add_matching_files(&name_list, dirname, suffix); + } + + snprintf(dirname, sizeof(dirname), "%s/default", dir); + dirname[sizeof(dirname)-1] = '\0'; + dbg("looking at '%s'", dirname); + add_matching_files(&name_list, dirname, suffix); + + list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) { + run_program(name_loop->name, subsystem); + list_del(&name_loop->node); + } + + logging_close(); + return 0; +} diff --git a/extras/run_directory/udev_run_devd.c b/extras/run_directory/udev_run_devd.c new file mode 100644 index 0000000000..02bbc8c353 --- /dev/null +++ b/extras/run_directory/udev_run_devd.c @@ -0,0 +1,78 @@ +/* + * udev_run_devd.c - directory multiplexer + * + * Copyright (C) 2005 Kay Sievers + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../udev_utils.h" +#include "../../list.h" +#include "../../logging.h" + +extern int run_directory(const char *dir, const char *suffix, const char *subsystem); + +#ifdef USE_LOG +void log_message (int priority, const char *format, ...) +{ + va_list args; + static int udev_log = -1; + + if (udev_log == -1) { + const char *value; + + value = getenv("UDEV_LOG"); + if (value) + udev_log = log_priority(value); + else + udev_log = LOG_ERR; + } + + if (priority > udev_log) + return; + + va_start(args, format); + vsyslog(priority, format, args); + va_end(args); +} +#endif + +int main(int argc, char *argv[], char *envp[]) +{ + const char *subsystem; + int fd; + + if (getenv("DEVNAME") == NULL) + exit(0); + + subsystem = argv[1]; + logging_init("udev_run_devd"); + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, STDOUT_FILENO); + dup2(fd, STDIN_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + dbg("running dev.d directory"); + + run_directory("/etc/dev.d", ".dev", subsystem); + exit(0); +} diff --git a/extras/run_directory/udev_run_hotplugd.c b/extras/run_directory/udev_run_hotplugd.c new file mode 100644 index 0000000000..463473d7c7 --- /dev/null +++ b/extras/run_directory/udev_run_hotplugd.c @@ -0,0 +1,79 @@ +/* + * udev_run_hotplugd.c - directory multiplexer + * + * Copyright (C) 2005 Kay Sievers + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../udev_utils.h" +#include "../../list.h" +#include "../../logging.h" + +extern int run_directory(const char *dir, const char *suffix, const char *subsystem); + +#ifdef USE_LOG +void log_message (int priority, const char *format, ...) +{ + va_list args; + static int udev_log = -1; + + if (udev_log == -1) { + const char *value; + + value = getenv("UDEV_LOG"); + if (value) + udev_log = log_priority(value); + else + udev_log = LOG_ERR; + } + + if (priority > udev_log) + return; + + va_start(args, format); + vsyslog(priority, format, args); + va_end(args); +} +#endif + +int main(int argc, char *argv[], char *envp[]) +{ + const char *subsystem; + int fd; + + if (getenv("DEVNAME") == NULL) + exit(0); + + subsystem = argv[1]; + logging_init("udev_run_hotplugd"); + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, STDOUT_FILENO); + dup2(fd, STDIN_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + + dbg("running dev.d directory"); + + run_directory("/etc/hotplug.d", ".hotplug", subsystem); + exit(0); +} diff --git a/test/simple-build-check.sh b/test/simple-build-check.sh index d1e13e69ed..b653185b26 100644 --- a/test/simple-build-check.sh +++ b/test/simple-build-check.sh @@ -1,6 +1,6 @@ #/bin/sh -EXTRAS="extras/chassis_id extras/scsi_id extras/volume_id" +EXTRAS="extras/chassis_id extras/scsi_id extras/volume_id extras/run_directory" [ -z "$KERNEL_DIR" ] && KERNEL_DIR=/lib/modules/`uname -r`/build echo KERNEL_DIR: "$KERNEL_DIR" diff --git a/udev.c b/udev.c index 2be4c35740..999d25d4e5 100644 --- a/udev.c +++ b/udev.c @@ -219,10 +219,6 @@ int main(int argc, char *argv[], char *envp[]) execute_command(name_loop->name, udev.subsystem); } - /* run dev.d/ scripts if we created/deleted a node or changed a netif name */ - if (udev_dev_d && udev.devname[0] != '\0') - udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX); - } else if (udev.type == DEV_DEVICE) { if (strcmp(action, "add") == 0) { /* wait for sysfs */ diff --git a/udev.h b/udev.h index c6f26b3bfb..2c3377ad2e 100644 --- a/udev.h +++ b/udev.h @@ -102,7 +102,6 @@ extern char udev_config_filename[PATH_SIZE]; extern char udev_rules_filename[PATH_SIZE]; extern int udev_log_priority; extern int udev_run; -extern int udev_dev_d; extern int udev_hotplug_d; #endif diff --git a/udev_config.c b/udev_config.c index 6bc070d63a..0701d37e84 100644 --- a/udev_config.c +++ b/udev_config.c @@ -45,40 +45,8 @@ char udev_config_filename[PATH_SIZE]; char udev_rules_filename[PATH_SIZE]; int udev_log_priority; int udev_run; -int udev_dev_d; int udev_hotplug_d; -static int string_is_true(const char *str) -{ - if (strcasecmp(str, "true") == 0) - return 1; - if (strcasecmp(str, "yes") == 0) - return 1; - if (strcasecmp(str, "1") == 0) - return 1; - return 0; -} - -static int log_priority(const char *priority) -{ - char *endptr; - int prio; - - prio = strtol(priority, &endptr, 10); - if (endptr[0] == '\0') - return prio; - if (strncasecmp(priority, "err", 3) == 0) - return LOG_ERR; - if (strcasecmp(priority, "info") == 0) - return LOG_INFO; - if (strcasecmp(priority, "debug") == 0) - return LOG_DEBUG; - if (string_is_true(priority)) - return LOG_ERR; - - return 0; -} - static int get_key(char **line, char **key, char **value) { char *linepos; @@ -219,7 +187,6 @@ void udev_init_config(void) strcpy(udev_rules_filename, UDEV_RULES_FILE); udev_log_priority = LOG_ERR; udev_run = 1; - udev_dev_d = 1; udev_hotplug_d = 1; sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path)); @@ -228,10 +195,6 @@ void udev_init_config(void) if (env && !string_is_true(env)) udev_run = 0; - env = getenv("UDEV_NO_DEVD"); - if (env && string_is_true(env)) - udev_dev_d = 0; - env = getenv("UDEV_NO_HOTPLUGD"); if (env && string_is_true(env)) udev_hotplug_d = 0; diff --git a/udev_utils.c b/udev_utils.c index 74b55ed406..70b20e3a28 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,37 @@ void udev_cleanup_device(struct udevice *udev) } } +int string_is_true(const char *str) +{ + if (strcasecmp(str, "true") == 0) + return 1; + if (strcasecmp(str, "yes") == 0) + return 1; + if (strcasecmp(str, "1") == 0) + return 1; + return 0; +} + +int log_priority(const char *priority) +{ + char *endptr; + int prio; + + prio = strtol(priority, &endptr, 10); + if (endptr[0] == '\0') + return prio; + if (strncasecmp(priority, "err", 3) == 0) + return LOG_ERR; + if (strcasecmp(priority, "info") == 0) + return LOG_INFO; + if (strcasecmp(priority, "debug") == 0) + return LOG_DEBUG; + if (string_is_true(priority)) + return LOG_ERR; + + return 0; +} + int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel) { static unsigned int kversion = 0; diff --git a/udev_utils.h b/udev_utils.h index 9cdae6db57..b3e604fb98 100644 --- a/udev_utils.h +++ b/udev_utils.h @@ -34,6 +34,8 @@ extern void udev_cleanup_device(struct udevice *udev); extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel); extern int create_path(const char *path); +extern int log_priority(const char *priority); +extern int string_is_true(const char *str); extern int parse_get_pair(char **orig_string, char **left, char **right); extern int unlink_secure(const char *filename); extern int file_map(const char *filename, char **buf, size_t *bufsize); diff --git a/udevstart.c b/udevstart.c index 60e63c5ad8..34f3835d65 100644 --- a/udevstart.c +++ b/udevstart.c @@ -137,10 +137,6 @@ static int add_device(const char *path, const char *subsystem) execute_command(name_loop->name, udev.subsystem); } - /* run dev.d/ scripts if we created a node or changed a netif name */ - if (udev_dev_d && udev.devname[0] != '\0') - udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX); - sysfs_close_class_device(class_dev); udev_cleanup_device(&udev); From 995aec875973e29caf42b037736349fc8839ee40 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 05:13:33 +0200 Subject: [PATCH 08/24] udev: clear lists if a new value is assigned Former values are cleared if SYMLINK= is used. To add a value SYMLINK+= is now needed. Signed-off-by: Kay Sievers --- test/udev-test.pl | 63 +++++++++++++++++++++++++++++++---------------- udev_rules.c | 18 ++++++++++++++ udev_utils.c | 4 +++ 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/test/udev-test.pl b/test/udev-test.pl index 27fe35456e..884abf9e8b 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -783,9 +783,9 @@ EOF exp_name => "symlink-only2", exp_target => "link", rules => < "yes", exp_rem_error => "yes", rules => < "yes", option => "clean", rules => < "symlink0", exp_target => "ttyUSB0", rules => < "symlink-ttyUSB0", exp_target => "ttyUSB0", rules => < "major-188:0", exp_target => "ttyUSB0", rules => < "symlink-0:0:0:0", exp_target => "node", rules => < "test", exp_target => "ttyUSB0", rules => < "test", exp_target => "ttyUSB0", rules => < "this", exp_target => "ttyUSB0", rules => < "test", exp_target => "link", rules => < "188:0", exp_target => "ttyUSB0", rules => < "188", exp_target => "ttyUSB0", rules => < "percent%sign", exp_target => "ttyUSB0", rules => < "%ttyUSB0_name", exp_target => "ttyUSB0", rules => < "link1", exp_target => "node", rules => < "link4", exp_target => "node", rules => < "/block/sda/sda1", exp_name => "last", rules => < "reset list to current value", + subsys => "tty", + devpath => "/class/tty/ttyUSB0", + exp_name => "three", + not_exp_name => "two", + exp_target => "node", + rules => <{exp_name}"); + if (defined($rules->{not_exp_name})) { + if ((-e "$PWD/$udev_root$rules->{not_exp_name}") || + (-l "$PWD/$udev_root$rules->{not_exp_name}")) { + print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n"; + $error++ + } + } if (defined($rules->{exp_perms})) { permissions_test($rules, $uid, $gid, $mode); } diff --git a/udev_rules.c b/udev_rules.c index 42509f16ce..631cc4270a 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -782,6 +782,15 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL) udev->symlink_final = 1; + else if (rule->symlink_operation == KEY_OP_ASSIGN) { + struct name_entry *name_loop; + struct name_entry *temp_loop; + + list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) { + list_del(&name_loop->node); + free(name_loop); + } + } info("configured rule in '%s[%i]' applied, added symlink '%s'", rule->config_file, rule->config_line, rule->symlink); strlcpy(temp, rule->symlink, sizeof(temp)); @@ -821,6 +830,15 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d if (rule->run_operation == KEY_OP_ASSIGN_FINAL) udev->run_final = 1; + else if (rule->run_operation == KEY_OP_ASSIGN) { + struct name_entry *name_loop; + struct name_entry *temp_loop; + + list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { + list_del(&name_loop->node); + free(name_loop); + } + } strlcpy(program, rule->run, sizeof(program)); apply_format(udev, program, sizeof(program), class_dev, sysfs_device); dbg("add run '%s'", program); diff --git a/udev_utils.c b/udev_utils.c index 70b20e3a28..d605631088 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -108,6 +108,10 @@ void udev_cleanup_device(struct udevice *udev) list_del(&name_loop->node); free(name_loop); } + list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { + list_del(&name_loop->node); + free(name_loop); + } } int string_is_true(const char *str) From c2401132bf72cbda6555f1ef4403851c14faeba5 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 05:17:21 +0200 Subject: [PATCH 09/24] volume_id: use udev-provided log-level Signed-off-by: Kay Sievers --- extras/volume_id/Makefile | 2 +- extras/volume_id/udev_volume_id.c | 18 ++++++++++++++++-- udev.c | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/extras/volume_id/Makefile b/extras/volume_id/Makefile index 91527cc9f5..56fdf278b9 100644 --- a/extras/volume_id/Makefile +++ b/extras/volume_id/Makefile @@ -33,7 +33,7 @@ override CFLAGS+=-D_FILE_OFFSET_BITS=64 VOLUME_ID_BASE=volume_id include $(VOLUME_ID_BASE)/Makefile.inc -OBJS = udev_volume_id.o $(VOLUME_ID_OBJS) $(SYSFS) +OBJS = udev_volume_id.o $(VOLUME_ID_OBJS) ../../udev.a HEADERS = $(VOLUME_ID_HEADERS) $(OBJS): $(HEADERS) diff --git a/extras/volume_id/udev_volume_id.c b/extras/volume_id/udev_volume_id.c index a00b01a27d..7c6fc4050d 100644 --- a/extras/volume_id/udev_volume_id.c +++ b/extras/volume_id/udev_volume_id.c @@ -40,12 +40,26 @@ #define BLKGETSIZE64 _IOR(0x12,114,size_t) #ifdef USE_LOG -void log_message(int level, const char *format, ...) +void log_message(int priority, const char *format, ...) { va_list args; + static int udev_log = -1; + + if (udev_log == -1) { + const char *value; + + value = getenv("UDEV_LOG"); + if (value) + udev_log = log_priority(value); + else + udev_log = LOG_ERR; + } + + if (priority > udev_log) + return; va_start(args, format); - vsyslog(level, format, args); + vsyslog(priority, format, args); va_end(args); } #endif diff --git a/udev.c b/udev.c index 999d25d4e5..3f76e98b24 100644 --- a/udev.c +++ b/udev.c @@ -152,7 +152,7 @@ int main(int argc, char *argv[], char *envp[]) goto hotplug; } - /* export logging flag, as called scripts may want to do the same as udev */ + /* export logging flag, as called programs may want to do the same as udev */ if (udev_log_priority) { char priority[32]; From c07669bd663d780e4957691e488798aa0178e76b Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 15:55:29 +0200 Subject: [PATCH 10/24] udev: handle all events - not only class and block devices Handle all events with rules. If udev is expected to handle hotplug.d/ the exernal helper must be called. Signed-off-by: Kay Sievers --- Makefile | 2 +- extras/run_directory/udev_run_hotplugd.c | 3 - udev.8.in | 28 +--- udev.c | 153 ++++++++---------- udev.h | 9 +- udev.spec | 3 - udev_add.c | 16 -- udev_config.c | 6 - udev_multiplex.c | 92 ----------- udev_remove.c | 26 ++- udev_rules.c | 192 +++++++++-------------- udev_rules.h | 3 +- udev_rules_parse.c | 8 +- udevstart.c | 24 ++- 14 files changed, 177 insertions(+), 388 deletions(-) delete mode 100644 udev_multiplex.c diff --git a/Makefile b/Makefile index 1cf3e54fb7..d36bd5866c 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,6 @@ UDEV_OBJS = \ udev_remove.o \ udev_sysfs.o \ udev_db.o \ - udev_multiplex.o \ udev_rules.o \ udev_rules_parse.o \ udev_libc_wrapper.o @@ -382,6 +381,7 @@ install: install-config install-man install-dev.d all - ln -f -s $(sbindir)/$(SENDER) $(DESTDIR)$(hotplugdir)/10-udev.hotplug ifndef DESTDIR - killall $(DAEMON) + - $(sbindir)/$(DAEMON) -d - rm -rf $(udevdb) endif @extras="$(EXTRAS)" ; for target in $$extras ; do \ diff --git a/extras/run_directory/udev_run_hotplugd.c b/extras/run_directory/udev_run_hotplugd.c index 463473d7c7..54b6bf44e3 100644 --- a/extras/run_directory/udev_run_hotplugd.c +++ b/extras/run_directory/udev_run_hotplugd.c @@ -58,9 +58,6 @@ int main(int argc, char *argv[], char *envp[]) const char *subsystem; int fd; - if (getenv("DEVNAME") == NULL) - exit(0); - subsystem = argv[1]; logging_init("udev_run_hotplugd"); diff --git a/udev.8.in b/udev.8.in index 79c4a83d16..e4c1c11af2 100644 --- a/udev.8.in +++ b/udev.8.in @@ -306,11 +306,9 @@ following the '[' is a '!', any characters not enclosed are matched. .P After device node creation, removal, or network device renaming, .B udev -executes the programs located in the directory tree under -.IR /etc/dev.d/ . -The name of a program must have the suffix -.I .dev -to be recognized. +executes the programs specified by the +.B RUN +key. .br In addition to the kernel provided hotplug environment variables, .B UDEV_LOG @@ -319,15 +317,7 @@ is set and contains the numerical priority value, if udev is configured to use Executed programs may want to follow that setting. .B DEVNAME is exported to make the name of the created node, or the name the network -device is renamed to, available to the executed program. The programs in every -directory are sorted in lexical order, while the directories are searched in -the following order: -.sp -.nf -/etc/dev.d/$(DEVNAME)/*.dev -/etc/dev.d/$(SUBSYSTEM)/*.dev -/etc/dev.d/default/*.dev -.fi +device is renamed to, available to the executed programs. .SH "ENVIRONMENT" .P The following variables are read from the environment: @@ -353,20 +343,10 @@ Overrides the log priority specified in the config file. .TP .B UDEV_RUN If set to "0", it disables the execution of programs added by rules. -.TP -.B UDEV_NO_DEVD -The default behavior of -.B udev -is to execute programs in the -.I /etc/dev.d/ -directory after device handling. If set, -.B udev -will skip this step. .SH "FILES" .nf /sbin/udev udev program /etc/udev/* udev config files -/etc/dev.d/* programs invoked by udev .fi .SH "SEE ALSO" .BR udevinfo (8), diff --git a/udev.c b/udev.c index 3f76e98b24..d623cbcc67 100644 --- a/udev.c +++ b/udev.c @@ -54,39 +54,6 @@ void log_message(int priority, const char *format, ...) } #endif -/* Decide if we should manage the whole uevent, including multiplexing - * of the hotplug directories. - * For now look if the kernel calls udevsend instead of /sbin/hotplug, - * or the uevent-helper in /proc/sys/kernel/hotplug is empty. - */ -static int manage_hotplug_event(void) { - char helper[256]; - int fd; - int len; - - /* don't handle hotplug.d if we are called directly */ - if (!getenv("UDEVD_EVENT")) - return 0; - - fd = open("/proc/sys/kernel/hotplug", O_RDONLY); - if (fd < 0) - return 0; - - len = read(fd, helper, sizeof(helper)-1); - close(fd); - - if (len < 0) - return 0; - helper[len] = '\0'; - - if (helper[0] == '\0' || helper[0] == '\n') - return 1; - if (strstr(helper, "udevsend")) - return 1; - - return 0; -} - static void asmlinkage sig_handler(int signum) { switch (signum) { @@ -100,15 +67,12 @@ static void asmlinkage sig_handler(int signum) int main(int argc, char *argv[], char *envp[]) { - struct sysfs_class_device *class_dev; - struct sysfs_device *devices_dev; struct udevice udev; char path[PATH_SIZE]; const char *error; const char *action; const char *devpath; const char *subsystem; - int managed_event; struct sigaction act; int retval = -EINVAL; @@ -133,11 +97,6 @@ int main(int argc, char *argv[], char *envp[]) /* trigger timeout to prevent hanging processes */ alarm(ALARM_TIMEOUT); - /* let the executed programs know if we handle the whole hotplug event */ - managed_event = manage_hotplug_event(); - if (managed_event) - setenv("MANAGED_EVENT", "1", 1); - action = getenv("ACTION"); devpath = getenv("DEVPATH"); subsystem = getenv("SUBSYSTEM"); @@ -145,14 +104,12 @@ int main(int argc, char *argv[], char *envp[]) if (!subsystem && argc == 2) subsystem = argv[1]; - udev_init_device(&udev, devpath, subsystem, action); - if (!action || !subsystem || !devpath) { err("action, subsystem or devpath missing"); - goto hotplug; + goto exit; } - /* export logging flag, as called programs may want to do the same as udev */ + /* export log_level , as called programs may want to do the same as udev */ if (udev_log_priority) { char priority[32]; @@ -160,93 +117,109 @@ int main(int argc, char *argv[], char *envp[]) setenv("UDEV_LOG", priority, 1); } + udev_init_device(&udev, devpath, subsystem, action); + udev_rules_init(); + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) { - udev_rules_init(); - + /* handle device node */ if (strcmp(action, "add") == 0) { - /* wait for sysfs and possibly add node */ - dbg("udev add"); - - /* skip subsystems without "dev", but handle net devices */ - if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) { - dbg("don't care about '%s' devices", udev.subsystem); - goto hotplug; - } + struct sysfs_class_device *class_dev; + /* wait for sysfs of /sys/class /sys/block */ + dbg("node add"); snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath); path[sizeof(path)-1] = '\0'; class_dev = wait_class_device_open(path); if (class_dev == NULL) { dbg("open class device failed"); - goto hotplug; + goto run; } dbg("opened class_dev->name='%s'", class_dev->name); - wait_for_class_device(class_dev, &error); - /* name, create node, store in db */ - retval = udev_add_device(&udev, class_dev); + /* get major/minor */ + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS) { + udev.devt = get_devt(class_dev); + if (udev.devt) { + /* name device */ + udev_rules_get_name(&udev, class_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + if (udev.name[0] == '\0') { + info("device node creation supressed"); + goto run; + } + /* create node, store in db */ + retval = udev_add_device(&udev, class_dev); + } else { + dbg("no dev-file found"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + } + } sysfs_close_class_device(class_dev); } else if (strcmp(action, "remove") == 0) { - /* possibly remove a node */ - dbg("udev remove"); - - /* skip subsystems without "dev" */ - if (subsystem_expect_no_dev(udev.subsystem)) { - dbg("don't care about '%s' devices", udev.subsystem); - goto hotplug; - } - - udev_rules_get_run(&udev); + dbg("node remove"); + udev_rules_get_run(&udev, NULL); if (udev.ignore_device) { dbg("device event will be ignored"); - goto hotplug; + goto exit; } - /* get node from db, remove db-entry, delete created node */ + /* get name from db, remove db-entry, delete node */ retval = udev_remove_device(&udev); } + /* export name of device node or netif */ if (udev.devname[0] != '\0') setenv("DEVNAME", udev.devname, 1); - - if (udev_run && !list_empty(&udev.run_list)) { - struct name_entry *name_loop; - - dbg("executing run list"); - list_for_each_entry(name_loop, &udev.run_list, node) - execute_command(name_loop->name, udev.subsystem); - } - } else if (udev.type == DEV_DEVICE) { if (strcmp(action, "add") == 0) { - /* wait for sysfs */ - dbg("devices add"); + struct sysfs_device *devices_dev; + /* wait for sysfs of /sys/devices/ */ + dbg("devices add"); snprintf(path, sizeof(path), "%s%s", sysfs_path, devpath); path[sizeof(path)-1] = '\0'; devices_dev = wait_devices_device_open(path); if (!devices_dev) { dbg("devices device unavailable (probably remove has beaten us)"); - goto hotplug; + goto run; } dbg("devices device opened '%s'", path); - wait_for_devices_device(devices_dev, &error); - + udev_rules_get_run(&udev, devices_dev); sysfs_close_device(devices_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } } else if (strcmp(action, "remove") == 0) { dbg("devices remove"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } } - } else { - dbg("unhandled"); } -hotplug: - if (udev_hotplug_d && managed_event) - udev_multiplex_directory(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX); +run: + if (udev_run && !list_empty(&udev.run_list)) { + struct name_entry *name_loop; + dbg("executing run list"); + list_for_each_entry(name_loop, &udev.run_list, node) + execute_command(name_loop->name, udev.subsystem); + } + +exit: udev_cleanup_device(&udev); logging_close(); diff --git a/udev.h b/udev.h index 2c3377ad2e..11fbe02460 100644 --- a/udev.h +++ b/udev.h @@ -39,12 +39,6 @@ #define SEQNUM_SIZE 32 #define VALUE_SIZE 128 -#define DEVD_DIR "/etc/dev.d" -#define DEVD_SUFFIX ".dev" - -#define HOTPLUGD_DIR "/etc/hotplug.d" -#define HOTPLUG_SUFFIX ".hotplug" - #define DEFAULT_PARTITIONS_COUNT 15 enum device_type { @@ -62,6 +56,7 @@ struct udevice { enum device_type type; char name[PATH_SIZE]; + int name_set; char devname[PATH_SIZE]; struct list_head symlink_list; int symlink_final; @@ -92,7 +87,6 @@ extern int udev_add_device(struct udevice *udev, struct sysfs_class_device *clas extern int udev_remove_device(struct udevice *udev); extern void udev_init_config(void); extern int udev_start(void); -extern void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix); extern int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid); extern char sysfs_path[PATH_SIZE]; @@ -102,6 +96,5 @@ extern char udev_config_filename[PATH_SIZE]; extern char udev_rules_filename[PATH_SIZE]; extern int udev_log_priority; extern int udev_run; -extern int udev_hotplug_d; #endif diff --git a/udev.spec b/udev.spec index 28f19565da..0430a1259d 100644 --- a/udev.spec +++ b/udev.spec @@ -112,9 +112,6 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) /etc/hotplug.d/default/udev.hotplug %attr(755,root,root) /etc/init.d/udev %attr(0644,root,root) %{_mandir}/man8/udev*.8* -%attr(755,root,root) %dir /etc/dev.d/ -%attr(755,root,root) %dir /etc/dev.d/net/ -%attr(0755,root,root) /etc/dev.d/net/hotplug.dev %if %{scsi_id} %attr(755,root,root) /sbin/scsi_id diff --git a/udev_add.c b/udev_add.c index 9764cb9bcd..2081e503c7 100644 --- a/udev_add.c +++ b/udev_add.c @@ -268,22 +268,7 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev) char *pos; int retval = 0; - if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) { - udev->devt = get_devt(class_dev); - if (!udev->devt) { - dbg("no dev-file found, do nothing"); - return 0; - } - } - - udev_rules_get_name(udev, class_dev); - if (udev->ignore_device) { - dbg("device event will be ignored"); - return 0; - } - dbg("adding name='%s'", udev->name); - selinux_init(); if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) { @@ -325,6 +310,5 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev) exit: selinux_exit(); - return retval; } diff --git a/udev_config.c b/udev_config.c index 0701d37e84..773ee67f9e 100644 --- a/udev_config.c +++ b/udev_config.c @@ -45,7 +45,6 @@ char udev_config_filename[PATH_SIZE]; char udev_rules_filename[PATH_SIZE]; int udev_log_priority; int udev_run; -int udev_hotplug_d; static int get_key(char **line, char **key, char **value) { @@ -187,7 +186,6 @@ void udev_init_config(void) strcpy(udev_rules_filename, UDEV_RULES_FILE); udev_log_priority = LOG_ERR; udev_run = 1; - udev_hotplug_d = 1; sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path)); /* disable RUN key execution */ @@ -195,10 +193,6 @@ void udev_init_config(void) if (env && !string_is_true(env)) udev_run = 0; - env = getenv("UDEV_NO_HOTPLUGD"); - if (env && string_is_true(env)) - udev_hotplug_d = 0; - env = getenv("UDEV_CONFIG_FILE"); if (env) { strlcpy(udev_config_filename, env, sizeof(udev_config_filename)); diff --git a/udev_multiplex.c b/udev_multiplex.c deleted file mode 100644 index 22bbaf7b61..0000000000 --- a/udev_multiplex.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * udev_multiplex.c directory multiplexer - * - * Copyright (C) 2004 Greg Kroah-Hartman - * - * 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 essentially emulates the following shell script logic in C: - * DIR="/etc/dev.d" - * export DEVNAME="whatever_dev_name_udev_just_gave" - * for I in "${DIR}/$DEVNAME/"*.dev "${DIR}/$1/"*.dev "${DIR}/default/"*.dev ; do - * if [ -f $I ]; then $I $1 ; fi - * done - * exit 1; - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" -#include "udev_libc_wrapper.h" -#include "udev_utils.h" -#include "logging.h" - - -/* - * runs files in these directories in order: - * / - * subsystem/ - * default/ - */ -void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix) -{ - char dirname[PATH_SIZE]; - struct name_entry *name_loop, *name_tmp; - LIST_HEAD(name_list); - - /* chop the device name up into pieces based on '/' */ - if (udev->name[0] != '\0') { - char devname[PATH_SIZE]; - char *temp; - - strlcpy(devname, udev->name, sizeof(devname)); - temp = strchr(devname, '/'); - while (temp != NULL) { - temp[0] = '\0'; - - /* don't call the subsystem directory here */ - if (strcmp(devname, udev->subsystem) != 0) { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, devname); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - temp[0] = '/'; - ++temp; - temp = strchr(temp, '/'); - } - } - - if (udev->name[0] != '\0') { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->name); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - if (udev->subsystem[0] != '\0') { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->subsystem); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - snprintf(dirname, sizeof(dirname), "%s/default", basedir); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - - list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) { - execute_command(name_loop->name, udev->subsystem); - list_del(&name_loop->node); - } - -} diff --git a/udev_remove.c b/udev_remove.c index 2df555327b..cf28ff37a9 100644 --- a/udev_remove.c +++ b/udev_remove.c @@ -140,26 +140,20 @@ static int delete_node(struct udevice *udev) */ int udev_remove_device(struct udevice *udev) { - const char *temp; - if (udev->type != DEV_BLOCK && udev->type != DEV_CLASS) return 0; - if (udev_db_get_device(udev, udev->devpath) == 0) { - if (udev->ignore_remove) { - dbg("remove event for '%s' requested to be ignored by rule", udev->name); - return 0; - } - dbg("remove name='%s'", udev->name); - udev_db_delete_device(udev); - } else { - /* fall back to kernel name */ - temp = strrchr(udev->devpath, '/'); - if (temp == NULL) - return -ENODEV; - strlcpy(udev->name, &temp[1], sizeof(udev->name)); - info("'%s' not found in database, falling back on default name", udev->name); + /* remove node only if we can find it in our database */ + if (udev_db_get_device(udev, udev->devpath) != 0) { + dbg("'%s' not found in database, ignore event", udev->name); + return -1; } + if (udev->ignore_remove) { + dbg("remove event for '%s' requested to be ignored by rule", udev->name); + return 0; + } + dbg("remove name='%s'", udev->name); + udev_db_delete_device(udev); /* use full path to the environment */ snprintf(udev->devname, sizeof(udev->devname), "%s/%s", udev_root, udev->name); diff --git a/udev_rules.c b/udev_rules.c index 631cc4270a..cbd76e66eb 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -731,7 +731,7 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d list_for_each_entry(rule, &udev_rule_list, node) { dbg("process rule"); if (match_rule(udev, rule, class_dev, sysfs_device) == 0) { - if (udev->name[0] != '\0' && rule->name[0] != '\0') { + if (udev->name_set && rule->name_operation != KEY_OP_UNSET) { dbg("node name already set, rule ignored"); continue; } @@ -776,73 +776,84 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d } /* collect symlinks */ - if (!udev->symlink_final && rule->symlink[0] != '\0') { + if (!udev->symlink_final && rule->symlink_operation != KEY_OP_UNSET) { char temp[PATH_SIZE]; char *pos, *next; if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL) udev->symlink_final = 1; - else if (rule->symlink_operation == KEY_OP_ASSIGN) { + if (rule->symlink_operation == KEY_OP_ASSIGN || rule->symlink_operation == KEY_OP_ASSIGN_FINAL) { struct name_entry *name_loop; struct name_entry *temp_loop; + info("reset symlink list"); list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) { list_del(&name_loop->node); free(name_loop); } } - info("configured rule in '%s[%i]' applied, added symlink '%s'", - rule->config_file, rule->config_line, rule->symlink); - strlcpy(temp, rule->symlink, sizeof(temp)); - apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); + if (rule->symlink[0] != '\0') { + info("configured rule in '%s[%i]' applied, added symlink '%s'", + rule->config_file, rule->config_line, rule->symlink); + strlcpy(temp, rule->symlink, sizeof(temp)); + apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); - /* add multiple symlinks separated by spaces */ - pos = temp; - next = strchr(temp, ' '); - while (next) { - next[0] = '\0'; + /* add multiple symlinks separated by spaces */ + pos = temp; + next = strchr(temp, ' '); + while (next) { + next[0] = '\0'; + info("add symlink '%s'", pos); + name_list_add(&udev->symlink_list, pos, 0); + pos = &next[1]; + next = strchr(pos, ' '); + } info("add symlink '%s'", pos); name_list_add(&udev->symlink_list, pos, 0); - pos = &next[1]; - next = strchr(pos, ' '); } - info("add symlink '%s'", pos); - name_list_add(&udev->symlink_list, pos, 0); } /* set name, later rules with name set will be ignored */ - if (rule->name[0] != '\0') { - info("configured rule in '%s[%i]' applied, '%s' becomes '%s'", - rule->config_file, rule->config_line, udev->kernel_name, rule->name); + if (rule->name_operation != KEY_OP_UNSET) { + udev->name_set = 1; + if (rule->name[0] == '\0') { + info("configured rule in '%s[%i]' applied, node handling for '%s' supressed", + rule->config_file, rule->config_line, udev->kernel_name); + } else { + strlcpy(udev->name, rule->name, sizeof(udev->name)); + apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); + strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file)); + udev->config_line = rule->config_line; - strlcpy(udev->name, rule->name, sizeof(udev->name)); - apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); - strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file)); - udev->config_line = rule->config_line; - - if (udev->type != DEV_NET) - dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i", - udev->name, udev->owner, udev->group, udev->mode, udev->partitions); + info("configured rule in '%s:%i' applied, '%s' becomes '%s'", + rule->config_file, rule->config_line, udev->kernel_name, rule->name); + if (udev->type != DEV_NET) + dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i", + udev->name, udev->owner, udev->group, udev->mode, udev->partitions); + } } - if (!udev->run_final && rule->run[0] != '\0') { + if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) { char program[PATH_SIZE]; if (rule->run_operation == KEY_OP_ASSIGN_FINAL) udev->run_final = 1; - else if (rule->run_operation == KEY_OP_ASSIGN) { + if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) { struct name_entry *name_loop; struct name_entry *temp_loop; + info("reset run list"); list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { list_del(&name_loop->node); free(name_loop); } } - strlcpy(program, rule->run, sizeof(program)); - apply_format(udev, program, sizeof(program), class_dev, sysfs_device); - dbg("add run '%s'", program); - name_list_add(&udev->run_list, program, 0); + if (rule->run[0] != '\0') { + strlcpy(program, rule->run, sizeof(program)); + apply_format(udev, program, sizeof(program), class_dev, sysfs_device); + dbg("add run '%s'", program); + name_list_add(&udev->run_list, program, 0); + } } if (rule->last_rule) { @@ -866,113 +877,58 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d return 0; } -int udev_rules_get_run(struct udevice *udev) +int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device) { struct udev_rule *rule; - char program[PATH_SIZE]; /* look for a matching rule to apply */ list_for_each_entry(rule, &udev_rule_list, node) { dbg("process rule"); - if (rule->run[0] == '\0') + if (rule->run_operation == KEY_OP_UNSET) continue; - if (rule->name[0] != '\0' || rule->symlink[0] != '\0' || + if (rule->name_operation != KEY_OP_UNSET || rule->symlink_operation != KEY_OP_UNSET || rule->mode != 0000 || rule->owner[0] != '\0' || rule->group[0] != '\0') { dbg("skip rule that names a device"); continue; } - if (rule->action_operation != KEY_OP_UNSET) { - dbg("check for " KEY_ACTION " rule->action='%s' udev->action='%s'", - rule->action, udev->action); - if (strcmp_pattern(rule->action, udev->action) != 0) { - dbg(KEY_ACTION " is not matching"); - if (rule->action_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_ACTION " matches"); - if (rule->action_operation == KEY_OP_NOMATCH) - continue; + if (match_rule(udev, rule, NULL, sysfs_device) == 0) { + if (rule->ignore_device) { + info("configured rule in '%s[%i]' applied, '%s' is ignored", + rule->config_file, rule->config_line, udev->kernel_name); + udev->ignore_device = 1; + return 0; } - dbg(KEY_ACTION " key is true"); - } - if (rule->kernel_operation != KEY_OP_UNSET) { - dbg("check for " KEY_KERNEL " rule->kernel='%s' udev->kernel_name='%s'", - rule->kernel, udev->kernel_name); - if (strcmp_pattern(rule->kernel, udev->kernel_name) != 0) { - dbg(KEY_KERNEL " is not matching"); - if (rule->kernel_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_KERNEL " matches"); - if (rule->kernel_operation == KEY_OP_NOMATCH) - continue; - } - dbg(KEY_KERNEL " key is true"); - } + if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) { + char program[PATH_SIZE]; - if (rule->subsystem_operation != KEY_OP_UNSET) { - dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' udev->subsystem='%s'", - rule->subsystem, udev->subsystem); - if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) { - dbg(KEY_SUBSYSTEM " is not matching"); - if (rule->subsystem_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_SUBSYSTEM " matches"); - if (rule->subsystem_operation == KEY_OP_NOMATCH) - continue; - } - dbg(KEY_SUBSYSTEM " key is true"); - } + if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) { + struct name_entry *name_loop; + struct name_entry *temp_loop; - if (rule->env_pair_count) { - int i; - - dbg("check for " KEY_ENV " pairs"); - for (i = 0; i < rule->env_pair_count; i++) { - struct key_pair *pair; - const char *value; - - pair = &rule->env_pair[i]; - value = getenv(pair->name); - if (!value) { - dbg(KEY_ENV "{'%s'} is not found", pair->name); - continue; + info("reset run list"); + list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { + list_del(&name_loop->node); + free(name_loop); + } } - if (strcmp_pattern(pair->value, value) != 0) { - dbg(KEY_ENV "{'%s'} is not matching", pair->name); - if (pair->operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_ENV "{'%s'} matches", pair->name); - if (pair->operation == KEY_OP_NOMATCH) - continue; + if (rule->run[0] != '\0') { + strlcpy(program, rule->run, sizeof(program)); + apply_format(udev, program, sizeof(program), NULL, NULL); + dbg("add run '%s'", program); + name_list_add(&udev->run_list, program, 0); } + if (rule->run_operation == KEY_OP_ASSIGN_FINAL) + break; } - dbg(KEY_ENV " key is true"); - } - /* rule matches */ - - if (rule->ignore_device) { - info("configured rule in '%s[%i]' applied, '%s' is ignored", - rule->config_file, rule->config_line, udev->kernel_name); - udev->ignore_device = 1; - return 0; - } - - strlcpy(program, rule->run, sizeof(program)); - apply_format(udev, program, sizeof(program), NULL, NULL); - dbg("add run '%s'", program); - name_list_add(&udev->run_list, program, 0); - - if (rule->last_rule) { - dbg("last rule to be applied"); - break; + if (rule->last_rule) { + dbg("last rule to be applied"); + break; + } } } diff --git a/udev_rules.h b/udev_rules.h index f4a74bba45..75ffd5cb0f 100644 --- a/udev_rules.h +++ b/udev_rules.h @@ -96,6 +96,7 @@ struct udev_rule { int env_pair_count; char name[PATH_SIZE]; + enum key_operation name_operation; char symlink[PATH_SIZE]; enum key_operation symlink_operation; char owner[USER_SIZE]; @@ -120,7 +121,7 @@ extern struct list_head udev_rule_list; extern int udev_rules_init(void); extern int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev); -extern int udev_rules_get_run(struct udevice *udev); +extern int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device); extern void udev_rules_close(void); #endif diff --git a/udev_rules_parse.c b/udev_rules_parse.c index 3f07521ccb..57c797dd31 100644 --- a/udev_rules_parse.c +++ b/udev_rules_parse.c @@ -349,21 +349,19 @@ static int rules_parse(const char *filename) if (strncasecmp(key, KEY_NAME, sizeof(KEY_NAME)-1) == 0) { attr = get_key_attribute(key + sizeof(KEY_NAME)-1); - /* FIXME: remove old style options and make OPTIONS= mandatory */ if (attr != NULL) { if (strstr(attr, OPTION_PARTITIONS) != NULL) { dbg("creation of partition nodes requested"); rule.partitions = DEFAULT_PARTITIONS_COUNT; } + /* FIXME: remove old style option and make OPTIONS= mandatory */ if (strstr(attr, OPTION_IGNORE_REMOVE) != NULL) { dbg("remove event should be ignored"); rule.ignore_remove = 1; } } - if (value[0] != '\0') - strlcpy(rule.name, value, sizeof(rule.name)); - else - rule.ignore_device = 1; + rule.name_operation = operation; + strlcpy(rule.name, value, sizeof(rule.name)); valid = 1; continue; } diff --git a/udevstart.c b/udevstart.c index 34f3835d65..d1a0a8379c 100644 --- a/udevstart.c +++ b/udevstart.c @@ -37,6 +37,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "udev_libc_wrapper.h" +#include "udev_sysfs.h" #include "udev.h" #include "udev_version.h" #include "logging.h" @@ -110,25 +111,37 @@ static int add_device(const char *path, const char *subsystem) const char *devpath; devpath = &path[strlen(sysfs_path)]; - - /* set environment for callouts and dev.d/ */ setenv("DEVPATH", devpath, 1); setenv("SUBSYSTEM", subsystem, 1); - dbg("exec: '%s' (%s)\n", devpath, path); class_dev = sysfs_open_class_device_path(path); if (class_dev == NULL) { dbg ("sysfs_open_class_device_path failed"); - return -ENODEV; + return -1; } udev_init_device(&udev, devpath, subsystem, "add"); - udev_add_device(&udev, class_dev); + udev.devt = get_devt(class_dev); + if (!udev.devt) { + dbg ("sysfs_open_class_device_path failed"); + return -1; + } + udev_rules_get_name(&udev, class_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + if (udev.name[0] == '\0') { + info("device node creation supressed"); + goto run; + } + udev_add_device(&udev, class_dev); if (udev.devname[0] != '\0') setenv("DEVNAME", udev.devname, 1); +run: if (udev_run && !list_empty(&udev.run_list)) { struct name_entry *name_loop; @@ -137,6 +150,7 @@ static int add_device(const char *path, const char *subsystem) execute_command(name_loop->name, udev.subsystem); } +exit: sysfs_close_class_device(class_dev); udev_cleanup_device(&udev); From 9607c4222c08c2d3def2faeac62f6cca5d3ce119 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 17:11:09 +0200 Subject: [PATCH 11/24] klibc: version 1.0.14 Signed-off-by: Kay Sievers --- klibc/Makefile | 5 +++ klibc/include/{net => netinet}/if_ether.h | 0 klibc/include/netpacket/packet.h | 1 + klibc/include/signal.h | 4 --- klibc/klcc.1 | 43 ++++++++++++++++++++--- klibc/klcc.in | 15 ++++++-- klibc/klibc/SYSCALLS.def | 32 +++++++++++------ klibc/klibc/arch/i386/Makefile.inc | 1 + klibc/klibc/arch/x86_64/MCONFIG | 5 +++ klibc/klibc/arch/x86_64/Makefile.inc | 3 +- klibc/klibc/arch/x86_64/syscall.S | 6 ++-- klibc/klibc/fgets.c | 1 + klibc/klibc/sigaction.c | 35 ++++++++++++++++-- klibc/klibc/sigpending.c | 4 ++- klibc/klibc/sigprocmask.c | 4 ++- klibc/klibc/sigsuspend.c | 4 ++- klibc/klibc/strntoumax.c | 13 +++---- klibc/makeklcc.pl | 0 klibc/version | 2 +- 19 files changed, 141 insertions(+), 37 deletions(-) rename klibc/include/{net => netinet}/if_ether.h (100%) create mode 100644 klibc/include/netpacket/packet.h mode change 100644 => 100755 klibc/makeklcc.pl diff --git a/klibc/Makefile b/klibc/Makefile index 5071e60da4..e634aaccb5 100644 --- a/klibc/Makefile +++ b/klibc/Makefile @@ -69,4 +69,9 @@ local-install: $(CROSS)klcc $(INSTALL_DATA) klcc.1 $(INSTALLROOT)$(mandir)/man1/$(KCROSS)klcc.1 $(INSTALL_EXEC) $(KCROSS)klcc $(INSTALLROOT)$(bindir) +# This does all the prep work needed to turn a freshly exported git repository +# into a release tarball tree +release: klibc.spec + rm -f maketar.sh + -include MCONFIG diff --git a/klibc/include/net/if_ether.h b/klibc/include/netinet/if_ether.h similarity index 100% rename from klibc/include/net/if_ether.h rename to klibc/include/netinet/if_ether.h diff --git a/klibc/include/netpacket/packet.h b/klibc/include/netpacket/packet.h new file mode 100644 index 0000000000..b5e8e0e11f --- /dev/null +++ b/klibc/include/netpacket/packet.h @@ -0,0 +1 @@ +#include diff --git a/klibc/include/signal.h b/klibc/include/signal.h index ab3c98d6e4..05930bdea1 100644 --- a/klibc/include/signal.h +++ b/klibc/include/signal.h @@ -82,10 +82,6 @@ __extern int sigaction(int, const struct sigaction *, struct sigaction *); __extern int sigprocmask(int, const sigset_t *, sigset_t *); __extern int sigpending(sigset_t *); __extern int sigsuspend(const sigset_t *); -__extern int rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t); -__extern int rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t); -__extern int rt_sigpending(sigset_t *, size_t); -__extern int rt_sigsuspend(const sigset_t *, size_t); __extern int raise(int); __extern int kill(pid_t, int); diff --git a/klibc/klcc.1 b/klibc/klcc.1 index a6f979c6c4..76334a3a54 100644 --- a/klibc/klcc.1 +++ b/klibc/klcc.1 @@ -1,4 +1,4 @@ -.\" $Id: klcc.1,v 1.2 2005/03/02 02:24:17 hpa Exp $ +.\" $Id: klcc.1,v 1.3 2005/04/19 23:27:46 hpa Exp $ .\" ----------------------------------------------------------------------- .\" .\" Copyright 2005 H. Peter Anvin - All Rights Reserved @@ -39,7 +39,9 @@ klcc \- compile a program against klibc .B klcc is a wrapper around .BR gcc (1) -to compile a program against the +and +.BR ld (1) +which compiles and links a program against the .B klibc tiny C library. It supports most .B gcc @@ -63,7 +65,12 @@ or option to use the default optimization level; this will generally result in the smallest binaries. You may want to use .B \-s -when linking, however. +when linking, however. Use +.B \-O0 +to compile without any optimization whatsoever; this may not work depending +on the version of +.B gcc +used. .PP Use the .B \-shared @@ -72,10 +79,38 @@ or option to compile for and link against shared or static klibc. Note that shared klibc only supports running against the exact same klibc binary as the binary was linked with. +.PP +In addition to standard +.B gcc +options, +.B klcc +supports options of the form \fB\-print-klibc-\fP\fIoption\fP, +which prints the corresponding klibc configuration option. .SH AUTHOR Written by H. Peter Anvin . .SH COPYRIGHT -Copyright \(co 2005 H. Peter Anvin. +Copyright \(co 2005 H. Peter Anvin \- All Rights Reserved +.PP +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following +conditions: +.PP +The above copyright notice and this permission notice shall +be included in all copies or substantial portions of the Software. +.PP +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. .SH "SEE ALSO" .BR gcc (1) diff --git a/klibc/klcc.in b/klibc/klcc.in index 36c4d9b3ee..5629f24f1c 100644 --- a/klibc/klcc.in +++ b/klibc/klcc.in @@ -1,5 +1,7 @@ # -*- perl -*- +use IPC::Open3; + # Standard includes @includes = ("-I${prefix}/${KCROSS}include/arch/${ARCH}", "-I${prefix}/${KCROSS}include/bits${BITSIZE}", @@ -57,7 +59,7 @@ sub files_with_lang($$) { # Skip object files if ( $need ne 'obj' ) { - unless ( $xopt eq $need ) { + unless ( $xopt eq $need || $need eq 'stdin') { push(@as, '-x', $need); $xopt = $need; } @@ -79,7 +81,11 @@ sub syserr($) { # Run a program; printing out the command line if $verbose is set sub mysystem(@) { print STDERR join(' ', @_), "\n" if ( $verbose ); - return system(@_); + my $cmd = shift; + open(INPUT, "<&STDIN"); # dup STDIN filehandle to INPUT + my $childpid = open3("<&INPUT", ">&STDOUT", ">&STDERR", $cmd, @_); + waitpid ($childpid, 0); + return $?; } # @@ -117,6 +123,11 @@ while ( defined($a = shift(@ARGV)) ) { # Not an option. Must be a filename then. push(@files, $a); $flang{$a} = $lang || filename2lang($a); + } elsif ( $a eq '-' ) { + # gcc gets its input from stdin + push(@files, $a); + # prevent setting -x + $flang{$a} = 'stdin' } elsif ( $a =~ /^-print-klibc-(.*)$/ ) { # This test must precede -print if ( defined($conf{$1}) ) { diff --git a/klibc/klibc/SYSCALLS.def b/klibc/klibc/SYSCALLS.def index e8b9a7f176..11d8c9a47e 100644 --- a/klibc/klibc/SYSCALLS.def +++ b/klibc/klibc/SYSCALLS.def @@ -145,17 +145,29 @@ ssize_t pwrite64,pwrite::pwrite(int, void *, size_t, off_t) ; ; Signal operations ; -int kill(pid_t, int) ; We really should get rid of the non-rt_* of these, but that takes -; sanitizing for all architectures, sigh... - int sigaction(int, const struct sigaction *, struct sigaction *) - int sigsuspend(const sigset_t *) - int sigpending(sigset_t *) - int sigprocmask(int, const sigset_t *, sigset_t *) -int rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t) -int rt_sigsuspend(const sigset_t *, size_t) -int rt_sigpending(sigset_t *, size_t) -int rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t) +; sanitizing for all architectures, sigh. +#ifdef __NR_sigaction +int sigaction::__sigaction(int, const struct sigaction *, struct sigaction *) +#else +int rt_sigaction::__rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t) +#endif +#ifdef __NR_sigsuspend +int sigsuspend(const sigset_t *) +#else +int rt_sigsuspend::__rt_sigsuspend(const sigset_t *, size_t) +#endif +#ifdef __NR_sigpending +int sigpending(sigset_t *) +#else +int rt_sigpending::__rt_sigpending(sigset_t *, size_t) +#endif +#ifdef __NR_sigprocmask +int sigprocmask(int, const sigset_t *, sigset_t *) +#else +int rt_sigprocmask::__rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t) +#endif +int kill(pid_t, int) unsigned int alarm(unsigned int) int getitimer(int, struct itimerval *) int setitimer(int, const struct itimerval *, struct itimerval *) diff --git a/klibc/klibc/arch/i386/Makefile.inc b/klibc/klibc/arch/i386/Makefile.inc index 5c320cb453..80344bd0a5 100644 --- a/klibc/klibc/arch/i386/Makefile.inc +++ b/klibc/klibc/arch/i386/Makefile.inc @@ -13,6 +13,7 @@ ARCHOBJS = \ arch/$(ARCH)/setjmp.o \ arch/$(ARCH)/syscall.o \ arch/$(ARCH)/open.o \ + arch/$(ARCH)/sigreturn.o \ arch/$(ARCH)/libgcc/__ashldi3.o \ arch/$(ARCH)/libgcc/__ashrdi3.o \ arch/$(ARCH)/libgcc/__lshrdi3.o \ diff --git a/klibc/klibc/arch/x86_64/MCONFIG b/klibc/klibc/arch/x86_64/MCONFIG index 13b6e391f9..c9b5da8bd6 100644 --- a/klibc/klibc/arch/x86_64/MCONFIG +++ b/klibc/klibc/arch/x86_64/MCONFIG @@ -15,8 +15,13 @@ # debugging using gdb. # ARCHREQFLAGS = -m64 +ifeq ($(DEBUG),y) +OPTFLAGS = -Os -fomit-frame-pointer \ + -falign-functions=0 -falign-jumps=0 -falign-loops=0 +else OPTFLAGS = -Os -fno-asynchronous-unwind-tables -fomit-frame-pointer \ -falign-functions=0 -falign-jumps=0 -falign-loops=0 +endif BITSIZE = 64 LDFLAGS = -m elf_x86_64 diff --git a/klibc/klibc/arch/x86_64/Makefile.inc b/klibc/klibc/arch/x86_64/Makefile.inc index d6cc1204e4..26d880d7c7 100644 --- a/klibc/klibc/arch/x86_64/Makefile.inc +++ b/klibc/klibc/arch/x86_64/Makefile.inc @@ -10,7 +10,8 @@ ARCHOBJS = \ arch/$(ARCH)/exits.o \ arch/$(ARCH)/setjmp.o \ - arch/$(ARCH)/syscall.o + arch/$(ARCH)/syscall.o \ + arch/$(ARCH)/sigreturn.o ARCHSOOBJS = $(patsubst %.o,%.lo,$(ARCHOBJS)) diff --git a/klibc/klibc/arch/x86_64/syscall.S b/klibc/klibc/arch/x86_64/syscall.S index f2c74ae974..17977978b9 100644 --- a/klibc/klibc/arch/x86_64/syscall.S +++ b/klibc/klibc/arch/x86_64/syscall.S @@ -15,14 +15,14 @@ __syscall_common: syscall cmpq $-4095,%rax - jb 1f + jnb 1f + ret # Error return, must set errno +1: negl %eax movl %eax,errno(%rip) # errno is type int, so 32 bits orq $-1,%rax # orq $-1 smaller than movq $-1 - -1: ret .size __syscall_common,.-__syscall_common diff --git a/klibc/klibc/fgets.c b/klibc/klibc/fgets.c index 88a145a63f..72f8a13cf1 100644 --- a/klibc/klibc/fgets.c +++ b/klibc/klibc/fgets.c @@ -20,6 +20,7 @@ char *fgets(char *s, int n, FILE *f) return NULL; } *p++ = ch; + n--; if ( ch == '\n' ) break; } diff --git a/klibc/klibc/sigaction.c b/klibc/klibc/sigaction.c index 819ffd4fe8..85f42a244c 100644 --- a/klibc/klibc/sigaction.c +++ b/klibc/klibc/sigaction.c @@ -5,11 +5,40 @@ #include #include -#ifndef __NR_sigaction +__extern void __sigreturn(void); +__extern int __sigaction(int, const struct sigaction *, struct sigaction *); +__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t); int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { - return rt_sigaction(sig, act, oact, sizeof(sigset_t)); -} + int rv; +#if defined(__i386__) || defined(__x86_64__) + /* x86-64, and the Fedora i386 kernel, are broken without SA_RESTORER */ + struct sigaction sa; + + if ( act && !(act->sa_flags & SA_RESTORER) ) { + sa = *act; + act = &sa; + + /* The kernel can't be trusted to have a valid default restorer */ + sa.sa_flags |= SA_RESTORER; + sa.sa_restorer = &__sigreturn; + } #endif + +#ifdef __NR_sigaction + rv = __sigaction(sig, act, oact); +#else + rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t)); +#endif + + +#if defined(__i386__) || defined(__x86_64__) + if ( oact && (oact->sa_restorer == &__sigreturn) ) { + oact->sa_flags &= ~SA_RESTORER; + } +#endif + + return rv; +} diff --git a/klibc/klibc/sigpending.c b/klibc/klibc/sigpending.c index 76d2b1a7f6..decfe32b1b 100644 --- a/klibc/klibc/sigpending.c +++ b/klibc/klibc/sigpending.c @@ -7,9 +7,11 @@ #ifndef __NR_sigpending +__extern __rt_sigpending(sigset_t *, size_t); + int sigpending(sigset_t *set) { - return rt_sigpending(set, sizeof(sigset_t)); + return __rt_sigpending(set, sizeof(sigset_t)); } #endif diff --git a/klibc/klibc/sigprocmask.c b/klibc/klibc/sigprocmask.c index b5e58b28b8..372e0fd90d 100644 --- a/klibc/klibc/sigprocmask.c +++ b/klibc/klibc/sigprocmask.c @@ -7,9 +7,11 @@ #ifndef __NR_sigprocmask +__extern __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t); + int sigprocmask(int how, const sigset_t *set, sigset_t *oset) { - return rt_sigprocmask(how, set, oset, sizeof(sigset_t)); + return __rt_sigprocmask(how, set, oset, sizeof(sigset_t)); } #endif diff --git a/klibc/klibc/sigsuspend.c b/klibc/klibc/sigsuspend.c index a927999ae6..22f9a46681 100644 --- a/klibc/klibc/sigsuspend.c +++ b/klibc/klibc/sigsuspend.c @@ -7,9 +7,11 @@ #ifndef __NR_sigsuspend +__extern int __rt_sigsuspend(const sigset_t *, size_t); + int sigsuspend(const sigset_t *mask) { - return rt_sigsuspend(mask, sizeof *mask); + return __rt_sigsuspend(mask, sizeof *mask); } #endif diff --git a/klibc/klibc/strntoumax.c b/klibc/klibc/strntoumax.c index 4e30637d2c..4c47fe8662 100644 --- a/klibc/klibc/strntoumax.c +++ b/klibc/klibc/strntoumax.c @@ -33,12 +33,13 @@ uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) } /* Single optional + or - */ - if ( n && *nptr == '-' ) { - minus = 1; - nptr++; - n--; - } else if ( n && *nptr == '+' ) { - nptr++; + if ( n ) { + char c = *nptr; + if ( c == '-' || c == '+' ) { + minus = (c == '-'); + nptr++; + n--; + } } if ( base == 0 ) { diff --git a/klibc/makeklcc.pl b/klibc/makeklcc.pl old mode 100644 new mode 100755 diff --git a/klibc/version b/klibc/version index 238d6e882a..5b09c67c20 100644 --- a/klibc/version +++ b/klibc/version @@ -1 +1 @@ -1.0.7 +1.0.14 From 561d4c5a3a66830ecfb92fdfd7ccee19cf01c2a7 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 8 Jun 2005 11:57:53 +0200 Subject: [PATCH 12/24] udevd: allow starting of udevd with stopped exec-queue Signed-off-by: Kay Sievers --- test/simple-build-check.sh | 0 udevd.c | 16 ++++++++++++++-- udevstart.c | 10 ++++------ 3 files changed, 18 insertions(+), 8 deletions(-) mode change 100644 => 100755 test/simple-build-check.sh diff --git a/test/simple-build-check.sh b/test/simple-build-check.sh old mode 100644 new mode 100755 diff --git a/udevd.c b/udevd.c index b5597eab40..6fb0bd9433 100644 --- a/udevd.c +++ b/udevd.c @@ -766,6 +766,8 @@ int main(int argc, char *argv[], char *envp[]) fd_set readfds; const char *value; int uevent_nl_active = 0; + int daemonize = 0; + int i; logging_init("udevd"); udev_init_config(); @@ -776,8 +778,18 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } - /* daemonize on request */ - if (argc == 2 && strcmp(argv[1], "-d") == 0) { + for (i = 1 ; i < argc; i++) { + char *arg = argv[i]; + if (strcmp(arg, "--daemon") == 0 || strcmp(arg, "-d") == 0) { + info("will daemonize"); + daemonize = 1; + } + if (strcmp(arg, "--stop-exec-queue") == 0) { + info("will not execute event until START_EXEC_QUEUE is received"); + stop_exec_q = 1; + } + } + if (daemonize) { pid_t pid; pid = fork(); diff --git a/udevstart.c b/udevstart.c index d1a0a8379c..bd91e96f6a 100644 --- a/udevstart.c +++ b/udevstart.c @@ -117,30 +117,29 @@ static int add_device(const char *path, const char *subsystem) class_dev = sysfs_open_class_device_path(path); if (class_dev == NULL) { - dbg ("sysfs_open_class_device_path failed"); + dbg("sysfs_open_class_device_path failed"); return -1; } udev_init_device(&udev, devpath, subsystem, "add"); udev.devt = get_devt(class_dev); if (!udev.devt) { - dbg ("sysfs_open_class_device_path failed"); + dbg("sysfs_open_class_device_path failed"); return -1; } udev_rules_get_name(&udev, class_dev); if (udev.ignore_device) { - info("device event will be ignored"); + dbg("device event will be ignored"); goto exit; } if (udev.name[0] == '\0') { - info("device node creation supressed"); + dbg("device node creation supressed"); goto run; } udev_add_device(&udev, class_dev); if (udev.devname[0] != '\0') setenv("DEVNAME", udev.devname, 1); - run: if (udev_run && !list_empty(&udev.run_list)) { struct name_entry *name_loop; @@ -149,7 +148,6 @@ run: list_for_each_entry(name_loop, &udev.run_list, node) execute_command(name_loop->name, udev.subsystem); } - exit: sysfs_close_class_device(class_dev); udev_cleanup_device(&udev); From 60d7b201008edb3c6d9226ef336c7ae0daa5742f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 13 Jun 2005 22:38:42 +0200 Subject: [PATCH 13/24] udevcontrol: fix exit code Kay is lazy! :) Signed-off-by: Kay Sievers --- udevcontrol.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/udevcontrol.c b/udevcontrol.c index 6a278a04c1..4a54af805e 100644 --- a/udevcontrol.c +++ b/udevcontrol.c @@ -95,8 +95,13 @@ int main(int argc, char *argv[], char *envp[]) retval = sendto(sock, &usend_msg, sizeof(usend_msg), 0, (struct sockaddr *)&saddr, addrlen); - if (retval == -1) + if (retval == -1) { info("error sending message (%s)", strerror(errno)); + retval = 1; + } else { + dbg("sent message '%x' (%u bytes sent)\n", usend_msg.type, retval); + retval = 0; + } close(sock); From 0fa98832b5be9893e1b26252c20b68d730b77173 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Jun 2005 13:28:24 +0200 Subject: [PATCH 14/24] udev man page: add operators Patch from: Hannes Reinecke Signed-off-by: Kay Sievers --- udev.8.in | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/udev.8.in b/udev.8.in index e4c1c11af2..b4edd5aebd 100644 --- a/udev.8.in +++ b/udev.8.in @@ -104,6 +104,36 @@ Every rule consists of a list of comma separated key value fields: .sp .IR "key " ,[ "key " ,...] .P +Each key has the following format: +.sp +.IR "name op value" +.P +There are distinct key operation types, depending on the type of the key, it +does a comparison or an assignment. +.P +Comparison operators are: +.TP +.B == +Compare for equality. +.TP +.B != +Compare for non-equality. +.P +Assignment operators are: +.TP +.B += +Add the value to a key that holds a list of entries. +.TP +.B := +Assign a value to a key finally; disallow any later changes, which +is useful to prevent changes by any later rules. +.TP +.B = +Asign a value to a key. Keys that represent a list, are reset and only this +single value is assigned. While this operator still works inplicitely as +comparison on keys that can't get a value assigned, its usage as an comparison +operator is deprecated. +.P The following key names can be used to match against device properties: .TP .B BUS From d27d8d6a8d63ffce768842324dd53067b9b0e905 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 14 Jun 2005 16:12:31 +0200 Subject: [PATCH 15/24] udev: fix netdev RUN handling Signed-off-by: Kay Sievers --- udev.c | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/udev.c b/udev.c index d623cbcc67..3eb788f4c1 100644 --- a/udev.c +++ b/udev.c @@ -138,29 +138,29 @@ int main(int argc, char *argv[], char *envp[]) wait_for_class_device(class_dev, &error); /* get major/minor */ - if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS) { + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS) udev.devt = get_devt(class_dev); - if (udev.devt) { - /* name device */ - udev_rules_get_name(&udev, class_dev); - if (udev.ignore_device) { - info("device event will be ignored"); - goto exit; - } - if (udev.name[0] == '\0') { - info("device node creation supressed"); - goto run; - } - /* create node, store in db */ - retval = udev_add_device(&udev, class_dev); - } else { - dbg("no dev-file found"); - udev_rules_get_run(&udev, NULL); - if (udev.ignore_device) { - info("device event will be ignored"); - goto exit; - } + if (udev.type == DEV_NET || udev.devt) { + /* name device */ + udev_rules_get_name(&udev, class_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto cleanup; + } + if (udev.name[0] == '\0') { + info("device node creation supressed"); + goto cleanup; + } + + /* create node, store in db */ + retval = udev_add_device(&udev, class_dev); + } else { + dbg("no dev-file found"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto cleanup; } } sysfs_close_class_device(class_dev); @@ -169,7 +169,7 @@ int main(int argc, char *argv[], char *envp[]) udev_rules_get_run(&udev, NULL); if (udev.ignore_device) { dbg("device event will be ignored"); - goto exit; + goto cleanup; } /* get name from db, remove db-entry, delete node */ @@ -198,14 +198,14 @@ int main(int argc, char *argv[], char *envp[]) sysfs_close_device(devices_dev); if (udev.ignore_device) { info("device event will be ignored"); - goto exit; + goto cleanup; } } else if (strcmp(action, "remove") == 0) { dbg("devices remove"); udev_rules_get_run(&udev, NULL); if (udev.ignore_device) { info("device event will be ignored"); - goto exit; + goto cleanup; } } } @@ -219,9 +219,10 @@ run: execute_command(name_loop->name, udev.subsystem); } -exit: +cleanup: udev_cleanup_device(&udev); +exit: logging_close(); return retval; } From 510de9c9e40c27b1eb224dc49ac439997bfe4db6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Jun 2005 17:02:55 +0200 Subject: [PATCH 16/24] udevinitsend: handle replay messages correctly Signed-off-by: Kay Sievers --- udevd.c | 13 ++++++++----- udevd.h | 5 ++++- udevinitsend.c | 39 ++++++++++++++++++--------------------- udevsend.c | 2 +- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/udevd.c b/udevd.c index 6fb0bd9433..873b05d946 100644 --- a/udevd.c +++ b/udevd.c @@ -542,13 +542,15 @@ static struct uevent_msg *get_udevd_msg(void) } switch (usend_msg.type) { - case UDEVD_UEVENT: - dbg("udevd message (UEVENT) received"); + case UDEVD_UDEVSEND: + case UDEVD_INITSEND: + dbg("udevd event message received"); envbuf_size = size - offsetof(struct udevd_msg, envbuf); dbg("envbuf_size=%i", envbuf_size); msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); if (msg == NULL) return NULL; + msg->type = usend_msg.type; return msg; case UDEVD_STOP_EXEC_QUEUE: dbg("udevd message (STOP_EXEC_QUEUE) received"); @@ -566,7 +568,7 @@ switch (usend_msg.type) { } /* receive the kernel user event message and do some sanity checks */ -static struct uevent_msg *get_uevent_msg(void) +static struct uevent_msg *get_nl_msg(void) { struct uevent_msg *msg; int bufpos; @@ -591,6 +593,7 @@ static struct uevent_msg *get_uevent_msg(void) msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos); if (msg == NULL) return NULL; + msg->type = UDEVD_NL; /* validate message */ pos = strchr(buffer, '@'); @@ -935,7 +938,7 @@ int main(int argc, char *argv[], char *envp[]) msg = get_udevd_msg(); if (msg) { /* discard kernel messages if netlink is active */ - if (uevent_nl_active && msg->seqnum != 0) { + if (uevent_nl_active && msg->type == UDEVD_UDEVSEND && msg->seqnum != 0) { dbg("skip uevent_helper message, netlink is active"); free(msg); continue; @@ -945,7 +948,7 @@ int main(int argc, char *argv[], char *envp[]) } if (FD_ISSET(uevent_nl_sock, &workreadfds)) { - msg = get_uevent_msg(); + msg = get_nl_msg(); if (msg) { msg_queue_insert(msg); /* disable kernel uevent_helper with first netlink message */ diff --git a/udevd.h b/udevd.h index 60732fe052..b8fb6913c9 100644 --- a/udevd.h +++ b/udevd.h @@ -50,7 +50,9 @@ enum udevd_msg_type { UDEVD_UNKNOWN, - UDEVD_UEVENT, + UDEVD_UDEVSEND, + UDEVD_INITSEND, + UDEVD_NL, UDEVD_STOP_EXEC_QUEUE, UDEVD_START_EXEC_QUEUE, }; @@ -63,6 +65,7 @@ struct udevd_msg { }; struct uevent_msg { + enum udevd_msg_type type; struct list_head node; pid_t pid; long queue_time; diff --git a/udevinitsend.c b/udevinitsend.c index 05c39b99b3..c7d56fc259 100644 --- a/udevinitsend.c +++ b/udevinitsend.c @@ -58,17 +58,18 @@ void log_message (int level, const char *format, ...) * 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) +static int udevsend(char *filename, int sock, int disable_loop_detection) { - struct stat statbuf; - int fd, bufpos; - char *fdmap, *ls, *le, *ch; - struct udevd_msg usend_msg; - int retval = 0; + static struct udevd_msg usend_msg; int usend_msg_len; + int bufpos = 0; + struct stat statbuf; + int fd; + char *fdmap, *ls, *le, *ch; struct sockaddr_un saddr; socklen_t addrlen; - + int retval = 0; + if (stat(filename,&statbuf) < 0) { dbg("cannot stat %s: %s\n", filename, strerror(errno)); return 1; @@ -91,24 +92,23 @@ static int udevsend(char *filename, int sock, int ignore_loops) 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); + usend_msg.type = UDEVD_INITSEND; ls = fdmap; ch = le = ls; while (*ch && ch < fdmap + statbuf.st_size) { - le = strchr(ch,'\n'); + le = strchr(ch, '\n'); if (!le) break; - ch = strchr(ch,'='); + ch = strchr(ch, '='); if (!ch) break; /* prevent loops in the scripts we execute */ if (strncmp(ls, "UDEVD_EVENT=", 12) == 0) { - if (!ignore_loops) { + if (!disable_loop_detection) { dbg("event already handled by udev\n"); retval = -1; break; @@ -161,7 +161,8 @@ int main(int argc, char *argv[], char *envp[]) char *event_file = NULL; DIR *dirstream; struct dirent *direntry; - int retval = 1, ignore_loops = 0; + int retval = 1; + int disable_loop_detection = 0; int sock; logging_init("udevinitsend"); @@ -186,14 +187,10 @@ int main(int argc, char *argv[], char *envp[]) break; case 'l': - dbg("ignoring loops\n"); - ignore_loops = 1; + dbg("disable loop detection, ignore UDEVD_EVENT\n"); + disable_loop_detection = 1; break; - case 'V': - printf("udevinitsend, version 0.1\n"); - return 0; - case 'h': retval = 0; } @@ -217,11 +214,11 @@ int main(int argc, char *argv[], char *envp[]) if (!strcmp(direntry->d_name,".") || !strcmp(direntry->d_name,"..")) continue; - retval = udevsend(direntry->d_name, sock, ignore_loops); + retval = udevsend(direntry->d_name, sock, disable_loop_detection); } closedir(dirstream); } else if (event_file) { - retval = udevsend(event_file, sock, ignore_loops); + retval = udevsend(event_file, sock, disable_loop_detection); } if (sock != -1) diff --git a/udevsend.c b/udevsend.c index 888a88daa0..42ef0271dd 100644 --- a/udevsend.c +++ b/udevsend.c @@ -146,7 +146,7 @@ int main(int argc, char *argv[], char *envp[]) memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); - usend_msg.type = UDEVD_UEVENT; + usend_msg.type = UDEVD_UDEVSEND; /* copy all keys to send buffer */ for (i = 0; envp[i]; i++) { From e5b7f7b83428cb50f165b49408c2f7559dcfefef Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Jun 2005 20:27:08 +0200 Subject: [PATCH 17/24] klibc: add missing files Signed-off-by: Kay Sievers --- klibc/include/net/route.h | 1 + klibc/klibc/Kbuild | 149 ++++++++++++++++++++++++++++ klibc/klibc/arch/i386/sigreturn.S | 15 +++ klibc/klibc/arch/x86_64/sigreturn.S | 15 +++ 4 files changed, 180 insertions(+) create mode 100644 klibc/include/net/route.h create mode 100644 klibc/klibc/Kbuild create mode 100644 klibc/klibc/arch/i386/sigreturn.S create mode 100644 klibc/klibc/arch/x86_64/sigreturn.S diff --git a/klibc/include/net/route.h b/klibc/include/net/route.h new file mode 100644 index 0000000000..a60df24c0a --- /dev/null +++ b/klibc/include/net/route.h @@ -0,0 +1 @@ +#include diff --git a/klibc/klibc/Kbuild b/klibc/klibc/Kbuild new file mode 100644 index 0000000000..be239a6647 --- /dev/null +++ b/klibc/klibc/Kbuild @@ -0,0 +1,149 @@ +# +# Kbuild file for klibc +# + +libc-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ + asprintf.o vasprintf.o \ + vsscanf.o sscanf.o ctypes.o \ + strntoumax.o strntoimax.o \ + atoi.o atol.o atoll.o \ + strtol.o strtoll.o strtoul.o strtoull.o \ + strtoimax.o strtoumax.o \ + globals.o exitc.o atexit.o onexit.o \ + execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \ + fork.o wait.o wait3.o waitpid.o system.o setpgrp.o getpgrp.o \ + daemon.o \ + printf.o vprintf.o fprintf.o vfprintf.o perror.o \ + statfs.o fstatfs.o umount.o \ + open.o fopen.o fread.o fread2.o fgetc.o fgets.o \ + fwrite.o fwrite2.o fputc.o fputs.o puts.o putchar.o \ + sleep.o usleep.o strtotimespec.o strtotimeval.o \ + raise.o abort.o assert.o alarm.o pause.o \ + __signal.o sysv_signal.o bsd_signal.o siglist.o siglongjmp.o \ + sigaction.o sigpending.o sigprocmask.o sigsuspend.o \ + brk.o sbrk.o malloc.o realloc.o calloc.o mmap.o \ + memcpy.o memcmp.o memset.o memccpy.o memmem.o memswap.o \ + memmove.o memchr.o memrchr.o \ + strcasecmp.o strncasecmp.o strndup.o strerror.o \ + strcat.o strchr.o strcmp.o strcpy.o strdup.o strlen.o strnlen.o \ + strncat.o strlcpy.o strlcat.o \ + strstr.o strncmp.o strncpy.o strrchr.o \ + strxspn.o strspn.o strcspn.o strpbrk.o strsep.o strtok.o \ + gethostname.o getdomainname.o getcwd.o \ + seteuid.o setegid.o \ + getenv.o setenv.o putenv.o __put_env.o unsetenv.o \ + getopt.o readdir.o \ + syslog.o closelog.o pty.o getpt.o isatty.o reboot.o \ + time.o utime.o llseek.o nice.o getpriority.o \ + qsort.o \ + lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \ + inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \ + inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \ + send.o recv.o + +libc-$(CONFIG_KLIBC_ERRLIST) += errlist.o + +libc-$(CONFIG_KLIBC_ZLIB) += \ + zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \ + zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \ + zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o + +##### +# Add any architecture-specific rules +include $(obj)/arch/$(ARCH)/Makefile.inc + +##### +# Shared definitions +LIB := libc.a +SOLIB := libc.so +SOHASH := klibc.so +CRT0 := arch/$(ARCH)/crt0.o +INTERP_O := interp.o + +always := $(CRT0) $(LIB) $(SOLIB) $(SOHASH) $(INTERP_O) +LIB := $(call objectify,$(LIB)) +SOLIB := $(call objectify,$(SOLIB)) +SOHASH := $(call objectify,$(SOHASH)) +CRT0 := $(call objectify,$(CRT0)) +INTERP_O := $(call objectify,$(INTERP_O)) + +targets := arch/$(ARCH)/crt0.o +targets += $(libc-y) $(ARCHOBJS) + +# Generate syscall stubs +subdir-y += syscalls +# Generate socket calls stubs +subdir-y += socketcalls + +# Tell make to descend before building libs +$(obj)/syscalls/syscalls.o: $(obj)/syscalls +$(obj)/socketcalls/socketcalls.o: $(obj)/socketcalls + +##### +# Readable errormessages extracted from src.. +targets += errlist.c +quiet_cmd_errlist = GEN $@ + cmd_errlist = $(PERL) $< $(LINUXINCLUDE) -errlist > $@ || rm -f $@ + +$(obj)/errlist.c: $(srctree)/$(src)/makeerrlist.pl + $(call cmd,errlist) + +# full list of dependencies for klibc +libc-deps = $(call objectify, $(libc-y) $(ARCHOBJS)) \ + $(call objectify, syscalls/syscalls.o socketcalls/socketcalls.o) + +###### +# Build static library: libc.a +targets += libc.a __static_init.o +quiet_cmd_libc = USERAR $@ + cmd_libc = rm -f $@; \ + $(USERAR) cq $@ $(filter-out FORCE,$^); \ + $(USERRANLIB) $@ + +$(LIB): $(call objectify,__static_init.o) $(libc-deps) FORCE + $(call if_changed,libc) + +###### +# Build shared library +targets += libc.so __shared_init.o + +quiet_cmd_libcso = LD $@ + cmd_libcso = $(USERLD) $(USERLDFLAGS) $(USERSHAREDFLAGS) \ + -o $@ $(filter-out FORCE,$^) $(USERLIBGCC) + +$(SOLIB): $(CRT0) $(call objectify,__shared_init.o) $(libc-deps) FORCE + $(call if_changed,libcso) + + +##### +# Build sha1 hash values +targets += klibc.so libc.so.hash +hostprogs-y := sha1hash + +quiet_cmd_solibhash = HASH $@ + cmd_solibhash = $(USERNM) $< | egrep '^[0-9a-fA-F]+ [ADRTW] ' | \ + sort | $(obj)/sha1hash > $@ +$(SOLIB).hash: $(SOLIB) $(obj)/sha1hash FORCE + $(call if_changed,solibhash) + +quiet_cmd_sohash = GEN $@ + cmd_sohash = cat $< > $@; \ + $(USERSTRIP) $(USERSTRIPFLAGS) $@; \ + rm -f $(obj)/klibc-??????????????????????.so; \ + ln -f $@ $(obj)/klibc-`cat $(SOLIB).hash`.so +$(SOHASH): $(SOLIB) $(SOLIB).hash + $(call cmd,sohash) + + +##### +# build interp.o +targets += interp.o + +quiet_cmd_interp = BUILD $@ + cmd_interp = $(USERCC) $(usercflags) -D__ASSEMBLY__ \ + -DLIBDIR=\"$(SHLIBDIR)\" \ + -DSOHASH=\"`cat $(SOLIB).hash`\" \ + -c -o $@ $< + +$(INTERP_O): $(obj)/interp.S $(SOLIB).hash + $(call if_changed,interp) diff --git a/klibc/klibc/arch/i386/sigreturn.S b/klibc/klibc/arch/i386/sigreturn.S new file mode 100644 index 0000000000..f2a32419d3 --- /dev/null +++ b/klibc/klibc/arch/i386/sigreturn.S @@ -0,0 +1,15 @@ +# +# arch/i386/sigreturn.S +# + +#include + + .text + .align 4 + .globl __sigreturn + .type __sigreturn,@function +__sigreturn: + pop %eax # Have no idea why this is needed... + movl $__NR_sigreturn,%eax + int $0x80 + .size __sigreturn,.-__sigreturn diff --git a/klibc/klibc/arch/x86_64/sigreturn.S b/klibc/klibc/arch/x86_64/sigreturn.S new file mode 100644 index 0000000000..66e7152344 --- /dev/null +++ b/klibc/klibc/arch/x86_64/sigreturn.S @@ -0,0 +1,15 @@ +/* + * arch/x86_64/sigreturn.S + */ + +#include + + .text + .align 4 + .globl __sigreturn + .type __sigreturn,@function +__sigreturn: + movl $__NR_rt_sigreturn,%eax + syscall + + .size __sigreturn,.-__sigreturn From 3632a3685883d3270145c59d5764de6246547943 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Jun 2005 03:07:14 +0200 Subject: [PATCH 18/24] udeveventrecorder: add small program that writes an event to disk Used for debugging and event replay from initramfs. Signed-off-by: Kay Sievers --- Makefile | 12 ++++- udevd.c | 6 +-- udeveventrecorder.c | 127 ++++++++++++++++++++++++++++++++++++++++++++ udevinitsend.c | 15 +++++- 4 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 udeveventrecorder.c diff --git a/Makefile b/Makefile index d36bd5866c..9ad6ee103b 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,7 @@ ROOT = udev DAEMON = udevd SENDER = udevsend INITSENDER = udevinitsend +RECORDER = udeveventrecorder CONTROL = udevcontrol INFO = udevinfo TESTER = udevtest @@ -204,7 +205,7 @@ endif # config files automatically generated GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf -all: $(ROOT) $(SENDER) $(INITSENDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) +all: $(ROOT) $(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC) @extras="$(EXTRAS)" ; for target in $$extras ; do \ echo $$target ; \ $(MAKE) prefix=$(prefix) \ @@ -271,6 +272,7 @@ $(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) +$(RECORDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(CONTROL).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC) $(STARTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC) @@ -298,6 +300,10 @@ $(INITSENDER): $(KLCC) $(INITSENDER).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(INITSENDER).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ +$(RECORDER): $(KLCC) $(RECORDER).o $(OBJS) udevd.h + $(QUIET) $(LD) $(LDFLAGS) -o $@ $(RECORDER).o $(OBJS) $(LIB_OBJS) + $(QUIET) $(STRIPCMD) $@ + $(CONTROL): $(KLCC) $(CONTROL).o $(OBJS) udevd.h $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CONTROL).o $(OBJS) $(LIB_OBJS) $(QUIET) $(STRIPCMD) $@ @@ -313,7 +319,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) $(INITSENDER) $(CONTROL) $(TESTER) $(STARTER) + $(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(TESTER) $(STARTER) -rm -f ccdv $(MAKE) -C klibc SUBDIRS=klibc clean @extras="$(EXTRAS)" ; for target in $$extras ; do \ @@ -374,6 +380,7 @@ install: install-config install-man install-dev.d all $(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON) $(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER) $(INSTALL_PROGRAM) -D $(INITSENDER) $(DESTDIR)$(sbindir)/$(INITSENDER) + $(INSTALL_PROGRAM) -D $(RECORDER) $(DESTDIR)$(sbindir)/$(RECORDER) $(INSTALL_PROGRAM) -D $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL) $(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO) $(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER) @@ -400,6 +407,7 @@ uninstall: uninstall-man uninstall-dev.d - rm $(sbindir)/$(DAEMON) - rm $(sbindir)/$(SENDER) - rm $(sbindir)/$(INITSENDER) + - rm $(sbindir)/$(RECORDER) - rm $(sbindir)/$(CONTROL) - rm $(sbindir)/$(STARTER) - rm $(usrbindir)/$(INFO) diff --git a/udevd.c b/udevd.c index 873b05d946..f4c986b870 100644 --- a/udevd.c +++ b/udevd.c @@ -660,7 +660,7 @@ static void udev_done(int pid) list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { sysinfo(&info); - info("seq %llu exit, %ld sec old", msg->seqnum, info.uptime - msg->queue_time); + info("seq %llu exit, %ld seconds old", msg->seqnum, info.uptime - msg->queue_time); run_queue_delete(msg); /* we want to run the exec queue manager since there may @@ -951,9 +951,9 @@ int main(int argc, char *argv[], char *envp[]) msg = get_nl_msg(); if (msg) { msg_queue_insert(msg); - /* disable kernel uevent_helper with first netlink message */ + /* disable udevsend with first netlink message */ if (!uevent_nl_active) { - info("uevent_nl message received, disable uevent_helper messages"); + info("uevent_nl message received, disable udevsend messages"); uevent_nl_active = 1; } } diff --git a/udeveventrecorder.c b/udeveventrecorder.c new file mode 100644 index 0000000000..af7ea7c15c --- /dev/null +++ b/udeveventrecorder.c @@ -0,0 +1,127 @@ +/* + * udeveventrecorder.c + * + * Userspace devfs + * + * Copyright (C) 2004, 2005 Olaf Hering + * + * 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 "udev.h" +#include "udev_version.h" +#include "udev_utils.h" +#include "logging.h" + +#define BUFSIZE 12345 +#define FNSIZE 123 + +static int log = 0; + +#ifdef USE_LOG +void log_message (int priority, const char *format, ...) +{ + va_list args; + + if (priority > log) + return; + + va_start(args, format); + vsyslog(priority, format, args); + va_end(args); +} +#endif + +int main(int argc, char **argv, char **envp) +{ + int fd, i; + unsigned long seq; + char **ep = envp; + char *buf, *p, *a; + struct stat sb; + const char *env; + + if (stat("/events", &sb) || !(S_ISDIR(sb.st_mode))) + return 1; + + env = getenv("UDEV_LOG"); + if (env) + log = log_priority(env); + + logging_init("udeveventrecorder"); + dbg("version %s", UDEV_VERSION); + + p = getenv("SEQNUM"); + a = getenv("ACTION"); + buf = malloc(FNSIZE); + if (!(buf && a && argv[1])) + goto error; + if (p) + seq = strtoul(p, NULL, 0); + else + seq = 0; + + snprintf(buf, FNSIZE, "/events/debug.%05lu.%s.%s.%u", seq, argv[1], a ? a : "", getpid()); + if ((fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) { + err("error creating '%s'", buf); + goto error; + } + free(buf); + p = malloc(BUFSIZE); + buf = p; + buf += snprintf(buf, p + BUFSIZE - buf, "set --"); + for (i = 1; i < argc; ++i) { + buf += snprintf(buf, p + BUFSIZE - buf, " %s", argv[i]); + if (buf > p + BUFSIZE) + goto full; + } + buf += snprintf(buf, p + BUFSIZE - buf, "\n"); + if (buf > p + BUFSIZE) + goto full; + while (*ep) { + unsigned char *t; + t = memchr(*ep, '=', strlen(*ep)); + if (t) { + *t = '\0'; + t++; + buf += snprintf(buf, p + BUFSIZE - buf, "%s='%s'\n", *ep, t); + --t; + *t = '='; + } + ep++; + if (buf > p + BUFSIZE) + break; + } + +full: + buf = p; + write(fd, buf, strlen(buf)); + close(fd); + free(buf); + return 0; + +error: + fprintf(stderr, "record enviroment to /events, to be called from udev context\n"); + return 1; +} diff --git a/udevinitsend.c b/udevinitsend.c index c7d56fc259..31a7109d1b 100644 --- a/udevinitsend.c +++ b/udevinitsend.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -38,16 +39,21 @@ #include "udev.h" #include "udev_version.h" #include "udevd.h" +#include "udev_utils.h" #include "logging.h" +static int log = 0; #ifdef USE_LOG -void log_message (int level, const char *format, ...) +void log_message (int priority, const char *format, ...) { va_list args; + if (priority > log) + return; + va_start(args, format); - vsyslog(level, format, args); + vsyslog(priority, format, args); va_end(args); } #endif @@ -164,6 +170,11 @@ int main(int argc, char *argv[], char *envp[]) int retval = 1; int disable_loop_detection = 0; int sock; + const char *env; + + env = getenv("UDEV_LOG"); + if (env) + log = log_priority(env); logging_init("udevinitsend"); dbg("version %s", UDEV_VERSION); From 8ab44e3fd0b8fd4555db973d4c2c305ca09e787d Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 16 Jun 2005 01:58:47 +0200 Subject: [PATCH 19/24] udevd: control log-priority of the running daemon with udevcontrol Signed-off-by: Kay Sievers --- Makefile | 2 +- etc/udev/udev.conf.in | 1 - udev.c | 2 +- udev_utils.c | 4 +-- udevcontrol.c | 33 +++++++++++++++----- udevd.c | 70 ++++++++++++++++++++++++++----------------- udevd.h | 8 +++-- udevinitsend.c | 2 +- udevsend.c | 2 +- 9 files changed, 78 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index 9ad6ee103b..bdb87e5651 100644 --- a/Makefile +++ b/Makefile @@ -388,7 +388,7 @@ install: install-config install-man install-dev.d all - ln -f -s $(sbindir)/$(SENDER) $(DESTDIR)$(hotplugdir)/10-udev.hotplug ifndef DESTDIR - killall $(DAEMON) - - $(sbindir)/$(DAEMON) -d + - $(sbindir)/$(DAEMON) --daemon - rm -rf $(udevdb) endif @extras="$(EXTRAS)" ; for target in $$extras ; do \ diff --git a/etc/udev/udev.conf.in b/etc/udev/udev.conf.in index 9d5300a861..efdb1d1808 100644 --- a/etc/udev/udev.conf.in +++ b/etc/udev/udev.conf.in @@ -1,5 +1,4 @@ # udev.conf -# # Where in the filesystem to place the device nodes udev_root="@udevdir@" diff --git a/udev.c b/udev.c index 3eb788f4c1..f7b9bf3573 100644 --- a/udev.c +++ b/udev.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } - /* export log_level , as called programs may want to do the same as udev */ + /* export log_priority , as called programs may want to do the same as udev */ if (udev_log_priority) { char priority[32]; diff --git a/udev_utils.c b/udev_utils.c index d605631088..64a7ba9caa 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -409,10 +409,10 @@ int execute_command(const char *command, const char *subsystem) close(devnull); } retval = execv(arg, argv); - err("exec of child failed"); + err("exec of child '%s' failed", command); _exit(1); case -1: - dbg("fork of child failed"); + dbg("fork of child '%s' failed", command); break; return -1; default: diff --git a/udevcontrol.c b/udevcontrol.c index 4a54af805e..98776ccefd 100644 --- a/udevcontrol.c +++ b/udevcontrol.c @@ -37,18 +37,23 @@ #include "udev.h" #include "udev_version.h" #include "udevd.h" +#include "udev_utils.h" #include "logging.h" /* global variables */ static int sock = -1; +static int log = 0; #ifdef USE_LOG -void log_message (int level, const char *format, ...) +void log_message (int priority, const char *format, ...) { va_list args; + if (priority > log) + return; + va_start(args, format); - vsyslog(level, format, args); + vsyslog(priority, format, args); va_end(args); } #endif @@ -59,25 +64,37 @@ int main(int argc, char *argv[], char *envp[]) static struct udevd_msg usend_msg; struct sockaddr_un saddr; socklen_t addrlen; + const char *env; int retval = 1; + env = getenv("UDEV_LOG"); + if (env) + log = log_priority(env); + logging_init("udevcontrol"); dbg("version %s", UDEV_VERSION); if (argc != 2) { - info("usage: udevcontrol \n"); + info("usage: udevcontrol "); goto exit; } memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); - if (strstr(argv[1], "stop_exec_queue")) + if (!strcmp(argv[1], "stop_exec_queue")) usend_msg.type = UDEVD_STOP_EXEC_QUEUE; - else if (strstr(argv[1], "start_exec_queue")) + else if (!strcmp(argv[1], "start_exec_queue")) usend_msg.type = UDEVD_START_EXEC_QUEUE; - else { - info("unknown command\n"); + else if (!strncmp(argv[1], "log_priority=", strlen("log_priority="))) { + int *level = (int *) usend_msg.envbuf; + char *prio = &argv[1][strlen("log_priority=")]; + + usend_msg.type = UDEVD_SET_LOG_LEVEL; + *level = log_priority(prio); + dbg("send log_priority=%i", *level); + } else { + err("unknown command\n"); goto exit; } @@ -99,7 +116,7 @@ int main(int argc, char *argv[], char *envp[]) info("error sending message (%s)", strerror(errno)); retval = 1; } else { - dbg("sent message '%x' (%u bytes sent)\n", usend_msg.type, retval); + dbg("sent message '%x' (%u bytes sent)", usend_msg.type, retval); retval = 0; } diff --git a/udevd.c b/udevd.c index f4c986b870..209b9fcd87 100644 --- a/udevd.c +++ b/udevd.c @@ -50,7 +50,7 @@ /* global variables*/ static int udevd_sock; -static int uevent_nl_sock; +static int uevent_netlink_sock; static pid_t sid; static int pipefds[2]; @@ -173,8 +173,8 @@ static void execute_udev(struct uevent_msg *msg) switch (pid) { case 0: /* child */ - if (uevent_nl_sock != -1) - close(uevent_nl_sock); + if (uevent_netlink_sock != -1) + close(uevent_netlink_sock); close(udevd_sock); logging_close(); @@ -362,6 +362,9 @@ static void exec_queue_manager(void) struct uevent_msg *tmp_msg; int running; + if (list_empty(&exec_list)) + return; + running = running_processes(); dbg("%d processes runnning on system", running); if (running < 0) @@ -506,6 +509,7 @@ static struct uevent_msg *get_udevd_msg(void) struct ucred *cred; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; int envbuf_size; + int *intval; memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); iov.iov_base = &usend_msg; @@ -541,10 +545,10 @@ static struct uevent_msg *get_udevd_msg(void) return NULL; } -switch (usend_msg.type) { - case UDEVD_UDEVSEND: - case UDEVD_INITSEND: - dbg("udevd event message received"); + switch (usend_msg.type) { + case UDEVD_UEVENT_UDEVSEND: + case UDEVD_UEVENT_INITSEND: + info("udevd event message received"); envbuf_size = size - offsetof(struct udevd_msg, envbuf); dbg("envbuf_size=%i", envbuf_size); msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size); @@ -553,14 +557,24 @@ switch (usend_msg.type) { msg->type = usend_msg.type; return msg; case UDEVD_STOP_EXEC_QUEUE: - dbg("udevd message (STOP_EXEC_QUEUE) received"); + info("udevd message (STOP_EXEC_QUEUE) received"); stop_exec_q = 1; break; case UDEVD_START_EXEC_QUEUE: - dbg("udevd message (START_EXEC_QUEUE) received"); + info("udevd message (START_EXEC_QUEUE) received"); stop_exec_q = 0; exec_queue_manager(); break; + case UDEVD_SET_LOG_LEVEL: + intval = (int *) usend_msg.envbuf; + info("udevd message (SET_LOG_PRIORITY) received, udev_log_priority=%i", *intval); + udev_log_priority = *intval; + break; + case UDEVD_SET_MAX_CHILDS: + intval = (int *) usend_msg.envbuf; + info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval); + max_childs = *intval; + break; default: dbg("unknown message type"); } @@ -568,7 +582,7 @@ switch (usend_msg.type) { } /* receive the kernel user event message and do some sanity checks */ -static struct uevent_msg *get_nl_msg(void) +static struct uevent_msg *get_netlink_msg(void) { struct uevent_msg *msg; int bufpos; @@ -576,7 +590,7 @@ static struct uevent_msg *get_nl_msg(void) static char buffer[UEVENT_BUFFER_SIZE + 512]; char *pos; - size = recv(uevent_nl_sock, &buffer, sizeof(buffer), 0); + size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0); if (size < 0) { if (errno != EINTR) dbg("unable to receive udevd message"); @@ -593,7 +607,7 @@ static struct uevent_msg *get_nl_msg(void) msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos); if (msg == NULL) return NULL; - msg->type = UDEVD_NL; + msg->type = UDEVD_UEVENT_NETLINK; /* validate message */ pos = strchr(buffer, '@'); @@ -732,7 +746,7 @@ static int init_udevd_socket(void) return 0; } -static int init_uevent_nl_sock(void) +static int init_uevent_netlink_sock(void) { struct sockaddr_nl snl; int retval; @@ -742,18 +756,18 @@ static int init_uevent_nl_sock(void) snl.nl_pid = getpid(); snl.nl_groups = 0xffffffff; - uevent_nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (uevent_nl_sock == -1) { + uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (uevent_netlink_sock == -1) { dbg("error getting socket, %s", strerror(errno)); return -1; } - retval = bind(uevent_nl_sock, (struct sockaddr *) &snl, + retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl)); if (retval < 0) { dbg("bind failed, %s", strerror(errno)); - close(uevent_nl_sock); - uevent_nl_sock = -1; + close(uevent_netlink_sock); + uevent_netlink_sock = -1; return -1; } @@ -768,7 +782,7 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *value; - int uevent_nl_active = 0; + int uevent_netlink_active = 0; int daemonize = 0; int i; @@ -788,7 +802,7 @@ int main(int argc, char *argv[], char *envp[]) daemonize = 1; } if (strcmp(arg, "--stop-exec-queue") == 0) { - info("will not execute event until START_EXEC_QUEUE is received"); + info("will not execute events until START_EXEC_QUEUE is received"); stop_exec_q = 1; } } @@ -865,7 +879,7 @@ int main(int argc, char *argv[], char *envp[]) sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); - if (init_uevent_nl_sock() < 0) { + if (init_uevent_netlink_sock() < 0) { dbg("uevent socket not available"); } @@ -918,8 +932,8 @@ int main(int argc, char *argv[], char *envp[]) FD_ZERO(&readfds); FD_SET(udevd_sock, &readfds); - if (uevent_nl_sock != -1) - FD_SET(uevent_nl_sock, &readfds); + if (uevent_netlink_sock != -1) + FD_SET(uevent_netlink_sock, &readfds); FD_SET(pipefds[0], &readfds); maxsockplus = udevd_sock+1; while (1) { @@ -938,7 +952,7 @@ int main(int argc, char *argv[], char *envp[]) msg = get_udevd_msg(); if (msg) { /* discard kernel messages if netlink is active */ - if (uevent_nl_active && msg->type == UDEVD_UDEVSEND && msg->seqnum != 0) { + if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) { dbg("skip uevent_helper message, netlink is active"); free(msg); continue; @@ -947,14 +961,14 @@ int main(int argc, char *argv[], char *envp[]) } } - if (FD_ISSET(uevent_nl_sock, &workreadfds)) { - msg = get_nl_msg(); + if (FD_ISSET(uevent_netlink_sock, &workreadfds)) { + msg = get_netlink_msg(); if (msg) { msg_queue_insert(msg); /* disable udevsend with first netlink message */ - if (!uevent_nl_active) { + if (!uevent_netlink_active) { info("uevent_nl message received, disable udevsend messages"); - uevent_nl_active = 1; + uevent_netlink_active = 1; } } } diff --git a/udevd.h b/udevd.h index b8fb6913c9..34bfe931ba 100644 --- a/udevd.h +++ b/udevd.h @@ -50,11 +50,13 @@ enum udevd_msg_type { UDEVD_UNKNOWN, - UDEVD_UDEVSEND, - UDEVD_INITSEND, - UDEVD_NL, + UDEVD_UEVENT_UDEVSEND, + UDEVD_UEVENT_INITSEND, + UDEVD_UEVENT_NETLINK, UDEVD_STOP_EXEC_QUEUE, UDEVD_START_EXEC_QUEUE, + UDEVD_SET_LOG_LEVEL, + UDEVD_SET_MAX_CHILDS, }; diff --git a/udevinitsend.c b/udevinitsend.c index 31a7109d1b..26ae5c8418 100644 --- a/udevinitsend.c +++ b/udevinitsend.c @@ -100,7 +100,7 @@ static int udevsend(char *filename, int sock, int disable_loop_detection) memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); - usend_msg.type = UDEVD_INITSEND; + usend_msg.type = UDEVD_UEVENT_INITSEND; ls = fdmap; ch = le = ls; diff --git a/udevsend.c b/udevsend.c index 42ef0271dd..bdc69d0508 100644 --- a/udevsend.c +++ b/udevsend.c @@ -146,7 +146,7 @@ int main(int argc, char *argv[], char *envp[]) memset(&usend_msg, 0x00, sizeof(struct udevd_msg)); strcpy(usend_msg.magic, UDEV_MAGIC); - usend_msg.type = UDEVD_UDEVSEND; + usend_msg.type = UDEVD_UEVENT_UDEVSEND; /* copy all keys to send buffer */ for (i = 0; envp[i]; i++) { From 7628ff6e144a94c48e463d0188022f5661e0ba40 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 16 Jun 2005 03:22:27 +0200 Subject: [PATCH 20/24] udevcontrol: add max_childs command Signed-off-by: Kay Sievers --- udevcontrol.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/udevcontrol.c b/udevcontrol.c index 98776ccefd..f19ae98fba 100644 --- a/udevcontrol.c +++ b/udevcontrol.c @@ -65,6 +65,8 @@ int main(int argc, char *argv[], char *envp[]) struct sockaddr_un saddr; socklen_t addrlen; const char *env; + const char *val; + int *intval; int retval = 1; env = getenv("UDEV_LOG"); @@ -75,7 +77,7 @@ int main(int argc, char *argv[], char *envp[]) dbg("version %s", UDEV_VERSION); if (argc != 2) { - info("usage: udevcontrol "); + err("error finding comand"); goto exit; } @@ -87,20 +89,25 @@ int main(int argc, char *argv[], char *envp[]) else if (!strcmp(argv[1], "start_exec_queue")) usend_msg.type = UDEVD_START_EXEC_QUEUE; else if (!strncmp(argv[1], "log_priority=", strlen("log_priority="))) { - int *level = (int *) usend_msg.envbuf; - char *prio = &argv[1][strlen("log_priority=")]; - + intval = (int *) usend_msg.envbuf; + val = &argv[1][strlen("log_priority=")]; usend_msg.type = UDEVD_SET_LOG_LEVEL; - *level = log_priority(prio); - dbg("send log_priority=%i", *level); + *intval = log_priority(val); + info("send log_priority=%i", *intval); + } else if (!strncmp(argv[1], "max_childs=", strlen("max_childs="))) { + intval = (int *) usend_msg.envbuf; + val = &argv[1][strlen("max_childs=")]; + usend_msg.type = UDEVD_SET_MAX_CHILDS; + *intval = atoi(val); + info("send max_childs=%i", *intval); } else { - err("unknown command\n"); + err("error parsing command\n"); goto exit; } sock = socket(AF_LOCAL, SOCK_DGRAM, 0); if (sock == -1) { - info("error getting socket"); + err("error getting socket"); goto exit; } @@ -116,7 +123,7 @@ int main(int argc, char *argv[], char *envp[]) info("error sending message (%s)", strerror(errno)); retval = 1; } else { - dbg("sent message '%x' (%u bytes sent)", usend_msg.type, retval); + dbg("sent message type=0x%02x, %u bytes sent", usend_msg.type, retval); retval = 0; } From e33d1515e2d22fe8f872556dd649e0db3b601057 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 16 Jun 2005 03:26:16 +0200 Subject: [PATCH 21/24] Makefile: remove dev.d/ hotplug.d/ from install target Signed-off-by: Kay Sievers --- Makefile | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index bdb87e5651..8694b917a2 100644 --- a/Makefile +++ b/Makefile @@ -63,10 +63,7 @@ etcdir = ${prefix}/etc sbindir = ${exec_prefix}/sbin usrbindir = ${exec_prefix}/usr/bin mandir = ${prefix}/usr/share/man -hotplugdir = ${etcdir}/hotplug.d/default configdir = ${etcdir}/udev -initdir = ${etcdir}/init.d -dev_ddir = ${etcdir}/dev.d srcdir = . INSTALL = /usr/bin/install -c @@ -347,16 +344,6 @@ install-config: $(INSTALL_DATA) $(LOCAL_CFG_DIR)/udev.rules $(DESTDIR)$(configdir)/rules.d/50-udev.rules; \ fi -install-dev.d: - $(INSTALL) -d $(DESTDIR)$(dev_ddir)/default - $(INSTALL_PROGRAM) -D etc/dev.d/net/hotplug.dev $(DESTDIR)$(dev_ddir)/net/hotplug.dev - -uninstall-dev.d: - - rm $(dev_ddir)/net/hotplug.dev - - rmdir $(dev_ddir)/net - - rmdir $(dev_ddir)/default - - rmdir $(dev_ddir) - install-man: $(INSTALL_DATA) -D udev.8 $(DESTDIR)$(mandir)/man8/udev.8 $(INSTALL_DATA) -D udevinfo.8 $(DESTDIR)$(mandir)/man8/udevinfo.8 @@ -373,19 +360,15 @@ uninstall-man: - rm $(mandir)/man8/udevd.8 - rm $(mandir)/man8/udevsend.8 -install: install-config install-man install-dev.d all +install: install-config install-man all $(INSTALL) -d $(DESTDIR)$(udevdir) - $(INSTALL) -d $(DESTDIR)$(hotplugdir) $(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 $(RECORDER) $(DESTDIR)$(sbindir)/$(RECORDER) $(INSTALL_PROGRAM) -D $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL) $(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO) $(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER) $(INSTALL_PROGRAM) -D $(STARTER) $(DESTDIR)$(sbindir)/$(STARTER) - - ln -f -s $(sbindir)/$(SENDER) $(DESTDIR)$(hotplugdir)/10-udev.hotplug ifndef DESTDIR - killall $(DAEMON) - $(sbindir)/$(DAEMON) --daemon @@ -397,8 +380,7 @@ endif -C $$target $@ ; \ done ; \ -uninstall: uninstall-man uninstall-dev.d - - rm $(hotplugdir)/10-udev.hotplug +uninstall: uninstall-man - rm $(configdir)/rules.d/50-udev.rules - rm $(configdir)/udev.conf - rmdir $(configdir)/rules.d @@ -412,7 +394,6 @@ uninstall: uninstall-man uninstall-dev.d - rm $(sbindir)/$(STARTER) - rm $(usrbindir)/$(INFO) - rm $(usrbindir)/$(TESTER) - - rmdir $(hotplugdir) - rm -rf $(udevdb) - rmdir $(udevdir) - killall $(DAEMON) From 57663b364beda200ec189c889e7d9c9fede37c9a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Jun 2005 10:57:10 +0200 Subject: [PATCH 22/24] remove device node, when type block/char has changed Signed-off-by: Kay Sievers --- README | 3 +-- udev_add.c | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/README b/README index 54cee659a8..a2ce9c7d36 100644 --- a/README +++ b/README @@ -10,8 +10,7 @@ To use: - Your 2.6 kernel must have had CONFIG_HOTPLUG enabled when it was built. -- Make sure sysfs is mounted. udev will figure out where sysfs is mounted, but - the traditional place for it is at /sys. You can mount it by hand by running: +- Make sure sysfs is mounted at /sys. You can mount it by running: mount -t sysfs none /sys - Make sure you have the latest version of the linux-hotplug scripts. They are diff --git a/udev_add.c b/udev_add.c index 2081e503c7..89af96570f 100644 --- a/udev_add.c +++ b/udev_add.c @@ -52,23 +52,6 @@ int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mo struct stat stats; int retval = 0; - if (stat(file, &stats) != 0) - goto create; - - /* preserve node with already correct numbers, to not change the inode number */ - if (((stats.st_mode & S_IFMT) == S_IFBLK || (stats.st_mode & S_IFMT) == S_IFCHR) && - (stats.st_rdev == devt)) { - info("preserve file '%s', cause it has correct dev_t", file); - selinux_setfilecon(file, udev->kernel_name, stats.st_mode); - goto perms; - } - - if (unlink(file) != 0) - dbg("unlink(%s) failed with error '%s'", file, strerror(errno)); - else - dbg("already present file '%s' unlinked", file); - -create: switch (udev->type) { case DEV_BLOCK: mode |= S_IFBLK; @@ -81,6 +64,22 @@ create: return -EINVAL; } + if (stat(file, &stats) != 0) + goto create; + + /* preserve node with already correct numbers, to not change the inode number */ + if ((stats.st_mode & S_IFMT) == (mode & S_IFMT) && (stats.st_rdev == devt)) { + info("preserve file '%s', cause it has correct dev_t", file); + selinux_setfilecon(file, udev->kernel_name, stats.st_mode); + goto perms; + } + + if (unlink(file) != 0) + dbg("unlink(%s) failed with error '%s'", file, strerror(errno)); + else + dbg("already present file '%s' unlinked", file); + +create: selinux_setfscreatecon(file, udev->kernel_name, mode); retval = mknod(file, mode, devt); selinux_resetfscreatecon(); From bf5d2964730e63316861e310d1f24c165b11e961 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 20 Jun 2005 00:29:38 +0200 Subject: [PATCH 23/24] prepare for module loading rules and add MODALIAS key Signed-off-by: Kay Sievers --- test/udev-test.pl | 51 ++++++++++- udev_rules.c | 214 +++++++++++++++++++++++++++++++++++---------- udev_rules.h | 6 ++ udev_rules_parse.c | 14 +++ udev_sysfs.c | 54 ++++++------ 5 files changed, 261 insertions(+), 78 deletions(-) diff --git a/test/udev-test.pl b/test/udev-test.pl index 884abf9e8b..9225352130 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -241,7 +241,7 @@ BUS=="scsi", ID=="0:0:0:0", NAME="first_disk%n" EOF }, { - desc => "test NAME substitution chars", + desc => "test substitution chars", subsys => "block", devpath => "/block/sda/sda3", exp_name => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" , @@ -250,7 +250,7 @@ BUS=="scsi", ID=="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b" EOF }, { - desc => "test NAME substitution chars (with length limit)", + desc => "test substitution chars (with length limit)", subsys => "block", devpath => "/block/sda/sda3", exp_name => "M8-m3-n3-b0:0-sIBM" , @@ -360,6 +360,51 @@ EOF exp_name => "my-foo8" , rules => < "test substitution by variable name", + subsys => "block", + devpath => "/block/sda/sda3", + exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" , + rules => < "test substitution by variable name 2", + subsys => "block", + devpath => "/block/sda/sda3", + exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" , + rules => < "test substitution by variable name 3", + subsys => "block", + devpath => "/block/sda/sda3", + exp_name => "830:0:0:03" , + rules => < "test substitution by variable name 4", + subsys => "block", + devpath => "/block/sda/sda3", + exp_name => "833" , + rules => < "test substitution by variable name 5", + subsys => "block", + devpath => "/block/sda/sda3", + exp_name => "8330:0:0:0" , + rules => < "yes", option => "clean", rules => <path, name); tmpattr = sysfs_get_classdev_attr(class_dev, name); if (tmpattr) goto attr_found; } if (sysfs_device) { + dbg("look for devices attribute '%s/%s'", sysfs_device->path, name); tmpattr = sysfs_get_device_attr(sysfs_device, name); if (tmpattr) goto attr_found; } - return -1; attr_found: @@ -197,56 +198,133 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, { char temp[PATH_SIZE]; char temp2[PATH_SIZE]; - char *tail, *pos, *cpos, *attr, *rest; + char *head, *tail, *cpos, *attr, *rest; int len; int i; - char c; unsigned int next_free_number; struct sysfs_class_device *class_dev_parent; + enum subst_type { + SUBST_UNKNOWN, + SUBST_DEVPATH, + SUBST_ID, + SUBST_KERNEL_NUMBER, + SUBST_KERNEL_NAME, + SUBST_MAJOR, + SUBST_MINOR, + SUBST_RESULT, + SUBST_SYSFS, + SUBST_ENUM, + SUBST_PARENT, + SUBST_TEMP_NODE, + SUBST_ROOT, + SUBST_MODALIAS, + }; + static const struct subst_map { + char *name; + char fmt; + enum subst_type type; + } map[] = { + { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, + { .name = "id", .fmt = 'b', .type = SUBST_ID }, + { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, + { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL_NAME }, + { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, + { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, + { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, + { .name = "sysfs", .fmt = 's', .type = SUBST_SYSFS }, + { .name = "enum", .fmt = 'e', .type = SUBST_ENUM }, + { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, + { .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE }, + { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, + { .name = "modalias", .fmt = 'A', .type = SUBST_MODALIAS }, + {} + }; + enum subst_type type; + const struct subst_map *subst; - pos = string; + head = string; while (1) { - pos = strchr(pos, '%'); - if (pos == NULL) - break; - - pos[0] = '\0'; - tail = pos+1; - len = get_format_len(&tail); - c = tail[0]; - strlcpy(temp, tail+1, sizeof(temp)); - tail = temp; - dbg("format=%c, string='%s', tail='%s'",c , string, tail); + len = -1; + while (head[0] != '\0') { + if (head[0] == '$') { + /* substitute named variable */ + if (head[1] == '\0') + break; + if (head[1] == '$') { + strlcpy(temp, head+2, sizeof(temp)); + strlcpy(head+1, temp, maxsize); + head++; + continue; + } + head[0] = '\0'; + for (subst = map; subst->name; subst++) { + if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) { + type = subst->type; + tail = head + strlen(subst->name)+1; + dbg("will substitute format name '%s'", subst->name); + goto found; + } + } + } + else if (head[0] == '%') { + /* substitute format char */ + if (head[1] == '\0') + break; + if (head[1] == '%') { + strlcpy(temp, head+2, sizeof(temp)); + strlcpy(head+1, temp, maxsize); + head++; + continue; + } + head[0] = '\0'; + tail = head+1; + len = get_format_len(&tail); + for (subst = map; subst->name; subst++) { + if (tail[0] == subst->fmt) { + type = subst->type; + tail++; + dbg("will substitute format char '%c'", subst->fmt); + goto found; + } + } + } + head++; + } + break; +found: attr = get_format_attribute(&tail); + strlcpy(temp, tail, sizeof(temp)); + dbg("format=%i, string='%s', tail='%s', class_dev=%p, sysfs_dev=%p", + type ,string, tail, class_dev, sysfs_device); - switch (c) { - case 'p': + switch (type) { + case SUBST_DEVPATH: strlcat(string, udev->devpath, maxsize); - dbg("substitute kernel name '%s'", udev->kernel_name); + dbg("substitute devpath '%s'", udev->devpath); break; - case 'b': + case SUBST_ID: strlcat(string, udev->bus_id, maxsize); dbg("substitute bus_id '%s'", udev->bus_id); break; - case 'k': + case SUBST_KERNEL_NAME: strlcat(string, udev->kernel_name, maxsize); dbg("substitute kernel name '%s'", udev->kernel_name); break; - case 'n': + case SUBST_KERNEL_NUMBER: strlcat(string, udev->kernel_number, maxsize); dbg("substitute kernel number '%s'", udev->kernel_number); - break; - case 'm': - sprintf(temp2, "%d", minor(udev->devt)); - strlcat(string, temp2, maxsize); - dbg("substitute minor number '%s'", temp2); break; - case 'M': + case SUBST_MAJOR: sprintf(temp2, "%d", major(udev->devt)); strlcat(string, temp2, maxsize); dbg("substitute major number '%s'", temp2); break; - case 'c': + case SUBST_MINOR: + sprintf(temp2, "%d", minor(udev->devt)); + strlcat(string, temp2, maxsize); + dbg("substitute minor number '%s'", temp2); + break; + case SUBST_RESULT: if (udev->program_result[0] == '\0') break; /* get part part of the result string */ @@ -280,7 +358,7 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, dbg("substitute result string '%s'", udev->program_result); } break; - case 's': + case SUBST_SYSFS: if (attr == NULL) { dbg("missing attribute"); break; @@ -307,18 +385,14 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, strlcat(string, temp2, maxsize); dbg("substitute sysfs value '%s'", temp2); break; - case '%': - strlcat(string, "%", maxsize); - pos++; - break; - case 'e': + case SUBST_ENUM: next_free_number = find_free_number(udev, string); if (next_free_number > 0) { sprintf(temp2, "%d", next_free_number); strlcat(string, temp2, maxsize); } break; - case 'P': + case SUBST_PARENT: if (!class_dev) break; class_dev_parent = sysfs_get_classdev_parent(class_dev); @@ -336,7 +410,7 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, udev_cleanup_device(&udev_parent); } break; - case 'N': + case SUBST_TEMP_NODE: if (udev->tmp_node[0] == '\0') { dbg("create temporary device node for callout"); snprintf(udev->tmp_node, sizeof(udev->tmp_node), "%s/.tmp-%u-%u", @@ -347,19 +421,27 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, strlcat(string, udev->tmp_node, maxsize); dbg("substitute temporary device node name '%s'", udev->tmp_node); break; - case 'r': + case SUBST_ROOT: strlcat(string, udev_root, maxsize); dbg("substitute udev_root '%s'", udev_root); break; + case SUBST_MODALIAS: + if (find_sysfs_attribute(NULL, sysfs_device, "modalias", temp2, sizeof(temp2)) != 0) + break; + strlcat(string, temp2, maxsize); + dbg("substitute MODALIAS '%s'", temp2); + break; default: - err("unknown substitution type '%%%c'", c); + err("unknown substitution type=%i", type); break; } - /* truncate to specified length */ - if (len > 0) - pos[len] = '\0'; + /* possibly truncate to format-char specified length */ + if (len != -1) { + head[len] = '\0'; + dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); + } - strlcat(string, tail, maxsize); + strlcat(string, temp, maxsize); } } @@ -519,6 +601,42 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule, dbg(KEY_SUBSYSTEM " key is true"); } + if (rule->devpath_operation != KEY_OP_UNSET) { + dbg("check for " KEY_DEVPATH " rule->devpath='%s' udev->devpath='%s'", + rule->devpath, udev->devpath); + if (strcmp_pattern(rule->devpath, udev->devpath) != 0) { + dbg(KEY_DEVPATH " is not matching"); + if (rule->devpath_operation != KEY_OP_NOMATCH) + goto exit; + } else { + dbg(KEY_DEVPATH " matches"); + if (rule->devpath_operation == KEY_OP_NOMATCH) + goto exit; + } + dbg(KEY_DEVPATH " key is true"); + } + + if (rule->modalias_operation != KEY_OP_UNSET) { + char value[NAME_SIZE]; + + if (find_sysfs_attribute(NULL, sysfs_device, "modalias", value, sizeof(value)) != 0) { + dbg(KEY_MODALIAS " value not found"); + goto exit; + } + dbg("check for " KEY_MODALIAS " rule->modalias='%s' modalias='%s'", + rule->modalias, value); + if (strcmp_pattern(rule->modalias, value) != 0) { + dbg(KEY_MODALIAS " is not matching"); + if (rule->modalias_operation != KEY_OP_NOMATCH) + goto exit; + } else { + dbg(KEY_MODALIAS " matches"); + if (rule->modalias_operation == KEY_OP_NOMATCH) + goto exit; + } + dbg(KEY_MODALIAS " key is true"); + } + if (rule->env_pair_count) { int i; @@ -729,13 +847,13 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d /* look for a matching rule to apply */ list_for_each_entry(rule, &udev_rule_list, node) { + if (udev->name_set && rule->name_operation != KEY_OP_UNSET) { + dbg("node name already set, rule ignored"); + continue; + } + dbg("process rule"); if (match_rule(udev, rule, class_dev, sysfs_device) == 0) { - if (udev->name_set && rule->name_operation != KEY_OP_UNSET) { - dbg("node name already set, rule ignored"); - continue; - } - /* apply options */ if (rule->ignore_device) { info("configured rule in '%s[%i]' applied, '%s' is ignored", @@ -917,7 +1035,7 @@ int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device) } if (rule->run[0] != '\0') { strlcpy(program, rule->run, sizeof(program)); - apply_format(udev, program, sizeof(program), NULL, NULL); + apply_format(udev, program, sizeof(program), NULL, sysfs_device); dbg("add run '%s'", program); name_list_add(&udev->run_list, program, 0); } diff --git a/udev_rules.h b/udev_rules.h index 75ffd5cb0f..2bf8107543 100644 --- a/udev_rules.h +++ b/udev_rules.h @@ -31,6 +31,7 @@ #define KEY_KERNEL "KERNEL" #define KEY_SUBSYSTEM "SUBSYSTEM" #define KEY_ACTION "ACTION" +#define KEY_DEVPATH "DEVPATH" #define KEY_BUS "BUS" #define KEY_ID "ID" #define KEY_PROGRAM "PROGRAM" @@ -38,6 +39,7 @@ #define KEY_DRIVER "DRIVER" #define KEY_SYSFS "SYSFS" #define KEY_ENV "ENV" +#define KEY_MODALIAS "MODALIAS" #define KEY_NAME "NAME" #define KEY_SYMLINK "SYMLINK" #define KEY_OWNER "OWNER" @@ -80,6 +82,8 @@ struct udev_rule { enum key_operation subsystem_operation; char action[NAME_SIZE]; enum key_operation action_operation; + char devpath[PATH_SIZE]; + enum key_operation devpath_operation; char bus[NAME_SIZE]; enum key_operation bus_operation; char id[NAME_SIZE]; @@ -94,6 +98,8 @@ struct udev_rule { int sysfs_pair_count; struct key_pair env_pair[KEY_ENV_PAIRS_MAX]; int env_pair_count; + enum key_operation modalias_operation; + char modalias[PATH_SIZE]; char name[PATH_SIZE]; enum key_operation name_operation; diff --git a/udev_rules_parse.c b/udev_rules_parse.c index 57c797dd31..89925a35e4 100644 --- a/udev_rules_parse.c +++ b/udev_rules_parse.c @@ -269,6 +269,13 @@ static int rules_parse(const char *filename) continue; } + if (strcasecmp(key, KEY_DEVPATH) == 0) { + strlcpy(rule.devpath, value, sizeof(rule.devpath)); + rule.devpath_operation = operation; + valid = 1; + continue; + } + if (strcasecmp(key, KEY_BUS) == 0) { strlcpy(rule.bus, value, sizeof(rule.bus)); rule.bus_operation = operation; @@ -325,6 +332,13 @@ static int rules_parse(const char *filename) continue; } + if (strcasecmp(key, KEY_MODALIAS) == 0) { + strlcpy(rule.modalias, value, sizeof(rule.modalias)); + rule.modalias_operation = operation; + valid = 1; + continue; + } + if (strcasecmp(key, KEY_DRIVER) == 0) { strlcpy(rule.driver, value, sizeof(rule.driver)); rule.driver_operation = operation; diff --git a/udev_sysfs.c b/udev_sysfs.c index f9ff1ed2f9..5c43190644 100644 --- a/udev_sysfs.c +++ b/udev_sysfs.c @@ -297,38 +297,38 @@ int wait_for_devices_device(struct sysfs_device *devices_dev, { .bus = "usb", .file = "idVendor" }, { .bus = "usb", .file = "iInterface" }, { .bus = "usb", .file = "bNumEndpoints" }, - { .bus = "usb-serial", .file = "detach_state" }, - { .bus = "ide", .file = "detach_state" }, + { .bus = "usb-serial", .file = "power" }, + { .bus = "ide", .file = "power" }, { .bus = "pci", .file = "vendor" }, - { .bus = "platform", .file = "detach_state" }, - { .bus = "pcmcia", .file = "detach_state" }, - { .bus = "i2c", .file = "detach_state" }, + { .bus = "platform", .file = "power" }, + { .bus = "pcmcia", .file = "power" }, + { .bus = "i2c", .file = "power" }, { .bus = "ieee1394", .file = "node_count" }, { .bus = "ieee1394", .file = "nodeid" }, { .bus = "ieee1394", .file = "address" }, { .bus = "bttv-sub", .file = NULL }, - { .bus = "pnp", .file = "detach_state" }, - { .bus = "eisa", .file = "detach_state" }, - { .bus = "serio", .file = "detach_state" }, - { .bus = "pseudo", .file = "detach_state" }, - { .bus = "mmc", .file = "detach_state" }, - { .bus = "macio", .file = "detach_state" }, - { .bus = "of_platform", .file = "detach_state" }, - { .bus = "vio", .file = "detach_state" }, - { .bus = "ecard", .file = "detach_state" }, - { .bus = "sa1111-rab", .file = "detach_state" }, - { .bus = "amba", .file = "detach_state" }, - { .bus = "locomo-bus", .file = "detach_state" }, - { .bus = "logicmodule", .file = "detach_state" }, - { .bus = "parisc", .file = "detach_state" }, - { .bus = "ocp", .file = "detach_state" }, - { .bus = "dio", .file = "detach_state" }, - { .bus = "MCA", .file = "detach_state" }, - { .bus = "wl", .file = "detach_state" }, - { .bus = "ccwgroup", .file = "detach_state" }, - { .bus = "css", .file = "detach_state" }, - { .bus = "ccw", .file = "detach_state" }, - { .bus = "iucv", .file = "detach_state" }, + { .bus = "pnp", .file = "power" }, + { .bus = "eisa", .file = "power" }, + { .bus = "serio", .file = "power" }, + { .bus = "pseudo", .file = "power" }, + { .bus = "mmc", .file = "power" }, + { .bus = "macio", .file = "power" }, + { .bus = "of_platform", .file = "power" }, + { .bus = "vio", .file = "power" }, + { .bus = "ecard", .file = "power" }, + { .bus = "sa1111-rab", .file = "power" }, + { .bus = "amba", .file = "power" }, + { .bus = "locomo-bus", .file = "power" }, + { .bus = "logicmodule", .file = "power" }, + { .bus = "parisc", .file = "power" }, + { .bus = "ocp", .file = "power" }, + { .bus = "dio", .file = "power" }, + { .bus = "MCA", .file = "power" }, + { .bus = "wl", .file = "power" }, + { .bus = "ccwgroup", .file = "power" }, + { .bus = "css", .file = "power" }, + { .bus = "ccw", .file = "power" }, + { .bus = "iucv", .file = "power" }, { NULL, NULL } }; const struct device_file *devicefile = NULL; From d27d3bb05288fb5e70bc3f3fc7da1dc8ee5413a8 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 22 Jun 2005 01:31:24 +0200 Subject: [PATCH 24/24] fix udevstart and let all events trvel trough udev Signed-off-by: Kay Sievers --- udev.c | 14 +++++++------- udevtest.c | 17 ++++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/udev.c b/udev.c index f7b9bf3573..67d081d005 100644 --- a/udev.c +++ b/udev.c @@ -200,13 +200,13 @@ int main(int argc, char *argv[], char *envp[]) info("device event will be ignored"); goto cleanup; } - } else if (strcmp(action, "remove") == 0) { - dbg("devices remove"); - udev_rules_get_run(&udev, NULL); - if (udev.ignore_device) { - info("device event will be ignored"); - goto cleanup; - } + } + } else { + dbg("default handling"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto cleanup; } } diff --git a/udevtest.c b/udevtest.c index 93387f76d0..d3e43593bf 100644 --- a/udevtest.c +++ b/udevtest.c @@ -98,12 +98,6 @@ int main(int argc, char *argv[], char *envp[]) /* fill in values and test_run flag*/ udev_init_device(&udev, devpath, subsystem, "add"); - /* skip subsystems without "dev", but handle net devices */ - if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) { - info("don't care about '%s' devices", udev.subsystem); - return 2; - } - /* open the device */ snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath); path[sizeof(path)-1] = '\0'; @@ -112,13 +106,18 @@ int main(int argc, char *argv[], char *envp[]) info("sysfs_open_class_device_path failed"); return 1; } - info("opened class_dev->name='%s'", class_dev->name); + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS) + udev.devt = get_devt(class_dev); + /* simulate node creation with test flag */ udev.test_run = 1; - udev_add_device(&udev, class_dev); - + if (udev.type == DEV_NET || udev.devt) { + udev_rules_get_name(&udev, class_dev); + udev_add_device(&udev, class_dev); + } else + info("only char and block devices with a dev-file are supported by this test program"); sysfs_close_class_device(class_dev); return 0;