#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/wait.h>
#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;
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎