1*57718be8SEnji Cooper /* $NetBSD: fdpass.c,v 1.1 2012/08/13 11:15:05 christos Exp $ */ 2*57718be8SEnji Cooper /* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 djm Exp $ */ 3*57718be8SEnji Cooper /* 4*57718be8SEnji Cooper * Copyright 2001 Niels Provos <provos@citi.umich.edu> 5*57718be8SEnji Cooper * All rights reserved. 6*57718be8SEnji Cooper * 7*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 8*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 9*57718be8SEnji Cooper * are met: 10*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 11*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 12*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 13*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 14*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 15*57718be8SEnji Cooper * 16*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17*57718be8SEnji Cooper * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18*57718be8SEnji Cooper * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19*57718be8SEnji Cooper * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20*57718be8SEnji Cooper * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21*57718be8SEnji Cooper * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22*57718be8SEnji Cooper * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23*57718be8SEnji Cooper * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24*57718be8SEnji Cooper * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25*57718be8SEnji Cooper * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26*57718be8SEnji Cooper */ 27*57718be8SEnji Cooper 28*57718be8SEnji Cooper #include <sys/cdefs.h> 29*57718be8SEnji Cooper __RCSID("$NetBSD: fdpass.c,v 1.1 2012/08/13 11:15:05 christos Exp $"); 30*57718be8SEnji Cooper #include <sys/types.h> 31*57718be8SEnji Cooper #include <sys/socket.h> 32*57718be8SEnji Cooper #include <sys/uio.h> 33*57718be8SEnji Cooper #include <sys/wait.h> 34*57718be8SEnji Cooper 35*57718be8SEnji Cooper #include <stdio.h> 36*57718be8SEnji Cooper #include <errno.h> 37*57718be8SEnji Cooper #include <err.h> 38*57718be8SEnji Cooper #include <stdlib.h> 39*57718be8SEnji Cooper #include <unistd.h> 40*57718be8SEnji Cooper #include <fcntl.h> 41*57718be8SEnji Cooper #include <poll.h> 42*57718be8SEnji Cooper #include <string.h> 43*57718be8SEnji Cooper 44*57718be8SEnji Cooper static int debug; 45*57718be8SEnji Cooper 46*57718be8SEnji Cooper static int 47*57718be8SEnji Cooper send_fd(int sock, int fd) 48*57718be8SEnji Cooper { 49*57718be8SEnji Cooper struct msghdr msg; 50*57718be8SEnji Cooper union { 51*57718be8SEnji Cooper struct cmsghdr hdr; 52*57718be8SEnji Cooper char buf[1024]; 53*57718be8SEnji Cooper } cmsgbuf; 54*57718be8SEnji Cooper struct cmsghdr *cmsg; 55*57718be8SEnji Cooper struct iovec vec; 56*57718be8SEnji Cooper char ch = '\0'; 57*57718be8SEnji Cooper ssize_t n; 58*57718be8SEnji Cooper struct pollfd pfd; 59*57718be8SEnji Cooper 60*57718be8SEnji Cooper if (sizeof(cmsgbuf.buf) < CMSG_SPACE(sizeof(int))) 61*57718be8SEnji Cooper errx(1, "%s: %zu < %zu, recompile", __func__, 62*57718be8SEnji Cooper sizeof(cmsgbuf.buf), CMSG_SPACE(sizeof(int))); 63*57718be8SEnji Cooper 64*57718be8SEnji Cooper memset(&msg, 0, sizeof(msg)); 65*57718be8SEnji Cooper msg.msg_control = &cmsgbuf.buf; 66*57718be8SEnji Cooper msg.msg_controllen = CMSG_SPACE(sizeof(int)); 67*57718be8SEnji Cooper cmsg = CMSG_FIRSTHDR(&msg); 68*57718be8SEnji Cooper cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 69*57718be8SEnji Cooper cmsg->cmsg_level = SOL_SOCKET; 70*57718be8SEnji Cooper cmsg->cmsg_type = SCM_RIGHTS; 71*57718be8SEnji Cooper *(int *)CMSG_DATA(cmsg) = fd; 72*57718be8SEnji Cooper msg.msg_controllen = cmsg->cmsg_len; 73*57718be8SEnji Cooper 74*57718be8SEnji Cooper vec.iov_base = &ch; 75*57718be8SEnji Cooper vec.iov_len = 1; 76*57718be8SEnji Cooper msg.msg_iov = &vec; 77*57718be8SEnji Cooper msg.msg_iovlen = 1; 78*57718be8SEnji Cooper 79*57718be8SEnji Cooper pfd.fd = sock; 80*57718be8SEnji Cooper pfd.events = POLLOUT; 81*57718be8SEnji Cooper while ((n = sendmsg(sock, &msg, 0)) == -1 && 82*57718be8SEnji Cooper (errno == EAGAIN || errno == EINTR)) { 83*57718be8SEnji Cooper (void)poll(&pfd, 1, -1); 84*57718be8SEnji Cooper } 85*57718be8SEnji Cooper switch (n) { 86*57718be8SEnji Cooper case -1: 87*57718be8SEnji Cooper err(1, "%s: sendmsg(%d)", __func__, fd); 88*57718be8SEnji Cooper case 1: 89*57718be8SEnji Cooper if (debug) 90*57718be8SEnji Cooper fprintf(stderr, "%d: send fd %d\n", getpid(), fd); 91*57718be8SEnji Cooper return 0; 92*57718be8SEnji Cooper default: 93*57718be8SEnji Cooper errx(1, "%s: sendmsg: expected sent 1 got %ld", 94*57718be8SEnji Cooper __func__, (long)n); 95*57718be8SEnji Cooper } 96*57718be8SEnji Cooper } 97*57718be8SEnji Cooper 98*57718be8SEnji Cooper static int 99*57718be8SEnji Cooper recv_fd(int sock) 100*57718be8SEnji Cooper { 101*57718be8SEnji Cooper struct msghdr msg; 102*57718be8SEnji Cooper union { 103*57718be8SEnji Cooper struct cmsghdr hdr; 104*57718be8SEnji Cooper char buf[1024]; 105*57718be8SEnji Cooper } cmsgbuf; 106*57718be8SEnji Cooper struct cmsghdr *cmsg; 107*57718be8SEnji Cooper struct iovec vec; 108*57718be8SEnji Cooper ssize_t n; 109*57718be8SEnji Cooper char ch; 110*57718be8SEnji Cooper int fd; 111*57718be8SEnji Cooper struct pollfd pfd; 112*57718be8SEnji Cooper 113*57718be8SEnji Cooper if (sizeof(cmsgbuf.buf) < CMSG_SPACE(sizeof(int))) 114*57718be8SEnji Cooper errx(1, "%s: %zu < %zu, recompile", __func__, 115*57718be8SEnji Cooper sizeof(cmsgbuf.buf), CMSG_SPACE(sizeof(int))); 116*57718be8SEnji Cooper 117*57718be8SEnji Cooper memset(&msg, 0, sizeof(msg)); 118*57718be8SEnji Cooper vec.iov_base = &ch; 119*57718be8SEnji Cooper vec.iov_len = 1; 120*57718be8SEnji Cooper msg.msg_iov = &vec; 121*57718be8SEnji Cooper msg.msg_iovlen = 1; 122*57718be8SEnji Cooper msg.msg_control = &cmsgbuf.buf; 123*57718be8SEnji Cooper msg.msg_controllen = CMSG_SPACE(sizeof(int)); 124*57718be8SEnji Cooper 125*57718be8SEnji Cooper pfd.fd = sock; 126*57718be8SEnji Cooper pfd.events = POLLIN; 127*57718be8SEnji Cooper while ((n = recvmsg(sock, &msg, 0)) == -1 && 128*57718be8SEnji Cooper (errno == EAGAIN || errno == EINTR)) { 129*57718be8SEnji Cooper (void)poll(&pfd, 1, -1); 130*57718be8SEnji Cooper } 131*57718be8SEnji Cooper switch (n) { 132*57718be8SEnji Cooper case -1: 133*57718be8SEnji Cooper err(1, "%s: recvmsg", __func__); 134*57718be8SEnji Cooper case 1: 135*57718be8SEnji Cooper break; 136*57718be8SEnji Cooper default: 137*57718be8SEnji Cooper errx(1, "%s: recvmsg: expected received 1 got %ld", 138*57718be8SEnji Cooper __func__, (long)n); 139*57718be8SEnji Cooper } 140*57718be8SEnji Cooper 141*57718be8SEnji Cooper cmsg = CMSG_FIRSTHDR(&msg); 142*57718be8SEnji Cooper if (cmsg == NULL) 143*57718be8SEnji Cooper errx(1, "%s: no message header", __func__); 144*57718be8SEnji Cooper 145*57718be8SEnji Cooper if (cmsg->cmsg_type != SCM_RIGHTS) 146*57718be8SEnji Cooper err(1, "%s: expected type %d got %d", __func__, 147*57718be8SEnji Cooper SCM_RIGHTS, cmsg->cmsg_type); 148*57718be8SEnji Cooper fd = (*(int *)CMSG_DATA(cmsg)); 149*57718be8SEnji Cooper if (debug) 150*57718be8SEnji Cooper fprintf(stderr, "%d: recv fd %d\n", getpid(), fd); 151*57718be8SEnji Cooper return fd; 152*57718be8SEnji Cooper } 153*57718be8SEnji Cooper 154*57718be8SEnji Cooper static void usage(void) __attribute__((__noreturn__)); 155*57718be8SEnji Cooper 156*57718be8SEnji Cooper static void 157*57718be8SEnji Cooper usage(void) 158*57718be8SEnji Cooper { 159*57718be8SEnji Cooper fprintf(stderr, "Usage: %s [-vd] -i <input> -o <output>\n" 160*57718be8SEnji Cooper "\t %s [-v] -p <progname>\n", getprogname(), getprogname()); 161*57718be8SEnji Cooper exit(EXIT_FAILURE); 162*57718be8SEnji Cooper } 163*57718be8SEnji Cooper 164*57718be8SEnji Cooper int 165*57718be8SEnji Cooper main(int argc, char *argv[]) 166*57718be8SEnji Cooper { 167*57718be8SEnji Cooper int s[2], fd, status, c, verbose; 168*57718be8SEnji Cooper char buf[1024], *prog; 169*57718be8SEnji Cooper 170*57718be8SEnji Cooper prog = NULL; 171*57718be8SEnji Cooper s[0] = s[1] = -1; 172*57718be8SEnji Cooper verbose = 0; 173*57718be8SEnji Cooper 174*57718be8SEnji Cooper while ((c = getopt(argc, argv, "di:o:p:")) != -1) 175*57718be8SEnji Cooper switch (c) { 176*57718be8SEnji Cooper case 'd': 177*57718be8SEnji Cooper debug++; 178*57718be8SEnji Cooper break; 179*57718be8SEnji Cooper case 'i': 180*57718be8SEnji Cooper s[0] = atoi(optarg); 181*57718be8SEnji Cooper break; 182*57718be8SEnji Cooper case 'o': 183*57718be8SEnji Cooper s[1] = atoi(optarg); 184*57718be8SEnji Cooper break; 185*57718be8SEnji Cooper case 'p': 186*57718be8SEnji Cooper prog = optarg; 187*57718be8SEnji Cooper break; 188*57718be8SEnji Cooper default: 189*57718be8SEnji Cooper usage(); 190*57718be8SEnji Cooper } 191*57718be8SEnji Cooper 192*57718be8SEnji Cooper if ((s[0] == -1 && s[1] != -1) || (s[0] != -1 && s[1] == -1)) 193*57718be8SEnji Cooper usage(); 194*57718be8SEnji Cooper 195*57718be8SEnji Cooper if (s[0] == -1) { 196*57718be8SEnji Cooper if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, s) == -1) 197*57718be8SEnji Cooper err(1, "socketpair"); 198*57718be8SEnji Cooper } else 199*57718be8SEnji Cooper goto recv; 200*57718be8SEnji Cooper 201*57718be8SEnji Cooper switch (fork()) { 202*57718be8SEnji Cooper case -1: 203*57718be8SEnji Cooper err(1, "fork"); 204*57718be8SEnji Cooper default: 205*57718be8SEnji Cooper fd = open("foo", O_RDWR|O_CREAT|O_TRUNC, 0666); 206*57718be8SEnji Cooper if (fd == -1) 207*57718be8SEnji Cooper err(1, "open"); 208*57718be8SEnji Cooper send_fd(s[0], fd); 209*57718be8SEnji Cooper wait(&status); 210*57718be8SEnji Cooper return 0; 211*57718be8SEnji Cooper case 0: 212*57718be8SEnji Cooper if (prog != NULL) { 213*57718be8SEnji Cooper char i[64], o[64]; 214*57718be8SEnji Cooper snprintf(i, sizeof(i), "%d", s[0]); 215*57718be8SEnji Cooper snprintf(o, sizeof(o), "%d", s[1]); 216*57718be8SEnji Cooper execlp(prog, prog, "-i", i, "-o", o, NULL); 217*57718be8SEnji Cooper err(1, "execlp"); 218*57718be8SEnji Cooper } 219*57718be8SEnji Cooper recv: 220*57718be8SEnji Cooper fd = recv_fd(s[1]); 221*57718be8SEnji Cooper if (verbose) { 222*57718be8SEnji Cooper snprintf(buf, sizeof(buf), "ls -l /proc/%d/fd", 223*57718be8SEnji Cooper getpid()); 224*57718be8SEnji Cooper system(buf); 225*57718be8SEnji Cooper } 226*57718be8SEnji Cooper if (write(fd, "foo\n", 4) == -1) 227*57718be8SEnji Cooper err(1, "write"); 228*57718be8SEnji Cooper close(fd); 229*57718be8SEnji Cooper return 0; 230*57718be8SEnji Cooper } 231*57718be8SEnji Cooper } 232