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