#define _GNU_SOURCE #include #include #include #include #include #include #include #include #define pexit(msg) do { perror(msg); exit(1); } while (0) static int sendfd(int sockfd, int fd) { struct msghdr msg = { 0 }; struct cmsghdr *cmsg; int err; char iobuf; struct iovec io = { .iov_base = &iobuf, .iov_len = sizeof(iobuf), }; union { char buf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr align; } u; msg.msg_iov = &io; msg.msg_iovlen = 1; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); /* Send the file descriptor with an empty message * containing only the ancillary data. */ msg.msg_iov = NULL; msg.msg_iovlen = 0; memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); err = sendmsg(sockfd, &msg, 0); if (err < 0) pexit("sendmsg"); if (err != msg.msg_iovlen) pexit("sendmsg"); return 0; } static int recvfd(int sockfd) { struct msghdr msg = { 0 }; struct cmsghdr *cmsg; int err; int fd; union { char buf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr align; } u; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); err = recvmsg(sockfd, &msg, 0); if (err < 0) pexit("recvmsg"); cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg || cmsg->cmsg_len != CMSG_LEN(sizeof(fd)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) pexit("Invalid cmsg"); memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); return fd; } int main(void) { int scm_fds[2], r; r = socketpair(AF_UNIX, SOCK_STREAM, 0, scm_fds); if (r < 0) pexit("socketpair"); if (fork()) { int fd = open("/", O_PATH | O_DIRECTORY); if (fd < 0) pexit("open"); r = sendfd(scm_fds[0], fd); if (r < 0) pexit("sendfd"); puts("sent fd"); } else { int fd = recvfd(scm_fds[1]); if (fd < 0) pexit("recvfd"); puts("received fd"); exit(0); } wait(NULL); puts("done"); return 0; }