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