#include #include #include #include #include #include #include #include #include void run_mandoc(int sockfd) { char sockfdstr[10]; if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) err(EXIT_FAILURE, "snprintf"); if (execlp("mandoc", "mandoc", "-Thtml", "-u", sockfdstr, NULL) == -1) err(EXIT_FAILURE, "execlp(mandoc)"); } ssize_t sock_fd_write(int fd, int fd0, int fd1, int fd2) { struct msghdr msg; struct iovec iov; union { struct cmsghdr cmsghdr; char control[CMSG_SPACE(3 * sizeof(int))]; } cmsgu; struct cmsghdr *cmsg; unsigned char dummy[1] = {'\0'}; iov.iov_base = dummy; iov.iov_len = sizeof(dummy); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgu.control; msg.msg_controllen = sizeof(cmsgu.control); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; int *walk = (int *)CMSG_DATA(cmsg); *(walk++) = fd0; *(walk++) = fd1; *(walk++) = fd2; return sendmsg(fd, &msg, 0); } int process_manpage(struct sockaddr *addr) { int fd; if ((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) return -1; if (connect(fd, addr, sizeof(struct sockaddr_un)) < 0) return -1; int pstdin[2]; int pstdout[2]; int pstderr[2]; if (pipe(pstdin) == -1 || pipe(pstdout) == -1 || pipe(pstderr) == -1) return -1; if (sock_fd_write(fd, pstdin[0], pstdout[1], pstderr[1]) < 0) return -1; close(pstdin[0]); close(pstdout[1]); close(pstderr[1]); const char *man = ".TH example code\n"; if (write(pstdin[1], man, strlen(man)) < 0) return -1; close(pstdin[1]); char buf[4096]; ssize_t n = read(pstdout[0], buf, sizeof(buf)); if (n < 0) return -1; printf("read: \"%.*s\"\n", (int)n, buf); return 0; } int setup_socket(struct sockaddr *addr) { int sockfd; if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) return -1; if (bind(sockfd, addr, sizeof(struct sockaddr_un)) < 0) return -1; if (listen(sockfd, 1) < 0) return -1; return sockfd; } int main(int argc, char **argv) { struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_LOCAL; int sockfd = setup_socket((struct sockaddr *)&addr); if (sockfd == -1) err(EXIT_FAILURE, "socket setup"); pid_t pid = fork(); switch (pid) { case -1: err(EXIT_FAILURE, "fork"); case 0: run_mandoc(sockfd); break; default: if (process_manpage((struct sockaddr *)&addr) == -1) err(EXIT_FAILURE, "process_manpage"); if (kill(pid, SIGKILL) == -1) err(EXIT_FAILURE, "kill(%d)", pid); break; } }