Blame uwac/libuwac/uwac-os.c

Packit 1fb8d4
/*
Packit 1fb8d4
 * Copyright © 2012 Collabora, Ltd.
Packit 1fb8d4
 *
Packit 1fb8d4
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 1fb8d4
 * documentation for any purpose is hereby granted without fee, provided that
Packit 1fb8d4
 * the above copyright notice appear in all copies and that both that copyright
Packit 1fb8d4
 * notice and this permission notice appear in supporting documentation, and
Packit 1fb8d4
 * that the name of the copyright holders not be used in advertising or
Packit 1fb8d4
 * publicity pertaining to distribution of the software without specific,
Packit 1fb8d4
 * written prior permission.  The copyright holders make no representations
Packit 1fb8d4
 * about the suitability of this software for any purpose.  It is provided "as
Packit 1fb8d4
 * is" without express or implied warranty.
Packit 1fb8d4
 *
Packit 1fb8d4
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit 1fb8d4
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit 1fb8d4
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit 1fb8d4
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit 1fb8d4
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit 1fb8d4
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
Packit 1fb8d4
 * OF THIS SOFTWARE.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * This file is an adaptation of src/wayland-os.h from the wayland project and
Packit 1fb8d4
 * shared/os-compatiblity.h from the weston project.
Packit 1fb8d4
 *
Packit 1fb8d4
 * Functions have been renamed just to prevent name clashes.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#define _GNU_SOURCE
Packit 1fb8d4
Packit 1fb8d4
#if defined(__FreeBSD__) || defined(__DragonFly__)
Packit 1fb8d4
#define USE_SHM
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <sys/types.h>
Packit 1fb8d4
#include <sys/socket.h>
Packit 1fb8d4
#ifdef USE_SHM
Packit 1fb8d4
#include <sys/mman.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <sys/epoll.h>
Packit 1fb8d4
Packit 1fb8d4
#include "../config.h"
Packit 1fb8d4
#include "uwac-os.h"
Packit 1fb8d4
Packit 1fb8d4
static int set_cloexec_or_close(int fd)
Packit 1fb8d4
{
Packit 1fb8d4
	long flags;
Packit 1fb8d4
Packit 1fb8d4
	if (fd == -1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	flags = fcntl(fd, F_GETFD);
Packit 1fb8d4
Packit 1fb8d4
	if (flags == -1)
Packit 1fb8d4
		goto err;
Packit 1fb8d4
Packit 1fb8d4
	if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
Packit 1fb8d4
		goto err;
Packit 1fb8d4
Packit 1fb8d4
	return fd;
Packit 1fb8d4
err:
Packit 1fb8d4
	close(fd);
Packit 1fb8d4
	return -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int uwac_os_socket_cloexec(int domain, int type, int protocol)
Packit 1fb8d4
{
Packit 1fb8d4
	int fd;
Packit 1fb8d4
	fd = socket(domain, type | SOCK_CLOEXEC, protocol);
Packit 1fb8d4
Packit 1fb8d4
	if (fd >= 0)
Packit 1fb8d4
		return fd;
Packit 1fb8d4
Packit 1fb8d4
	if (errno != EINVAL)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	fd = socket(domain, type, protocol);
Packit 1fb8d4
	return set_cloexec_or_close(fd);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int uwac_os_dupfd_cloexec(int fd, long minfd)
Packit 1fb8d4
{
Packit 1fb8d4
	int newfd;
Packit 1fb8d4
	newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
Packit 1fb8d4
Packit 1fb8d4
	if (newfd >= 0)
Packit 1fb8d4
		return newfd;
Packit 1fb8d4
Packit 1fb8d4
	if (errno != EINVAL)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	newfd = fcntl(fd, F_DUPFD, minfd);
Packit 1fb8d4
	return set_cloexec_or_close(newfd);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr* msg, int flags)
Packit 1fb8d4
{
Packit 1fb8d4
	ssize_t len;
Packit 1fb8d4
	struct cmsghdr* cmsg;
Packit 1fb8d4
	unsigned char* data;
Packit 1fb8d4
	int* fd;
Packit 1fb8d4
	int* end;
Packit 1fb8d4
	len = recvmsg(sockfd, msg, flags);
Packit 1fb8d4
Packit 1fb8d4
	if (len == -1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!msg->msg_control || msg->msg_controllen == 0)
Packit 1fb8d4
		return len;
Packit 1fb8d4
Packit 1fb8d4
	cmsg = CMSG_FIRSTHDR(msg);
Packit 1fb8d4
Packit 1fb8d4
	for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (cmsg->cmsg_level != SOL_SOCKET ||
Packit 1fb8d4
		    cmsg->cmsg_type != SCM_RIGHTS)
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		data = CMSG_DATA(cmsg);
Packit 1fb8d4
		end = (int*)(data + cmsg->cmsg_len - CMSG_LEN(0));
Packit 1fb8d4
Packit 1fb8d4
		for (fd = (int*)data; fd < end; ++fd)
Packit 1fb8d4
			*fd = set_cloexec_or_close(*fd);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return len;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr* msg, int flags)
Packit 1fb8d4
{
Packit 1fb8d4
	ssize_t len;
Packit 1fb8d4
	len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
Packit 1fb8d4
Packit 1fb8d4
	if (len >= 0)
Packit 1fb8d4
		return len;
Packit 1fb8d4
Packit 1fb8d4
	if (errno != EINVAL)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return recvmsg_cloexec_fallback(sockfd, msg, flags);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int uwac_os_epoll_create_cloexec(void)
Packit 1fb8d4
{
Packit 1fb8d4
	int fd;
Packit 1fb8d4
#ifdef EPOLL_CLOEXEC
Packit 1fb8d4
	fd = epoll_create1(EPOLL_CLOEXEC);
Packit 1fb8d4
Packit 1fb8d4
	if (fd >= 0)
Packit 1fb8d4
		return fd;
Packit 1fb8d4
Packit 1fb8d4
	if (errno != EINVAL)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	fd = epoll_create(1);
Packit 1fb8d4
	return set_cloexec_or_close(fd);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int create_tmpfile_cloexec(char* tmpname)
Packit 1fb8d4
{
Packit 1fb8d4
	int fd;
Packit 1fb8d4
#ifdef USE_SHM
Packit 1fb8d4
	fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
Packit 1fb8d4
#elif defined(HAVE_MKOSTEMP)
Packit 1fb8d4
	fd = mkostemp(tmpname, O_CLOEXEC);
Packit 1fb8d4
Packit 1fb8d4
	if (fd >= 0)
Packit 1fb8d4
		unlink(tmpname);
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
	fd = mkstemp(tmpname);
Packit 1fb8d4
Packit 1fb8d4
	if (fd >= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		fd = set_cloexec_or_close(fd);
Packit 1fb8d4
		unlink(tmpname);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return fd;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Create a new, unique, anonymous file of the given size, and
Packit 1fb8d4
 * return the file descriptor for it. The file descriptor is set
Packit 1fb8d4
 * CLOEXEC. The file is immediately suitable for mmap()'ing
Packit 1fb8d4
 * the given size at offset zero.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The file should not have a permanent backing store like a disk,
Packit 1fb8d4
 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The file name is deleted from the file system.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The file is suitable for buffer sharing between processes by
Packit 1fb8d4
 * transmitting the file descriptor over Unix sockets using the
Packit 1fb8d4
 * SCM_RIGHTS methods.
Packit 1fb8d4
 *
Packit 1fb8d4
 * If the C library implements posix_fallocate(), it is used to
Packit 1fb8d4
 * guarantee that disk space is available for the file at the
Packit 1fb8d4
 * given size. If disk space is insufficient, errno is set to ENOSPC.
Packit 1fb8d4
 * If posix_fallocate() is not supported, program may receive
Packit 1fb8d4
 * SIGBUS on accessing mmap()'ed file contents instead.
Packit 1fb8d4
 */
Packit 1fb8d4
int uwac_create_anonymous_file(off_t size)
Packit 1fb8d4
{
Packit 1fb8d4
	static const char template[] = "/weston-shared-XXXXXX";
Packit 1fb8d4
	const char* path;
Packit 1fb8d4
	char* name;
Packit 1fb8d4
	int fd;
Packit 1fb8d4
	int ret;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	path = getenv("XDG_RUNTIME_DIR");
Packit 1fb8d4
Packit 1fb8d4
	if (!path)
Packit 1fb8d4
	{
Packit 1fb8d4
		errno = ENOENT;
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = strlen(path) + sizeof(template);
Packit 1fb8d4
	name = malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!name)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	snprintf(name, length, "%s%s", path, template);
Packit 1fb8d4
	fd = create_tmpfile_cloexec(name);
Packit 1fb8d4
	free(name);
Packit 1fb8d4
Packit 1fb8d4
	if (fd < 0)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_POSIX_FALLOCATE
Packit 1fb8d4
	ret = posix_fallocate(fd, 0, size);
Packit 1fb8d4
Packit 1fb8d4
	if (ret != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		close(fd);
Packit 1fb8d4
		errno = ret;
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
	ret = ftruncate(fd, size);
Packit 1fb8d4
Packit 1fb8d4
	if (ret < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		close(fd);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return fd;
Packit 1fb8d4
}