1/* 2 * Copyright © 2012 Collabora, Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial 14 * portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25 26/* 27 * Based on weston shared/os-compatibility.c 28 */ 29 30#ifndef _WIN32 31#include "anon_file.h" 32 33#include <unistd.h> 34#include <fcntl.h> 35#include <errno.h> 36#include <stdlib.h> 37 38#if defined(HAVE_MEMFD_CREATE) || defined(__FreeBSD__) || defined(__OpenBSD__) 39#include <sys/mman.h> 40#elif defined(ANDROID) 41#include <sys/syscall.h> 42#include <linux/memfd.h> 43#else 44#include <stdio.h> 45#endif 46 47#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP) || defined(ANDROID)) 48static int 49set_cloexec_or_close(int fd) 50{ 51 long flags; 52 53 if (fd == -1) 54 return -1; 55 56 flags = fcntl(fd, F_GETFD); 57 if (flags == -1) 58 goto err; 59 60 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 61 goto err; 62 63 return fd; 64 65err: 66 close(fd); 67 return -1; 68} 69#endif 70 71#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(ANDROID)) 72static int 73create_tmpfile_cloexec(char *tmpname) 74{ 75 int fd; 76 77#ifdef HAVE_MKOSTEMP 78 fd = mkostemp(tmpname, O_CLOEXEC); 79#else 80 fd = mkstemp(tmpname); 81#endif 82 83 if (fd < 0) { 84 return fd; 85 } 86 87#ifndef HAVE_MKOSTEMP 88 fd = set_cloexec_or_close(fd); 89#endif 90 91 unlink(tmpname); 92 return fd; 93} 94#endif 95 96/* 97 * Create a new, unique, anonymous file of the given size, and 98 * return the file descriptor for it. The file descriptor is set 99 * CLOEXEC. The file is immediately suitable for mmap()'ing 100 * the given size at offset zero. 101 * 102 * An optional name for debugging can be provided as the second argument. 103 * 104 * The file should not have a permanent backing store like a disk, 105 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. 106 * 107 * If memfd or SHM_ANON is supported, the filesystem is not touched at all. 108 * Otherwise, the file name is deleted from the file system. 109 * 110 * The file is suitable for buffer sharing between processes by 111 * transmitting the file descriptor over Unix sockets using the 112 * SCM_RIGHTS methods. 113 */ 114int 115os_create_anonymous_file(off_t size, const char *debug_name) 116{ 117 int fd, ret; 118#if defined(HAVE_MEMFD_CREATE) 119 if (!debug_name) 120 debug_name = "mesa-shared"; 121 fd = memfd_create(debug_name, MFD_CLOEXEC | MFD_ALLOW_SEALING); 122#elif defined(ANDROID) 123 if (!debug_name) 124 debug_name = "mesa-shared"; 125 fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC | MFD_ALLOW_SEALING); 126#elif defined(__FreeBSD__) 127 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600); 128#elif defined(__OpenBSD__) 129 char template[] = "/tmp/mesa-XXXXXXXXXX"; 130 fd = shm_mkstemp(template); 131 if (fd != -1) 132 shm_unlink(template); 133#else 134 const char *path; 135 char *name; 136 137 path = getenv("XDG_RUNTIME_DIR"); 138 if (!path) { 139 errno = ENOENT; 140 return -1; 141 } 142 143 if (debug_name) 144 asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name); 145 else 146 asprintf(&name, "%s/mesa-shared-XXXXXX", path); 147 if (!name) 148 return -1; 149 150 fd = create_tmpfile_cloexec(name); 151 152 free(name); 153#endif 154 155 if (fd < 0) 156 return -1; 157 158 ret = ftruncate(fd, size); 159 if (ret < 0) { 160 close(fd); 161 return -1; 162 } 163 164 return fd; 165} 166#endif 167