xref: /dragonfly/test/socket/recvmsg/cloexec/recvmsg_cloexec.c (revision d4e572342e3910606a080c783e3d82dd07545163)
1 #include <sys/types.h>
2 #include <sys/wait.h>
3 #include <sys/socket.h>
4 #include <sys/uio.h>
5 #include <unistd.h>
6 #include <err.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 /* workaround leaky case */
13 #ifndef MSG_CMSG_CLOEXEC
14 #define MSG_CMSG_CLOEXEC 0
15 #endif
16 
17 #define CHECKFD_CMD "checkfd"
18 #define CHECKFD_PATH          "/usr/local/bin/" CHECKFD_CMD
19 
20 int sendfd(int s, int fd);
21 int recvfd(int s);
22 
main(void)23 int main(void)
24 {
25           pid_t pid;
26           int s[2], status, ecode;
27 
28           socketpair(AF_UNIX, SOCK_STREAM, 0, s);
29 
30           pid = fork();
31           if (pid < 0) {
32                     err(1, "fork failed");
33           } else if (pid == 0) {
34                     close(0);
35                     close(1);
36                     /* close(2); */
37 
38                     int mysecretfd = recvfd(s[0]);
39 
40                     write(mysecretfd, "hello secret\n", 14);
41 
42                     char fd[8];
43                     snprintf(fd, sizeof(fd), "%d", mysecretfd);
44                     if (execl(CHECKFD_PATH, CHECKFD_CMD, fd, NULL) < 0)
45                               err(3, "execl failed");
46           } else {
47                     sendfd(s[1], 1);
48           }
49 
50           if (waitpid(pid, &status, 0) < 0)
51                     err(1, "waitpid failed");
52 
53           if (!WIFEXITED(status))
54                     errx(1, CHECKFD_CMD " did not exit");
55 
56           ecode = WEXITSTATUS(status);
57           if (ecode != 0) {
58                     warnx("exit code %d", ecode);
59                     abort();
60           }
61 
62           fprintf(stderr, "passed\n");
63           exit(0);
64 
65 }
66 
67 int
sendfd(int s,int fd)68 sendfd(int s, int fd)
69 {
70           char buf[1];
71           struct iovec iov;
72           struct msghdr msg;
73           struct cmsghdr *cmsg;
74           int n;
75           char cms[CMSG_SPACE(sizeof(int))];
76 
77           buf[0] = 0;
78           iov.iov_base = buf;
79           iov.iov_len = 1;
80 
81           memset(&msg, 0, sizeof msg);
82           msg.msg_iov = &iov;
83           msg.msg_iovlen = 1;
84           msg.msg_control = (caddr_t)cms;
85           msg.msg_controllen = CMSG_LEN(sizeof(int));
86 
87           cmsg = CMSG_FIRSTHDR(&msg);
88           cmsg->cmsg_len = CMSG_LEN(sizeof(int));
89           cmsg->cmsg_level = SOL_SOCKET;
90           cmsg->cmsg_type = SCM_RIGHTS;
91           memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
92 
93           if ((n=sendmsg(s, &msg, 0)) != (int)iov.iov_len)
94                     return -1;
95           return 0;
96 }
97 
98 int
recvfd(int s)99 recvfd(int s)
100 {
101           int n;
102           int fd;
103           char buf[1];
104           struct iovec iov;
105           struct msghdr msg;
106           struct cmsghdr *cmsg;
107           char cms[CMSG_SPACE(sizeof(int))];
108 
109           iov.iov_base = buf;
110           iov.iov_len = 1;
111 
112           memset(&msg, 0, sizeof msg);
113           msg.msg_name = 0;
114           msg.msg_namelen = 0;
115           msg.msg_iov = &iov;
116           msg.msg_iovlen = 1;
117 
118           msg.msg_control = (caddr_t)cms;
119           msg.msg_controllen = sizeof cms;
120 
121           if ((n=recvmsg(s, &msg, MSG_CMSG_CLOEXEC)) < 0)
122                     return -1;
123           if (n == 0){
124                     return -1;
125           }
126           cmsg = CMSG_FIRSTHDR(&msg);
127           memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
128           return fd;
129 }
130