Home | History | Annotate | Line # | Download | only in fdpass
      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