aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--nldev-handler.c128
-rw-r--r--nldev.c132
3 files changed, 191 insertions, 75 deletions
diff --git a/Makefile b/Makefile
index e28138f..a15252b 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ include config.mk
SRC = ${NAME}.c
OBJ = ${SRC:.c=.o} log.o
-all: options ${NAME}
+all: options ${NAME} nldev-handler
options:
@echo ${NAME} build options:
@@ -24,6 +24,10 @@ ${NAME}: ${OBJ}
@echo CC -o $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
+# hack for now
+nldev-handler: nldev-handler.o log.o
+ ${CC} -o $@ $^ ${LDFLAGS}
+
clean:
@echo cleaning
@rm -f ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz
diff --git a/nldev-handler.c b/nldev-handler.c
new file mode 100644
index 0000000..4fa6e2a
--- /dev/null
+++ b/nldev-handler.c
@@ -0,0 +1,128 @@
+
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "log.h"
+
+#define EVENT_TIMEOUT 2000
+
+void
+child(char *runpath)
+{
+ pid_t pid;
+
+ if (!(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);
+}
+
+
+void
+usage(void)
+{
+ die("usage: %s [-d] [-r run]\n", argv0);
+}
+
+int main(int argc, char *argv[])
+{
+ struct pollfd fds;
+ int r;
+ static char buf[16384];
+ char *runpath = "/bin/mdev";
+ char *subsystem = NULL;
+
+ ARGBEGIN {
+ case 'd':
+ dodebug = 1;
+ break;
+ case 'r':
+ runpath = EARGF(usage());
+ break;
+ case 'f':
+ subsystem = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ dbg("runpath=%s\n", runpath);
+
+ fds.fd = 0; /* stdin */
+ fds.events = POLLIN;
+ while ((r = poll(&fds, 1, EVENT_TIMEOUT)) > 0) {
+ size_t len;
+ int i, slen;
+ char *key, *value;
+
+ clearenv();
+ setenv("PATH", "/sbin:/bin", 1);
+
+ if (!(fds.revents & POLLIN))
+ continue;
+
+ len = read(fds.fd, buf, sizeof(buf)-1);
+ buf[len] = 0;
+ dbg("Got %u bytes", len);
+
+ 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);
+ }
+
+ if (fds.revents & POLLHUP) {
+ dbg("parent hung up\n");
+ return 0;
+ }
+ }
+ if (r == -1)
+ edie("poll");
+
+ if (r == 0)
+ dbg("exit due to timeout");
+
+ return 0;
+}
+
+
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);