1 /*	$OpenBSD: kqueue-fdpass.c,v 1.2 2015/08/13 10:14:41 uebayasi Exp $	*/
2 /*
3  *	Written by Philip Guenther <guenther@openbsd.org> 2011 Public Domain
4  */
5 
6 #include <sys/types.h>
7 #include <sys/event.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <sys/wait.h>
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <err.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <signal.h>
19 
20 #define ASS(cond, mess) do { if (!(cond)) { mess; return 1; } } while (0)
21 
22 #define ASSX(cond) ASS(cond, warnx("assertion " #cond " failed on line %d", __LINE__))
23 
24 
25 int do_fdpass(void);
26 
27 int
28 do_fdpass(void)
29 {
30 	struct msghdr msg;
31 	union {
32 		struct cmsghdr hdr;
33 		char buf[CMSG_SPACE(sizeof(int))];
34 	} cmsgbuf;
35 	struct kevent ke;
36 	struct cmsghdr *cmp;
37 	pid_t pid;
38 	int pfd[2], fd, status;
39 
40 	ASS(socketpair(PF_LOCAL, SOCK_STREAM, 0, pfd) == 0,
41 	    warn("socketpair"));
42 
43 	pid = fork();
44 	if (pid == -1)
45 		err(1, "fork");
46 	if (pid == 0) {
47 		close(pfd[0]);
48 
49 		/* a kqueue with event to pass */
50 		fd = kqueue();
51 		EV_SET(&ke, SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE,
52 		    0, 0, NULL);
53 		if (kevent(fd, &ke, 1, NULL, 0, NULL) != 0)
54 			err(1, "can't register events on kqueue");
55 
56 		memset(&cmsgbuf.buf, 0, sizeof cmsgbuf.buf);
57 		memset(&msg, 0, sizeof msg);
58 		msg.msg_control = &cmsgbuf.buf;
59 		msg.msg_controllen = sizeof(cmsgbuf);
60 
61 		cmp = CMSG_FIRSTHDR(&msg);
62 		cmp->cmsg_len = CMSG_LEN(sizeof(int));
63 		cmp->cmsg_level = SOL_SOCKET;
64 		cmp->cmsg_type = SCM_RIGHTS;
65 
66 		*(int *)CMSG_DATA(cmp) = fd;
67 
68 		if (sendmsg(pfd[1], &msg, 0) == 0)
69 			errx(1, "sendmsg succeeded when it shouldn't");
70 		if (errno != EINVAL)
71 			err(1, "child sendmsg");
72 		printf("sendmsg failed with EINVAL as expected\n");
73 		close(pfd[1]);
74 		exit(0);
75 	}
76 
77 	close(pfd[1]);
78 	wait(&status);
79 	close(pfd[0]);
80 
81 	return (0);
82 }
83 
84