aboutsummaryrefslogtreecommitdiffstats
path: root/nldev.c
diff options
context:
space:
mode:
Diffstat (limited to 'nldev.c')
-rw-r--r--nldev.c132
1 files changed, 58 insertions, 74 deletions
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);