/*
 * send secretmem fd via SCM_RIGHTS
 */

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/un.h>
#include <unistd.h>

#ifndef __NR_memfd_secret
# if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) \
  || defined(__s390__) || defined(__s390x__) || defined(__riscv)
#  define __NR_memfd_secret 447
# else
#  define __NR_memfd_secret -1
# endif
#endif

static int send_fd(int sock, int fd)
{
	char buf = 0;
	struct iovec iov = { .iov_base = &buf, .iov_len = 1 };
	union {
		char buf[CMSG_SPACE(sizeof(int))];
		struct cmsghdr align;
	} u;
	memset(&u, 0, sizeof(u));
	struct msghdr msg = {
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = u.buf,
		.msg_controllen = sizeof(u.buf),
	};
	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
	memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
	return sendmsg(sock, &msg, 0) < 0 ? -1 : 0;
}

int main(void)
{
	if (__NR_memfd_secret < 0) {
		/* Syscall number unknown on this arch */
		return 0;
	}

	int sv[2];
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0)
		return errno;

	/* Try memfd_secret which may return ENOSYS on older kernels. */
	int sfd = (int)syscall(__NR_memfd_secret, 0);
	if (sfd < 0) {
		return errno == ENOSYS ? EXIT_SUCCESS : errno;
	}

	send_fd(sv[0], sfd);

	close(sfd);
	close(sv[0]);
	close(sv[1]);

	return 0;
}
