From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kay Sievers Date: Thu, 18 Aug 2005 19:23:27 +0000 Subject: Re: move udev-rules parsing into the daemon Message-Id: <20050818192327.GA10257@vrfy.org> MIME-Version: 1 Content-Type: multipart/mixed; boundary="u3/rZRmxL6MmkK24" List-Id: References: <20050731004227.GA26803@vrfy.org> In-Reply-To: <20050731004227.GA26803@vrfy.org> To: linux-hotplug@vger.kernel.org --u3/rZRmxL6MmkK24 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Aug 12, 2005 at 11:04:11AM -0700, Greg KH wrote: > On Fri, Aug 12, 2005 at 04:49:36AM +0200, Kay Sievers wrote: > > On Fri, Aug 12, 2005 at 01:06:24AM +0200, Kay Sievers wrote: > > > On Wed, Aug 10, 2005 at 11:13:14PM -0700, Greg KH wrote: > > > > On Tue, Aug 09, 2005 at 04:30:07AM +0200, Kay Sievers wrote: > > > > > Here we go with the Inotify version on top of the current tree. > > > > > I've added some stuff to our libc-wrapper file until the inotify > > > > > headers have reached glibc and we can just add an #include to > > > > > udevd.c for it. > > > > > > > > Looks good to me. > > > > > > Here is a version on top of the new 066. > > > > New version to compile successfully with glibc and klibc on: > > i386, x86_64, ppc, ppc64, ia64, s390, s390x > > I'm happy with this, care to add this to your git tree, so I can add it > to mainline? Any one else have any objections to this? Here is a version on top of the current release. We hopefully fixed all remaining issues with today's version 068 so this can go into mainline next week. Thanks, Kay --u3/rZRmxL6MmkK24 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline; filename="udev-rules-in-daemon-01.patch" diff --git a/etc/udev/udev.conf.in b/etc/udev/udev.conf.in --- a/etc/udev/udev.conf.in +++ b/etc/udev/udev.conf.in @@ -9,6 +9,8 @@ udev_db="@udevdir@/.udevdb" # The name and location of the udev rules file(s). udev_rules="@configdir@/rules.d" -# The syslog(3) priority: "err", "info", or the numerical value. +# The initial syslog(3) priority: "err", "info", "debug" or its +# numerical equivalent. For runtime debugging, change the daemons +# internal state with: "udevcontrol log_priority=". udev_log="err" diff --git a/klibc/klibc/SYSCALLS.def b/klibc/klibc/SYSCALLS.def --- a/klibc/klibc/SYSCALLS.def +++ b/klibc/klibc/SYSCALLS.def @@ -114,6 +114,9 @@ int lchown32,lchown::lchown(const char * int getcwd::__getcwd(char *, size_t) int utime(const char *, const struct utimbuf *) int utimes(const char *, const struct timeval *) + int inotify_init(void) + int inotify_add_watch(int, const char *, __u32) + int inotify_rm_watch(int, __u32) ; ; I/O operations diff --git a/udev_libc_wrapper.h b/udev_libc_wrapper.h --- a/udev_libc_wrapper.h +++ b/udev_libc_wrapper.h @@ -25,6 +25,75 @@ #include #include #include +#include + +/* needed until Inotify! reaches libc */ +#ifndef __NR_inotify_init +#if defined(__i386__) +# define __NR_inotify_init 291 +# define __NR_inotify_add_watch 292 +# define __NR_inotify_rm_watch 293 +#elif defined(__x86_64__) +# define __NR_inotify_init 253 +# define __NR_inotify_add_watch 254 +# define __NR_inotify_rm_watch 255 +#elif defined(__powerpc__) || defined(__powerpc64__) +# define __NR_inotify_init 275 +# define __NR_inotify_add_watch 276 +# define __NR_inotify_rm_watch 277 +#elif defined (__ia64__) +# define __NR_inotify_init 1277 +# define __NR_inotify_add_watch 1278 +# define __NR_inotify_rm_watch 1279 +#elif defined (__s390__) +# define __NR_inotify_init 284 +# define __NR_inotify_add_watch 285 +# define __NR_inotify_rm_watch 286 +#elif defined (__alpha__) +# define __NR_inotify_init 444 +# define __NR_inotify_add_watch 445 +# define __NR_inotify_rm_watch 446 +#elif defined (__sparc__) || defined (__sparc64__) +# define __NR_inotify_init 151 +# define __NR_inotify_add_watch 152 +# define __NR_inotify_rm_watch 156 +#elif defined (__arm__) +# define __NR_inotify_init 316 +# define __NR_inotify_add_watch 317 +# define __NR_inotify_rm_watch 318 +#elif defined (__sh__) +# define __NR_inotify_init 290 +# define __NR_inotify_add_watch 291 +# define __NR_inotify_rm_watch 292 +#else +# error "Unsupported architecture!" +#endif +#endif /* __NR_inotify_init */ + +#ifdef __KLIBC__ +static inline _syscall0(int, inotify_init); +static inline _syscall3(int, inotify_add_watch, int, fd, const char*, name, __u32, mask); +#else +static inline int inotify_init(void) +{ + return syscall(__NR_inotify_init); +} + +static inline int inotify_add_watch(int fd, const char *name, __u32 mask) +{ + return syscall(__NR_inotify_add_watch, fd, name, mask); +} +#endif + +/* needed until it reaches libc */ +#ifndef IN_CREATE +#define IN_CREATE 0x00000100 /* Subfile was created */ +#define IN_MOVED_FROM 0x00000040 /* File was moved from X */ +#define IN_MOVED_TO 0x00000080 /* File was moved to Y */ +#define IN_DELETE 0x00000200 /* Subfile was deleted */ +#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */ +#endif /* needed for our signal handlers to work */ #undef asmlinkage diff --git a/udevcontrol.c b/udevcontrol.c --- a/udevcontrol.c +++ b/udevcontrol.c @@ -89,6 +89,8 @@ int main(int argc, char *argv[], char *e usend_msg.type = UDEVD_STOP_EXEC_QUEUE; else if (!strcmp(arg, "start_exec_queue")) usend_msg.type = UDEVD_START_EXEC_QUEUE; + else if (!strcmp(arg, "reload_rules")) + usend_msg.type = UDEVD_RELOAD_RULES; else if (!strncmp(arg, "log_priority=", strlen("log_priority="))) { intval = (int *) usend_msg.envbuf; val = &arg[strlen("log_priority=")]; @@ -106,6 +108,7 @@ int main(int argc, char *argv[], char *e " log_priority= set the udev log level for the daemon\n" " stop_exec_queue keep udevd from executing events, queue only\n" " start_exec_queue execute events, flush queue\n" + " reload_rules reloads the rules files\n" " max_childs= maximum number of childs running at the same time\n" " --help print this help text\n\n"); exit(0); diff --git a/udevd.c b/udevd.c --- a/udevd.c +++ b/udevd.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -46,13 +47,16 @@ #include "udev_libc_wrapper.h" #include "udev.h" #include "udev_version.h" +#include "udev_rules.h" #include "udev_utils.h" #include "udevd.h" #include "logging.h" /* global variables*/ +struct udev_rules rules; static int udevd_sock; static int uevent_netlink_sock; +static int inotify_fd; static pid_t sid; static int pipefds[2] = {-1, -1}; @@ -60,10 +64,10 @@ static volatile int sigchilds_waiting; static volatile int run_msg_q; static volatile int sig_flag; static volatile int udev_exit; +static volatile int reload_config; static int init_phase = 1; static int run_exec_q; static int stop_exec_q; -static char *udev_bin; static int event_timeout; static int max_childs; static int max_childs_running; @@ -76,7 +80,7 @@ static LIST_HEAD(running_list); #ifdef USE_LOG -void log_message (int priority, const char *format, ...) +void log_message(int priority, const char *format, ...) { va_list args; @@ -161,10 +165,55 @@ static void msg_queue_insert(struct ueve return; } -/* forks event and removes event from run queue when finished */ +static void asmlinkage udev_event_sig_handler(int signum) +{ + if (signum == SIGALRM) + exit(1); +} + +static int udev_event_process(struct uevent_msg *msg) +{ + struct sigaction act; + struct udevice udev; + struct name_entry *name_loop; + int i; + int retval; + + /* set signal handlers */ + memset(&act, 0x00, sizeof(act)); + act.sa_handler = (void (*)(int)) udev_event_sig_handler; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGALRM, &act, NULL); + + /* trigger timeout to prevent hanging processes */ + alarm(UDEV_ALARM_TIMEOUT); + + /* reconstruct env from message */ + for (i = 0; msg->envp[i]; i++) + putenv(msg->envp[i]); + + udev_init_device(&udev, msg->devpath, msg->subsystem, msg->action); + retval = udev_process_event(&rules, &udev); + + /* run programs collected by RUN-key*/ + if (!retval) { + list_for_each_entry(name_loop, &udev.run_list, node) { + if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0) + pass_env_to_socket(&name_loop->name[strlen("socket:")], msg->devpath, msg->action); + else + run_program(name_loop->name, udev.subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO)); + } + } + + udev_cleanup_device(&udev); + + return 0; +} + +/* runs event and removes event from run queue when finished */ static void udev_event_run(struct uevent_msg *msg) { - char *const argv[] = { "udev", msg->subsystem, NULL }; pid_t pid; struct sysinfo info; @@ -172,14 +221,20 @@ static void udev_event_run(struct uevent switch (pid) { case 0: /* child */ - if (uevent_netlink_sock != -1) + if (uevent_netlink_sock > 0) close(uevent_netlink_sock); + if (inotify_fd > 0) + close(inotify_fd); close(udevd_sock); logging_close(); + + logging_init("udevd-event"); setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); - execve(udev_bin, argv, msg->envp); - err("exec of child failed"); - _exit(1); + udev_event_process(msg); + info("seq %llu finished", msg->seqnum); + + logging_close(); + exit(0); case -1: err("fork of child failed"); msg_queue_delete(msg); @@ -547,7 +602,7 @@ static struct uevent_msg *get_udevd_msg( switch (usend_msg.type) { case UDEVD_UEVENT_UDEVSEND: case UDEVD_UEVENT_INITSEND: - dbg("udevd event message received"); + 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); @@ -576,6 +631,10 @@ static struct uevent_msg *get_udevd_msg( info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval); max_childs = *intval; break; + case UDEVD_RELOAD_RULES: + info("udevd message (RELOAD_RULES) received"); + reload_config = 1; + break; default: dbg("unknown message type"); } @@ -651,6 +710,9 @@ static void asmlinkage sig_handler(int s /* set flag, then write to pipe if needed */ sigchilds_waiting = 1; break; + case SIGHUP: + reload_config = 1; + break; } /* if pipe is empty, write to pipe to force select to return, @@ -852,17 +914,11 @@ int main(int argc, char *argv[], char *e err("error fcntl on read pipe: %s", strerror(errno)); goto exit; } - retval = fcntl(pipefds[0], F_SETFD, FD_CLOEXEC); - if (retval < 0) - err("error fcntl on read pipe: %s", strerror(errno)); retval = fcntl(pipefds[1], F_SETFL, O_NONBLOCK); if (retval < 0) { err("error fcntl on write pipe: %s", strerror(errno)); goto exit; } - retval = fcntl(pipefds[1], F_SETFD, FD_CLOEXEC); - if (retval < 0) - err("error fcntl on write pipe: %s", strerror(errno)); /* set signal handlers */ memset(&act, 0x00, sizeof(struct sigaction)); @@ -875,24 +931,24 @@ int main(int argc, char *argv[], char *e sigaction(SIGCHLD, &act, NULL); sigaction(SIGHUP, &act, NULL); + /* parse the rules and keep it in memory */ + udev_rules_init(&rules, 0, 1); + if (init_udevd_socket() < 0) { if (errno == EADDRINUSE) dbg("another udevd running, exit"); else dbg("error initialising udevd socket: %s", strerror(errno)); - goto exit; } if (init_uevent_netlink_sock() < 0) - info("uevent socket not available"); + err("uevent socket not available"); - /* 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; + /* watch rules directory */ + inotify_fd = inotify_init(); + if (inotify_fd > 0) + inotify_add_watch(inotify_fd, udev_rules_filename, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); /* init of expected_seqnum value */ value = getenv("UDEVD_EXPECTED_SEQNUM"); @@ -925,6 +981,9 @@ int main(int argc, char *argv[], char *e max_childs_running = UDEVD_MAX_CHILDS_RUNNING; info("initialize max_childs_running to %u", max_childs_running); + /* clear environment for forked event processes */ + clearenv(); + /* export log_priority , as called programs may want to follow that setting */ sprintf(log, "UDEV_LOG=%i", udev_log_priority); putenv(log); @@ -938,8 +997,10 @@ int main(int argc, char *argv[], char *e FD_SET(udevd_sock, &readfds); if (uevent_netlink_sock > 0) FD_SET(uevent_netlink_sock, &readfds); + if (inotify_fd > 0) + FD_SET(inotify_fd, &readfds); - fdcount = select(UDEV_MAX(udevd_sock, uevent_netlink_sock)+1, &readfds, NULL, NULL, NULL); + fdcount = select(UDEV_MAX(uevent_netlink_sock, inotify_fd)+1, &readfds, NULL, NULL, NULL); if (fdcount < 0) { if (errno != EINTR) dbg("error in select: %s", strerror(errno)); @@ -986,6 +1047,33 @@ int main(int argc, char *argv[], char *e sig_flag = 0; } + /* rules directory inotify watch */ + if (FD_ISSET(inotify_fd, &readfds)) { + int nbytes; + + /* discard all possible events, we can just reload the config */ + if ((ioctl(inotify_fd, FIONREAD, &nbytes) == 0) && nbytes) { + char *buf; + + reload_config = 1; + buf = malloc(nbytes); + if (!buf) { + err("error getting buffer for inotify, disable watching"); + close(inotify_fd); + inotify_fd = -1; + } + read(inotify_fd, buf, nbytes); + free(buf); + } + } + + /* rules changed, set by inotify or a signal*/ + if (reload_config) { + udev_rules_close(&rules); + udev_rules_init(&rules, 0, 1); + reload_config = 0; + } + /* forked child have returned */ if (sigchilds_waiting) { sigchilds_waiting = 0; @@ -1011,6 +1099,8 @@ int main(int argc, char *argv[], char *e } exit: + udev_rules_close(&rules); + if (pipefds[0] > 0) close(pipefds[0]); if (pipefds[1] > 0) @@ -1018,6 +1108,8 @@ exit: if (udevd_sock > 0) close(udevd_sock); + if (inotify_fd > 0) + close(inotify_fd); if (uevent_netlink_sock > 0) close(uevent_netlink_sock); diff --git a/udevd.h b/udevd.h --- a/udevd.h +++ b/udevd.h @@ -54,6 +54,7 @@ enum udevd_msg_type { UDEVD_START_EXEC_QUEUE, UDEVD_SET_LOG_LEVEL, UDEVD_SET_MAX_CHILDS, + UDEVD_RELOAD_RULES, }; --u3/rZRmxL6MmkK24-- ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel