17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2012 Collabora, Ltd.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining
57ec681f3Smrg * a copy of this software and associated documentation files (the
67ec681f3Smrg * "Software"), to deal in the Software without restriction, including
77ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
87ec681f3Smrg * distribute, sublicense, and/or sell copies of the Software, and to
97ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
107ec681f3Smrg * the following conditions:
117ec681f3Smrg *
127ec681f3Smrg * The above copyright notice and this permission notice (including the
137ec681f3Smrg * next paragraph) shall be included in all copies or substantial
147ec681f3Smrg * portions of the Software.
157ec681f3Smrg *
167ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
177ec681f3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
187ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
197ec681f3Smrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
207ec681f3Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
217ec681f3Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
227ec681f3Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
237ec681f3Smrg * SOFTWARE.
247ec681f3Smrg */
257ec681f3Smrg
267ec681f3Smrg/*
277ec681f3Smrg * Based on weston shared/os-compatibility.c
287ec681f3Smrg */
297ec681f3Smrg
307ec681f3Smrg#ifndef _WIN32
317ec681f3Smrg#include "anon_file.h"
327ec681f3Smrg
337ec681f3Smrg#include <unistd.h>
347ec681f3Smrg#include <fcntl.h>
357ec681f3Smrg#include <errno.h>
367ec681f3Smrg#include <stdlib.h>
377ec681f3Smrg
387ec681f3Smrg#if defined(HAVE_MEMFD_CREATE) || defined(__FreeBSD__) || defined(__OpenBSD__)
397ec681f3Smrg#include <sys/mman.h>
407ec681f3Smrg#elif defined(ANDROID)
417ec681f3Smrg#include <sys/syscall.h>
427ec681f3Smrg#include <linux/memfd.h>
437ec681f3Smrg#else
447ec681f3Smrg#include <stdio.h>
457ec681f3Smrg#endif
467ec681f3Smrg
477ec681f3Smrg#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP) || defined(ANDROID))
487ec681f3Smrgstatic int
497ec681f3Smrgset_cloexec_or_close(int fd)
507ec681f3Smrg{
517ec681f3Smrg   long flags;
527ec681f3Smrg
537ec681f3Smrg   if (fd == -1)
547ec681f3Smrg      return -1;
557ec681f3Smrg
567ec681f3Smrg   flags = fcntl(fd, F_GETFD);
577ec681f3Smrg   if (flags == -1)
587ec681f3Smrg      goto err;
597ec681f3Smrg
607ec681f3Smrg   if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
617ec681f3Smrg      goto err;
627ec681f3Smrg
637ec681f3Smrg   return fd;
647ec681f3Smrg
657ec681f3Smrgerr:
667ec681f3Smrg   close(fd);
677ec681f3Smrg   return -1;
687ec681f3Smrg}
697ec681f3Smrg#endif
707ec681f3Smrg
717ec681f3Smrg#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(ANDROID))
727ec681f3Smrgstatic int
737ec681f3Smrgcreate_tmpfile_cloexec(char *tmpname)
747ec681f3Smrg{
757ec681f3Smrg   int fd;
767ec681f3Smrg
777ec681f3Smrg#ifdef HAVE_MKOSTEMP
787ec681f3Smrg   fd = mkostemp(tmpname, O_CLOEXEC);
797ec681f3Smrg#else
807ec681f3Smrg   fd = mkstemp(tmpname);
817ec681f3Smrg#endif
827ec681f3Smrg
837ec681f3Smrg   if (fd < 0) {
847ec681f3Smrg      return fd;
857ec681f3Smrg   }
867ec681f3Smrg
877ec681f3Smrg#ifndef HAVE_MKOSTEMP
887ec681f3Smrg   fd = set_cloexec_or_close(fd);
897ec681f3Smrg#endif
907ec681f3Smrg
917ec681f3Smrg   unlink(tmpname);
927ec681f3Smrg   return fd;
937ec681f3Smrg}
947ec681f3Smrg#endif
957ec681f3Smrg
967ec681f3Smrg/*
977ec681f3Smrg * Create a new, unique, anonymous file of the given size, and
987ec681f3Smrg * return the file descriptor for it. The file descriptor is set
997ec681f3Smrg * CLOEXEC. The file is immediately suitable for mmap()'ing
1007ec681f3Smrg * the given size at offset zero.
1017ec681f3Smrg *
1027ec681f3Smrg * An optional name for debugging can be provided as the second argument.
1037ec681f3Smrg *
1047ec681f3Smrg * The file should not have a permanent backing store like a disk,
1057ec681f3Smrg * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
1067ec681f3Smrg *
1077ec681f3Smrg * If memfd or SHM_ANON is supported, the filesystem is not touched at all.
1087ec681f3Smrg * Otherwise, the file name is deleted from the file system.
1097ec681f3Smrg *
1107ec681f3Smrg * The file is suitable for buffer sharing between processes by
1117ec681f3Smrg * transmitting the file descriptor over Unix sockets using the
1127ec681f3Smrg * SCM_RIGHTS methods.
1137ec681f3Smrg */
1147ec681f3Smrgint
1157ec681f3Smrgos_create_anonymous_file(off_t size, const char *debug_name)
1167ec681f3Smrg{
1177ec681f3Smrg   int fd, ret;
1187ec681f3Smrg#if defined(HAVE_MEMFD_CREATE)
1197ec681f3Smrg   if (!debug_name)
1207ec681f3Smrg      debug_name = "mesa-shared";
1217ec681f3Smrg   fd = memfd_create(debug_name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
1227ec681f3Smrg#elif defined(ANDROID)
1237ec681f3Smrg   if (!debug_name)
1247ec681f3Smrg      debug_name = "mesa-shared";
1257ec681f3Smrg   fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
1267ec681f3Smrg#elif defined(__FreeBSD__)
1277ec681f3Smrg   fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600);
1287ec681f3Smrg#elif defined(__OpenBSD__)
1297ec681f3Smrg   char template[] = "/tmp/mesa-XXXXXXXXXX";
1307ec681f3Smrg   fd = shm_mkstemp(template);
1317ec681f3Smrg   if (fd != -1)
1327ec681f3Smrg      shm_unlink(template);
1337ec681f3Smrg#else
1347ec681f3Smrg   const char *path;
1357ec681f3Smrg   char *name;
1367ec681f3Smrg
1377ec681f3Smrg   path = getenv("XDG_RUNTIME_DIR");
1387ec681f3Smrg   if (!path) {
1397ec681f3Smrg      errno = ENOENT;
1407ec681f3Smrg      return -1;
1417ec681f3Smrg   }
1427ec681f3Smrg
1437ec681f3Smrg   if (debug_name)
1447ec681f3Smrg      asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name);
1457ec681f3Smrg   else
1467ec681f3Smrg      asprintf(&name, "%s/mesa-shared-XXXXXX", path);
1477ec681f3Smrg   if (!name)
1487ec681f3Smrg      return -1;
1497ec681f3Smrg
1507ec681f3Smrg   fd = create_tmpfile_cloexec(name);
1517ec681f3Smrg
1527ec681f3Smrg   free(name);
1537ec681f3Smrg#endif
1547ec681f3Smrg
1557ec681f3Smrg   if (fd < 0)
1567ec681f3Smrg      return -1;
1577ec681f3Smrg
1587ec681f3Smrg   ret = ftruncate(fd, size);
1597ec681f3Smrg   if (ret < 0) {
1607ec681f3Smrg      close(fd);
1617ec681f3Smrg      return -1;
1627ec681f3Smrg   }
1637ec681f3Smrg
1647ec681f3Smrg   return fd;
1657ec681f3Smrg}
1667ec681f3Smrg#endif
167