• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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))
48 static int
set_cloexec_or_close(int fd)49 set_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 
65 err:
66    close(fd);
67    return -1;
68 }
69 #endif
70 
71 #if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(ANDROID))
72 static int
create_tmpfile_cloexec(char * tmpname)73 create_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  */
114 int
os_create_anonymous_file(off_t size,const char * debug_name)115 os_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