90c55cd5af0c8a7347ffbddeaa718ae8a96f4738
[mesa.git] / src / util / anon_file.c
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 <stdio.h>
37 #include <stdlib.h>
38
39 #ifdef __FreeBSD__
40 #include <sys/mman.h>
41 #elif defined(HAVE_MEMFD_CREATE)
42 #include <sys/syscall.h>
43 #include <linux/memfd.h>
44 #else
45 #include <stdio.h>
46 #include <stdlib.h>
47 #endif
48
49 #if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP))
50 static int
51 set_cloexec_or_close(int fd)
52 {
53 long flags;
54
55 if (fd == -1)
56 return -1;
57
58 flags = fcntl(fd, F_GETFD);
59 if (flags == -1)
60 goto err;
61
62 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
63 goto err;
64
65 return fd;
66
67 err:
68 close(fd);
69 return -1;
70 }
71 #endif
72
73 #if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE))
74 static int
75 create_tmpfile_cloexec(char *tmpname)
76 {
77 int fd;
78
79 #ifdef HAVE_MKOSTEMP
80 fd = mkostemp(tmpname, O_CLOEXEC);
81 #else
82 fd = mkstemp(tmpname);
83 #endif
84
85 if (fd < 0) {
86 return fd;
87 }
88
89 #ifndef HAVE_MKOSTEMP
90 fd = set_cloexec_or_close(fd);
91 #endif
92
93 unlink(tmpname);
94 return fd;
95 }
96 #endif
97
98 /*
99 * Create a new, unique, anonymous file of the given size, and
100 * return the file descriptor for it. The file descriptor is set
101 * CLOEXEC. The file is immediately suitable for mmap()'ing
102 * the given size at offset zero.
103 *
104 * An optional name for debugging can be provided as the second argument.
105 *
106 * The file should not have a permanent backing store like a disk,
107 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
108 *
109 * If memfd or SHM_ANON is supported, the filesystem is not touched at all.
110 * Otherwise, the file name is deleted from the file system.
111 *
112 * The file is suitable for buffer sharing between processes by
113 * transmitting the file descriptor over Unix sockets using the
114 * SCM_RIGHTS methods.
115 */
116 int
117 os_create_anonymous_file(off_t size, const char *debug_name)
118 {
119 int fd, ret;
120 #ifdef __FreeBSD__
121 (void*)debug_name;
122 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600);
123 #elif defined(HAVE_MEMFD_CREATE)
124 if (!debug_name)
125 debug_name = "mesa-shared";
126 fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC);
127 #else
128 const char *path;
129 char *name;
130
131 path = getenv("XDG_RUNTIME_DIR");
132 if (!path) {
133 errno = ENOENT;
134 return -1;
135 }
136
137 if (debug_name)
138 asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name);
139 else
140 asprintf(&name, "%s/mesa-shared-XXXXXX", path);
141 if (!name)
142 return -1;
143
144 fd = create_tmpfile_cloexec(name);
145
146 free(name);
147 #endif
148
149 if (fd < 0)
150 return -1;
151
152 ret = ftruncate(fd, size);
153 if (ret < 0) {
154 close(fd);
155 return -1;
156 }
157
158 return fd;
159 }
160 #endif