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 | #include "config.h" |
27 | |
28 | #include <sys/types.h> |
29 | #include <unistd.h> |
30 | #include <fcntl.h> |
31 | #include <errno.h> |
32 | #include <string.h> |
33 | #include <stdlib.h> |
34 | |
35 | #ifdef HAVE_MEMFD_CREATE |
36 | #include <sys/mman.h> |
37 | #endif |
38 | |
39 | #include "os-compatibility.h" |
40 | |
41 | #ifndef HAVE_MKOSTEMP |
42 | static int |
43 | set_cloexec_or_close(int fd) |
44 | { |
45 | long flags; |
46 | |
47 | if (fd == -1) |
48 | return -1; |
49 | |
50 | flags = fcntl(fd: fd, F_GETFD); |
51 | if (flags == -1) |
52 | goto err; |
53 | |
54 | if (fcntl(fd: fd, F_SETFD, flags | FD_CLOEXEC) == -1) |
55 | goto err; |
56 | |
57 | return fd; |
58 | |
59 | err: |
60 | close(fd: fd); |
61 | return -1; |
62 | } |
63 | #endif |
64 | |
65 | static int |
66 | create_tmpfile_cloexec(char *tmpname) |
67 | { |
68 | int fd; |
69 | |
70 | #ifdef HAVE_MKOSTEMP |
71 | fd = mkostemp(tmpname, O_CLOEXEC); |
72 | if (fd >= 0) |
73 | unlink(tmpname); |
74 | #else |
75 | fd = mkstemp(template: tmpname); |
76 | if (fd >= 0) { |
77 | fd = set_cloexec_or_close(fd); |
78 | unlink(name: tmpname); |
79 | } |
80 | #endif |
81 | |
82 | return fd; |
83 | } |
84 | |
85 | /* |
86 | * Create a new, unique, anonymous file of the given size, and |
87 | * return the file descriptor for it. The file descriptor is set |
88 | * CLOEXEC. The file is immediately suitable for mmap()'ing |
89 | * the given size at offset zero. |
90 | * |
91 | * The file should not have a permanent backing store like a disk, |
92 | * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. |
93 | * |
94 | * The file name is deleted from the file system. |
95 | * |
96 | * The file is suitable for buffer sharing between processes by |
97 | * transmitting the file descriptor over Unix sockets using the |
98 | * SCM_RIGHTS methods. |
99 | * |
100 | * If the C library implements posix_fallocate(), it is used to |
101 | * guarantee that disk space is available for the file at the |
102 | * given size. If disk space is insufficient, errno is set to ENOSPC. |
103 | * If posix_fallocate() is not supported, program may receive |
104 | * SIGBUS on accessing mmap()'ed file contents instead. |
105 | * |
106 | * If the C library implements memfd_create(), it is used to create the |
107 | * file purely in memory, without any backing file name on the file |
108 | * system, and then sealing off the possibility of shrinking it. This |
109 | * can then be checked before accessing mmap()'ed file contents, to |
110 | * make sure SIGBUS can't happen. It also avoids requiring |
111 | * XDG_RUNTIME_DIR. |
112 | */ |
113 | int |
114 | os_create_anonymous_file(off_t size) |
115 | { |
116 | static const char template[] = "/wayland-cursor-shared-XXXXXX" ; |
117 | const char *path; |
118 | char *name; |
119 | int fd; |
120 | int ret; |
121 | |
122 | #ifdef HAVE_MEMFD_CREATE |
123 | fd = memfd_create(name: "wayland-cursor" , MFD_CLOEXEC | MFD_ALLOW_SEALING); |
124 | if (fd >= 0) { |
125 | /* We can add this seal before calling posix_fallocate(), as |
126 | * the file is currently zero-sized anyway. |
127 | * |
128 | * There is also no need to check for the return value, we |
129 | * couldn't do anything with it anyway. |
130 | */ |
131 | fcntl(fd: fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); |
132 | } else |
133 | #endif |
134 | { |
135 | path = getenv(name: "XDG_RUNTIME_DIR" ); |
136 | if (!path) { |
137 | errno = ENOENT; |
138 | return -1; |
139 | } |
140 | |
141 | name = malloc(size: strlen(s: path) + sizeof(template)); |
142 | if (!name) |
143 | return -1; |
144 | |
145 | strcpy(dest: name, src: path); |
146 | strcat(dest: name, src: template); |
147 | |
148 | fd = create_tmpfile_cloexec(tmpname: name); |
149 | |
150 | free(ptr: name); |
151 | |
152 | if (fd < 0) |
153 | return -1; |
154 | } |
155 | |
156 | #ifdef HAVE_POSIX_FALLOCATE |
157 | ret = posix_fallocate(fd: fd, offset: 0, len: size); |
158 | if (ret != 0) { |
159 | close(fd: fd); |
160 | errno = ret; |
161 | return -1; |
162 | } |
163 | #else |
164 | ret = ftruncate(fd, size); |
165 | if (ret < 0) { |
166 | close(fd); |
167 | return -1; |
168 | } |
169 | #endif |
170 | |
171 | return fd; |
172 | } |
173 | |