• 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(__FreeBSD__) || defined(__OpenBSD__)
39 #include <sys/mman.h>
40 #elif defined(HAVE_MEMFD_CREATE) || 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 #ifdef __FreeBSD__
119    (void*)debug_name;
120    fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600);
121 #elif defined(__OpenBSD__)
122    char template[] = "/tmp/mesa-XXXXXXXXXX";
123    fd = shm_mkstemp(template);
124    if (fd != -1)
125       shm_unlink(template);
126 #elif defined(HAVE_MEMFD_CREATE) || defined(ANDROID)
127    if (!debug_name)
128       debug_name = "mesa-shared";
129    fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC);
130 #else
131    const char *path;
132    char *name;
133 
134    path = getenv("XDG_RUNTIME_DIR");
135    if (!path) {
136       errno = ENOENT;
137       return -1;
138    }
139 
140    if (debug_name)
141       asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name);
142    else
143       asprintf(&name, "%s/mesa-shared-XXXXXX", path);
144    if (!name)
145       return -1;
146 
147    fd = create_tmpfile_cloexec(name);
148 
149    free(name);
150 #endif
151 
152    if (fd < 0)
153       return -1;
154 
155    ret = ftruncate(fd, size);
156    if (ret < 0) {
157       close(fd);
158       return -1;
159    }
160 
161    return fd;
162 }
163 #endif
164