xref: /aosp_15_r20/external/wayland/cursor/os-compatibility.c (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
1*84e872a0SLloyd Pique /*
2*84e872a0SLloyd Pique  * Copyright © 2012 Collabora, Ltd.
3*84e872a0SLloyd Pique  *
4*84e872a0SLloyd Pique  * Permission is hereby granted, free of charge, to any person obtaining
5*84e872a0SLloyd Pique  * a copy of this software and associated documentation files (the
6*84e872a0SLloyd Pique  * "Software"), to deal in the Software without restriction, including
7*84e872a0SLloyd Pique  * without limitation the rights to use, copy, modify, merge, publish,
8*84e872a0SLloyd Pique  * distribute, sublicense, and/or sell copies of the Software, and to
9*84e872a0SLloyd Pique  * permit persons to whom the Software is furnished to do so, subject to
10*84e872a0SLloyd Pique  * the following conditions:
11*84e872a0SLloyd Pique  *
12*84e872a0SLloyd Pique  * The above copyright notice and this permission notice (including the
13*84e872a0SLloyd Pique  * next paragraph) shall be included in all copies or substantial
14*84e872a0SLloyd Pique  * portions of the Software.
15*84e872a0SLloyd Pique  *
16*84e872a0SLloyd Pique  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*84e872a0SLloyd Pique  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*84e872a0SLloyd Pique  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*84e872a0SLloyd Pique  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20*84e872a0SLloyd Pique  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21*84e872a0SLloyd Pique  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22*84e872a0SLloyd Pique  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*84e872a0SLloyd Pique  * SOFTWARE.
24*84e872a0SLloyd Pique  */
25*84e872a0SLloyd Pique 
26*84e872a0SLloyd Pique #define _GNU_SOURCE
27*84e872a0SLloyd Pique 
28*84e872a0SLloyd Pique #include "config.h"
29*84e872a0SLloyd Pique 
30*84e872a0SLloyd Pique #include <sys/types.h>
31*84e872a0SLloyd Pique #include <unistd.h>
32*84e872a0SLloyd Pique #include <fcntl.h>
33*84e872a0SLloyd Pique #include <errno.h>
34*84e872a0SLloyd Pique #include <signal.h>
35*84e872a0SLloyd Pique #include <string.h>
36*84e872a0SLloyd Pique #include <stdio.h>
37*84e872a0SLloyd Pique #include <stdlib.h>
38*84e872a0SLloyd Pique 
39*84e872a0SLloyd Pique #ifdef HAVE_MEMFD_CREATE
40*84e872a0SLloyd Pique #include <sys/mman.h>
41*84e872a0SLloyd Pique #endif
42*84e872a0SLloyd Pique 
43*84e872a0SLloyd Pique #include "os-compatibility.h"
44*84e872a0SLloyd Pique 
45*84e872a0SLloyd Pique #ifndef HAVE_MKOSTEMP
46*84e872a0SLloyd Pique static int
set_cloexec_or_close(int fd)47*84e872a0SLloyd Pique set_cloexec_or_close(int fd)
48*84e872a0SLloyd Pique {
49*84e872a0SLloyd Pique 	long flags;
50*84e872a0SLloyd Pique 
51*84e872a0SLloyd Pique 	if (fd == -1)
52*84e872a0SLloyd Pique 		return -1;
53*84e872a0SLloyd Pique 
54*84e872a0SLloyd Pique 	flags = fcntl(fd, F_GETFD);
55*84e872a0SLloyd Pique 	if (flags == -1)
56*84e872a0SLloyd Pique 		goto err;
57*84e872a0SLloyd Pique 
58*84e872a0SLloyd Pique 	if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
59*84e872a0SLloyd Pique 		goto err;
60*84e872a0SLloyd Pique 
61*84e872a0SLloyd Pique 	return fd;
62*84e872a0SLloyd Pique 
63*84e872a0SLloyd Pique err:
64*84e872a0SLloyd Pique 	close(fd);
65*84e872a0SLloyd Pique 	return -1;
66*84e872a0SLloyd Pique }
67*84e872a0SLloyd Pique #endif
68*84e872a0SLloyd Pique 
69*84e872a0SLloyd Pique static int
create_tmpfile_cloexec(char * tmpname)70*84e872a0SLloyd Pique create_tmpfile_cloexec(char *tmpname)
71*84e872a0SLloyd Pique {
72*84e872a0SLloyd Pique 	int fd;
73*84e872a0SLloyd Pique 
74*84e872a0SLloyd Pique #ifdef HAVE_MKOSTEMP
75*84e872a0SLloyd Pique 	fd = mkostemp(tmpname, O_CLOEXEC);
76*84e872a0SLloyd Pique 	if (fd >= 0)
77*84e872a0SLloyd Pique 		unlink(tmpname);
78*84e872a0SLloyd Pique #else
79*84e872a0SLloyd Pique 	fd = mkstemp(tmpname);
80*84e872a0SLloyd Pique 	if (fd >= 0) {
81*84e872a0SLloyd Pique 		fd = set_cloexec_or_close(fd);
82*84e872a0SLloyd Pique 		unlink(tmpname);
83*84e872a0SLloyd Pique 	}
84*84e872a0SLloyd Pique #endif
85*84e872a0SLloyd Pique 
86*84e872a0SLloyd Pique 	return fd;
87*84e872a0SLloyd Pique }
88*84e872a0SLloyd Pique 
89*84e872a0SLloyd Pique /*
90*84e872a0SLloyd Pique  * Create a new, unique, anonymous file of the given size, and
91*84e872a0SLloyd Pique  * return the file descriptor for it. The file descriptor is set
92*84e872a0SLloyd Pique  * CLOEXEC. The file is immediately suitable for mmap()'ing
93*84e872a0SLloyd Pique  * the given size at offset zero.
94*84e872a0SLloyd Pique  *
95*84e872a0SLloyd Pique  * The file should not have a permanent backing store like a disk,
96*84e872a0SLloyd Pique  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
97*84e872a0SLloyd Pique  *
98*84e872a0SLloyd Pique  * The file name is deleted from the file system.
99*84e872a0SLloyd Pique  *
100*84e872a0SLloyd Pique  * The file is suitable for buffer sharing between processes by
101*84e872a0SLloyd Pique  * transmitting the file descriptor over Unix sockets using the
102*84e872a0SLloyd Pique  * SCM_RIGHTS methods.
103*84e872a0SLloyd Pique  *
104*84e872a0SLloyd Pique  * If the C library implements posix_fallocate(), it is used to
105*84e872a0SLloyd Pique  * guarantee that disk space is available for the file at the
106*84e872a0SLloyd Pique  * given size. If disk space is insufficient, errno is set to ENOSPC.
107*84e872a0SLloyd Pique  * If posix_fallocate() is not supported, program may receive
108*84e872a0SLloyd Pique  * SIGBUS on accessing mmap()'ed file contents instead.
109*84e872a0SLloyd Pique  *
110*84e872a0SLloyd Pique  * If the C library implements memfd_create(), it is used to create the
111*84e872a0SLloyd Pique  * file purely in memory, without any backing file name on the file
112*84e872a0SLloyd Pique  * system, and then sealing off the possibility of shrinking it.  This
113*84e872a0SLloyd Pique  * can then be checked before accessing mmap()'ed file contents, to
114*84e872a0SLloyd Pique  * make sure SIGBUS can't happen.  It also avoids requiring
115*84e872a0SLloyd Pique  * XDG_RUNTIME_DIR.
116*84e872a0SLloyd Pique  */
117*84e872a0SLloyd Pique int
os_create_anonymous_file(off_t size)118*84e872a0SLloyd Pique os_create_anonymous_file(off_t size)
119*84e872a0SLloyd Pique {
120*84e872a0SLloyd Pique 	static const char template[] = "/wayland-cursor-shared-XXXXXX";
121*84e872a0SLloyd Pique 	const char *path;
122*84e872a0SLloyd Pique 	char *name;
123*84e872a0SLloyd Pique 	size_t name_size;
124*84e872a0SLloyd Pique 	int fd;
125*84e872a0SLloyd Pique 
126*84e872a0SLloyd Pique #ifdef HAVE_MEMFD_CREATE
127*84e872a0SLloyd Pique 	fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
128*84e872a0SLloyd Pique 	if (fd >= 0) {
129*84e872a0SLloyd Pique 		/* We can add this seal before calling posix_fallocate(), as
130*84e872a0SLloyd Pique 		 * the file is currently zero-sized anyway.
131*84e872a0SLloyd Pique 		 *
132*84e872a0SLloyd Pique 		 * There is also no need to check for the return value, we
133*84e872a0SLloyd Pique 		 * couldn't do anything with it anyway.
134*84e872a0SLloyd Pique 		 */
135*84e872a0SLloyd Pique 		fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
136*84e872a0SLloyd Pique 	} else
137*84e872a0SLloyd Pique #endif
138*84e872a0SLloyd Pique 	{
139*84e872a0SLloyd Pique 		path = getenv("XDG_RUNTIME_DIR");
140*84e872a0SLloyd Pique 		if (!path || path[0] != '/') {
141*84e872a0SLloyd Pique 			errno = ENOENT;
142*84e872a0SLloyd Pique 			return -1;
143*84e872a0SLloyd Pique 		}
144*84e872a0SLloyd Pique 
145*84e872a0SLloyd Pique 		name_size = strlen(path) + sizeof(template);
146*84e872a0SLloyd Pique 		name = malloc(name_size);
147*84e872a0SLloyd Pique 		if (!name)
148*84e872a0SLloyd Pique 			return -1;
149*84e872a0SLloyd Pique 
150*84e872a0SLloyd Pique 		snprintf(name, name_size, "%s%s", path, template);
151*84e872a0SLloyd Pique 
152*84e872a0SLloyd Pique 		fd = create_tmpfile_cloexec(name);
153*84e872a0SLloyd Pique 
154*84e872a0SLloyd Pique 		free(name);
155*84e872a0SLloyd Pique 
156*84e872a0SLloyd Pique 		if (fd < 0)
157*84e872a0SLloyd Pique 			return -1;
158*84e872a0SLloyd Pique 	}
159*84e872a0SLloyd Pique 
160*84e872a0SLloyd Pique 	if (os_resize_anonymous_file(fd, size) < 0) {
161*84e872a0SLloyd Pique 		close(fd);
162*84e872a0SLloyd Pique 		return -1;
163*84e872a0SLloyd Pique 	}
164*84e872a0SLloyd Pique 
165*84e872a0SLloyd Pique 	return fd;
166*84e872a0SLloyd Pique }
167*84e872a0SLloyd Pique 
168*84e872a0SLloyd Pique int
os_resize_anonymous_file(int fd,off_t size)169*84e872a0SLloyd Pique os_resize_anonymous_file(int fd, off_t size)
170*84e872a0SLloyd Pique {
171*84e872a0SLloyd Pique #ifdef HAVE_POSIX_FALLOCATE
172*84e872a0SLloyd Pique 	sigset_t mask;
173*84e872a0SLloyd Pique 	sigset_t old_mask;
174*84e872a0SLloyd Pique 
175*84e872a0SLloyd Pique 	/*
176*84e872a0SLloyd Pique 	 * posix_fallocate() might be interrupted, so we need to check
177*84e872a0SLloyd Pique 	 * for EINTR and retry in that case.
178*84e872a0SLloyd Pique 	 * However, in the presence of an alarm, the interrupt may trigger
179*84e872a0SLloyd Pique 	 * repeatedly and prevent a large posix_fallocate() to ever complete
180*84e872a0SLloyd Pique 	 * successfully, so we need to first block SIGALRM to prevent
181*84e872a0SLloyd Pique 	 * this.
182*84e872a0SLloyd Pique 	 */
183*84e872a0SLloyd Pique 	sigemptyset(&mask);
184*84e872a0SLloyd Pique 	sigaddset(&mask, SIGALRM);
185*84e872a0SLloyd Pique 	sigprocmask(SIG_BLOCK, &mask, &old_mask);
186*84e872a0SLloyd Pique 	/*
187*84e872a0SLloyd Pique 	 * Filesystems that do not support fallocate will return EINVAL or
188*84e872a0SLloyd Pique 	 * EOPNOTSUPP. In this case we need to fall back to ftruncate
189*84e872a0SLloyd Pique 	 */
190*84e872a0SLloyd Pique 	do {
191*84e872a0SLloyd Pique 		errno = posix_fallocate(fd, 0, size);
192*84e872a0SLloyd Pique 	} while (errno == EINTR);
193*84e872a0SLloyd Pique 	sigprocmask(SIG_SETMASK, &old_mask, NULL);
194*84e872a0SLloyd Pique 	if (errno == 0)
195*84e872a0SLloyd Pique 		return 0;
196*84e872a0SLloyd Pique 	else if (errno != EINVAL && errno != EOPNOTSUPP)
197*84e872a0SLloyd Pique 		return -1;
198*84e872a0SLloyd Pique #endif
199*84e872a0SLloyd Pique 	if (ftruncate(fd, size) < 0)
200*84e872a0SLloyd Pique 		return -1;
201*84e872a0SLloyd Pique 
202*84e872a0SLloyd Pique 	return 0;
203*84e872a0SLloyd Pique }
204