1#include <assert.h>
2#include <string.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <errno.h>
6#include <fcntl.h>
7#include <sys/socket.h>
8#include <sys/wait.h>
9
10int main(int ac, const char **av)
11{
12	int i;
13	int data = 0;
14	struct iovec iov = {
15		.iov_base = &data,
16		.iov_len = sizeof(iov)
17	};
18
19	while ((i = open("/dev/null", O_RDWR)) < 3)
20		assert(i >= 0);
21	(void) close(3);
22
23	int sv[2];
24	assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
25	int one = 1;
26	assert(setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) == 0);
27
28	pid_t pid = fork();
29	assert(pid >= 0);
30
31	if (pid) {
32		assert(close(sv[0]) == 0);
33		assert(dup2(sv[1], 1) == 1);
34		assert(close(sv[1]) == 0);
35
36		int fds[ac];
37		assert((fds[0] = open("/dev/null", O_RDWR)) == 3);
38		for (i = 1; i < ac; ++i)
39			assert((fds[i] = open(av[i], O_RDONLY)) == i + 3);
40
41		union {
42			struct cmsghdr cmsg;
43			char buf[CMSG_LEN(sizeof(fds))];
44		} control;
45
46		control.cmsg.cmsg_level = SOL_SOCKET;
47		control.cmsg.cmsg_type = SCM_RIGHTS;
48		control.cmsg.cmsg_len = CMSG_LEN(sizeof(fds));
49		memcpy(CMSG_DATA(&control.cmsg), fds, sizeof(fds));
50
51		struct msghdr mh = {
52			.msg_iov = &iov,
53			.msg_iovlen = 1,
54			.msg_control = &control,
55			.msg_controllen = sizeof(control)
56		};
57
58		assert(sendmsg(1, &mh, 0) == sizeof(iov));
59		assert(close(1) == 0);
60
61                int status;
62		assert(waitpid(pid, &status, 0) == pid);
63		assert(status == 0);
64	} else {
65		assert(close(sv[1]) == 0);
66		assert(dup2(sv[0], 0) == 0);
67		assert(close(sv[0]) == 0);
68
69		struct cmsghdr control[4 + ac * sizeof(int) / sizeof(struct cmsghdr)];
70
71		struct msghdr mh = {
72			.msg_iov = &iov,
73			.msg_iovlen = 1,
74			.msg_control = control,
75			.msg_controllen = sizeof(control)
76		};
77
78		assert(recvmsg(0, &mh, 0) == sizeof(iov));
79		assert(close(0) == 0);
80	}
81
82	return 0;
83}
84