#include #include #include #include #include #include extern const char *__progname; #include "nf.h" #include "scm-rights.h" #include "forker.h" void forker_main(int cfd, int dfd) { void (*fn)(int, int); unsigned char msg[sizeof(void (*)(int, int))]; unsigned char ctlbuf[CMSPACE(2*sizeof(int))]; struct msghdr mh; struct cmsghdr cmh; struct iovec iov; int fds[2]; int rv; struct pollfd pfd[2]; pid_t kid; signal(SIGCHLD,SIG_IGN); setproctitle("forker"); while (1) { pfd[0].fd = cfd; pfd[0].events = POLLIN | POLLRDNORM; pfd[1].fd = dfd; pfd[1].events = POLLIN | POLLRDNORM; rv = poll(&pfd[0],2,INFTIM); if (rv < 0) exit(0); if (pfd[1].revents & (POLLIN|POLLRDNORM|POLLHUP)) { fprintf(stderr,"%s: forker: parent death pipe readable\n",__progname); exit(0); } if (pfd[0].revents & POLLHUP) { fprintf(stderr,"%s: forker control pipe hangup\n",__progname); exit(0); } if (! (pfd[0].revents & (POLLIN|POLLRDNORM))) { fprintf(stderr,"%s: forker weird poll\n",__progname); exit(0); } iov.iov_base = &msg[0]; iov.iov_len = sizeof(msg); mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = &ctlbuf[0]; mh.msg_controllen = sizeof(ctlbuf); mh.msg_flags = 0; rv = recvmsg(cfd,&mh,0); if (rv < 0) { fprintf(stderr,"%s: forker recvmsg: %s\n",__progname,strerror(errno)); exit(1); } if (rv != sizeof(void (*)(int, int))) { fprintf(stderr,"%s: forker msg size (%d) wrong (not %d)\n",__progname,rv,(int)sizeof(void (*)(int, int))); exit(1); } if (mh.msg_controllen < sizeof(struct cmsghdr)) { fprintf(stderr,"%s: forker msg controllen (%d) too small (< %d)\n",__progname,(int)mh.msg_controllen,(int)sizeof(struct cmsghdr)); exit(1); } bcopy(&ctlbuf[0],&cmh,sizeof(struct cmsghdr)); if (cmh.cmsg_level != SOL_SOCKET) { fprintf(stderr,"%s: forker msg level (%d) wrong (not %d)\n",__progname,(int)cmh.cmsg_level,(int)SOL_SOCKET); exit(1); } if (cmh.cmsg_type != SCM_RIGHTS) { fprintf(stderr,"%s: forker msg type (%d) wrong (not %d)\n",__progname,(int)cmh.cmsg_type,(int)SCM_RIGHTS); exit(1); } if (cmh.cmsg_len < CMLEN(2*sizeof(int))) { fprintf(stderr,"%s: forker cmsg len (%d) too small (< %d)\n",__progname,(int)cmh.cmsg_len,(int)CMLEN(2*sizeof(int))); exit(1); } bcopy(&ctlbuf[CMSKIP(&cmh)],&fds[0],2*sizeof(int)); kid = nf_fork(); if (! kid) break; close(fds[0]); close(fds[1]); } close(cfd); close(dfd); bcopy(&msg[0],&fn,sizeof(void (*)(int, int))); (*fn)(fds[0],fds[1]); _exit(0); }