From c9e4f2c16ea032e9359b0203a2a11973d172ace7 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Thu, 12 Mar 2015 15:55:08 +0100 Subject: forward the events to a helper process via pipe To reduce number of forks we pass over the events to a helper program via a pipe. when there are no events for a certain time the helper program can exit to save memory. Once new events arrives the nldev application will respawn the helper. --- nldev.c | 132 ++++++++++++++++++++++++++++------------------------------------ 1 file changed, 58 insertions(+), 74 deletions(-) (limited to 'nldev.c') diff --git a/nldev.c b/nldev.c index eab53ff..f859eed 100644 --- a/nldev.c +++ b/nldev.c @@ -24,10 +24,15 @@ #include "arg.h" #include "log.h" -char *argv0; int listfd = -1; int dofork = 0; +struct handler { + int fd; + int argc; + char **argv; +}; + void disableoom(void) { @@ -47,30 +52,34 @@ disableoom(void) } void -child(char *runpath) +spawn_handler(struct handler *child) { - int fd, pid; - - if (!(pid = fork())) { - if (dofork && !dodebug) { - fd = open("/dev/null", O_RDWR); - if (fd >= 0) { - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) - close(fd); - } - } + int pipefd[2]; + + if (pipe(pipefd) == -1) + edie("pipe"); + + pid_t pid = fork(); - dbg("running %s", runpath); - if (execlp(runpath, basename(runpath), NULL) < 0) - edie("execvp"); - exit(0); - } if (pid < 0) edie("fork"); - waitpid(pid, NULL, 0); + if (pid == 0) { + close(pipefd[1]); + dup2(pipefd[0], 0); + execv(child->argv[0], child->argv); + edie("execl"); + } + close(pipefd[0]); + child->fd = pipefd[1]; +} + +int +write_to_handler(struct handler *child, const char *buf, size_t count) +{ + if (child->fd == -1) + spawn_handler(child); + return write(child->fd, buf, count); } void @@ -143,26 +152,25 @@ init_netlink_socket(void) void usage(void) { - die("usage: %s [-hdb] [-ku] [-f subsystem] [-r run]\n", argv0); + die("usage: %s [-hdb] [-ku] [-- run [...]]\n", argv0); } int main(int argc, char *argv[]) { struct sockaddr_nl cnls; - struct pollfd fds; + struct pollfd fds[2]; struct msghdr hdr; struct iovec iov; - char buf[4097], *subsystem, *runpath, *key, *value, - cbuf[CMSG_SPACE(sizeof(struct ucred))]; + char buf[4097], cbuf[CMSG_SPACE(sizeof(struct ucred))]; struct cmsghdr *chdr; struct ucred *cred; - int i, len, slen, showudev, showkernel; + int len, showudev, showkernel; + + struct handler child; showkernel = 1; showudev = 1; - subsystem = NULL; - runpath = "/bin/mdev"; ARGBEGIN { case 'b': @@ -171,25 +179,27 @@ main(int argc, char *argv[]) case 'd': dodebug = 1; break; - case 'f': - subsystem = EARGF(usage()); - break; case 'k': showudev = 0; break; case 'u': showkernel = 0; break; - case 'r': - runpath = EARGF(usage()); - break; default: usage(); } ARGEND; - fds.events = POLLIN; - fds.fd = init_netlink_socket(); - listfd = fds.fd; + child.fd = -1; + child.argc = argc; + child.argv = argv; + + fds[0].events = POLLIN; + fds[0].fd = init_netlink_socket(); + + fds[1].fd = child.fd; + fds[1].events = POLLERR; + + listfd = fds[0].fd; if (dofork) { if (daemon(0, 0) < 0) @@ -201,9 +211,15 @@ main(int argc, char *argv[]) disableoom(); buf[sizeof(buf)-1] = '\0'; - while (poll(&fds, 1, -1) > -1) { - clearenv(); - setenv("PATH", "/sbin:/bin", 1); + while (poll(fds, 2, -1) > -1) { + if (fds[1].revents & POLLERR) { + dbg("handler exited"); + close(child.fd); + fds[1].fd = child.fd = -1; + } + + if (!(fds[0].revents & POLLIN)) + continue; iov.iov_base = &buf; iov.iov_len = sizeof(buf); @@ -215,7 +231,7 @@ main(int argc, char *argv[]) hdr.msg_name = &cnls; hdr.msg_namelen = sizeof(cnls); - len = recvmsg(fds.fd, &hdr, 0); + len = recvmsg(fds[0].fd, &hdr, 0); if (len < 0) { if (errno == EINTR) continue; @@ -255,40 +271,8 @@ main(int argc, char *argv[]) if (cnls.nl_pid > 0) continue; } - - slen = 0; - for (i = 0; i < len; i += slen + 1) { - key = buf + i; - value = strchr(key, '='); - slen = strlen(buf+i); - - if (!slen || value == NULL) - continue; - if (subsystem && !strncmp(key, "SUBSYSTEM=", 10) - && !strstr(key+10, subsystem)) { - dbg("subsystem filter '%s' applied.", - subsystem); - break; - } - - value[0] = '\0'; - value++; - - /* - * We generally trust the kernel. But there - * might be some udev flaw. (It's >20k sloc!) - */ - if (strcmp(key, "PATH")) { - setenv(key, value, 1); - dbg("%s = \"%s\"", key, value); - } - } - if (getenv("ACTION") != NULL && - getenv("DEVPATH") != NULL && - getenv("SUBSYSTEM") != NULL && - getenv("SEQNUM") != NULL) { - child(runpath); - } + write_to_handler(&child, buf, len); + fds[1].fd = child.fd; } shutdown(listfd, SHUT_RDWR); -- cgit v1.2.3