aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2015-03-15 15:30:01 +0100
committerNatanael Copa <ncopa@alpinelinux.org>2015-03-15 15:30:01 +0100
commit311b810b9e2660231935c085429d94c5567b9522 (patch)
tree3c999c7533395ff7b38b92ed19cbc4f0068d8a1a
parentba51e3b67883f80462b667aa776e89168347739d (diff)
downloadnldev-311b810b9e2660231935c085429d94c5567b9522.tar.bz2
nldev-311b810b9e2660231935c085429d94c5567b9522.tar.xz
pass over the netlink socket to handler instead of using a pipe
hand over the netlink socket directly to the handler and let handler read from netlink instead of forwarding the message via pipe. This simplifies the logic of the longtime running netlink daemon and it simplifies the handling of partially read messages since all reading happens is done by the handler.
-rw-r--r--nldev-handler.c80
-rw-r--r--nldev.c133
2 files changed, 88 insertions, 125 deletions
diff --git a/nldev-handler.c b/nldev-handler.c
index 4fa6e2a..f4f7eb4 100644
--- a/nldev-handler.c
+++ b/nldev-handler.c
@@ -1,12 +1,17 @@
+#include <errno.h>
#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 <sys/socket.h>
+
+#include <linux/netlink.h>
#include "log.h"
@@ -33,21 +38,31 @@ child(char *runpath)
void
usage(void)
{
- die("usage: %s [-d] [-r run]\n", argv0);
+ die("usage: %s [-dku] [-f subsystem] [-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;
+ int showudev, showkernel;
+
+ showudev = 1;
+ showkernel = 1;
+
ARGBEGIN {
case 'd':
dodebug = 1;
break;
+ case 'k':
+ showudev = 0;
+ break;
+ case 'u':
+ showkernel = 0;
+ break;
case 'r':
runpath = EARGF(usage());
break;
@@ -66,6 +81,13 @@ int main(int argc, char *argv[])
size_t len;
int i, slen;
char *key, *value;
+ struct iovec iov;
+ char cbuf[CMSG_SPACE(sizeof(struct ucred))];
+ char buf[16384];
+ struct cmsghdr *chdr;
+ struct ucred *cred;
+ struct msghdr hdr;
+ struct sockaddr_nl cnls;
clearenv();
setenv("PATH", "/sbin:/bin", 1);
@@ -73,11 +95,57 @@ int main(int argc, char *argv[])
if (!(fds.revents & POLLIN))
continue;
- len = read(fds.fd, buf, sizeof(buf)-1);
- buf[len] = 0;
- dbg("Got %u bytes", len);
+ iov.iov_base = &buf;
+ iov.iov_len = sizeof(buf);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_control = cbuf;
+ hdr.msg_controllen = sizeof(cbuf);
+ hdr.msg_name = &cnls;
+ hdr.msg_namelen = sizeof(cnls);
+
+ len = recvmsg(fds.fd, &hdr, 0);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ edie("recvmsg");
+ }
+ if (len < 32 || len >= sizeof(buf))
+ continue;
+
+ chdr = CMSG_FIRSTHDR(&hdr);
+ if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS)
+ continue;
+
+ /*
+ * Don't allow anyone but root to send us messages.
+ *
+ * We will allow users to send us messages, when
+ * udev is enabled. Udev is just a toy you should
+ * only use for testing.
+ */
+ cred = (struct ucred *)CMSG_DATA(chdr);
+ if (cred->uid != 0 && !showudev)
+ continue;
+
+ if (!memcmp(buf, "libudev", 8)) {
+ /*
+ * Receiving messages from udev is insecure.
+ */
+ if (!showudev)
+ continue;
+ } else {
+ if (!showkernel)
+ continue;
+ /*
+ * Kernel messages shouldn't come from the
+ * userspace.
+ */
+ if (cnls.nl_pid > 0)
+ continue;
+ }
- slen = 0;
for (i = 0; i < len; i += slen + 1) {
key = buf + i;
value = strchr(key, '=');
diff --git a/nldev.c b/nldev.c
index a771931..bbc8eb2 100644
--- a/nldev.c
+++ b/nldev.c
@@ -24,44 +24,22 @@
#include "arg.h"
#include "log.h"
-int listfd = -1;
int dofork = 0;
-struct handler {
- int fd;
- int argc;
- char **argv;
-};
-
-void
-spawn_handler(struct handler *child)
+pid_t
+spawn_handler(int fd, char **argv)
{
- int pipefd[2];
-
- if (pipe(pipefd) == -1)
- edie("pipe");
-
pid_t pid = fork();
if (pid < 0)
edie("fork");
if (pid == 0) {
- close(pipefd[1]);
- dup2(pipefd[0], 0);
- execv(child->argv[0], child->argv);
+ dup2(fd, 0);
+ execv(argv[0], 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);
+ return pid;
}
void
@@ -129,25 +107,13 @@ init_netlink_socket(void)
void
usage(void)
{
- die("usage: %s [-hdb] [-ku] [-- run [...]]\n", argv0);
+ die("usage: %s [-bd] -- runpath [...]\n", argv0);
}
int
main(int argc, char *argv[])
{
- struct sockaddr_nl cnls;
- struct pollfd fds[2];
- struct msghdr hdr;
- struct iovec iov;
- char buf[4097], cbuf[CMSG_SPACE(sizeof(struct ucred))];
- struct cmsghdr *chdr;
- struct ucred *cred;
- int len, showudev, showkernel;
-
- struct handler child;
-
- showkernel = 1;
- showudev = 1;
+ struct pollfd fds;
ARGBEGIN {
case 'b':
@@ -156,27 +122,12 @@ main(int argc, char *argv[])
case 'd':
dodebug = 1;
break;
- case 'k':
- showudev = 0;
- break;
- case 'u':
- showkernel = 0;
- break;
default:
usage();
} ARGEND;
- 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;
+ fds.events = POLLIN;
+ fds.fd = init_netlink_socket();
if (dofork) {
if (daemon(0, 0) < 0)
@@ -186,68 +137,12 @@ main(int argc, char *argv[])
initsignals();
- 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);
- memset(&hdr, 0, sizeof(hdr));
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
- hdr.msg_control = cbuf;
- hdr.msg_controllen = sizeof(cbuf);
- hdr.msg_name = &cnls;
- hdr.msg_namelen = sizeof(cnls);
-
- len = recvmsg(fds[0].fd, &hdr, 0);
- if (len < 0) {
- if (errno == EINTR)
- continue;
- edie("recvmsg");
- }
- if (len < 32 || len >= sizeof(buf))
- continue;
-
- chdr = CMSG_FIRSTHDR(&hdr);
- if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS)
- continue;
-
- /*
- * Don't allow anyone but root to send us messages.
- *
- * We will allow users to send us messages, when
- * udev is enabled. Udev is just a toy you should
- * only use for testing.
- */
- cred = (struct ucred *)CMSG_DATA(chdr);
- if (cred->uid != 0 && !showudev)
- continue;
-
- if (!memcmp(buf, "libudev", 8)) {
- /*
- * Receiving messages from udev is insecure.
- */
- if (!showudev)
- continue;
- } else {
- if (!showkernel)
- continue;
- /*
- * Kernel messages shouldn't come from the
- * userspace.
- */
- if (cnls.nl_pid > 0)
- continue;
+ while (poll(&fds, 1, -1) > -1) {
+ if (fds.revents & POLLIN) {
+ int status;
+ pid_t childpid = spawn_handler(fds.fd, argv);
+ waitpid(childpid, &status, 0);
}
- write_to_handler(&child, buf, len);
- fds[1].fd = child.fd;
}
return 0;