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 #define _GNU_SOURCE 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 #include "config.h" 36 #include "os-compatibility.h" 37 38 #ifndef HAVE_MKOSTEMP 39 static int 40 set_cloexec_or_close(int fd) 41 { 42 long flags; 43 44 if (fd == -1) 45 return -1; 46 47 flags = fcntl(fd, F_GETFD); 48 if (flags == -1) 49 goto err; 50 51 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 52 goto err; 53 54 return fd; 55 56 err: 57 close(fd); 58 return -1; 59 } 60 #endif 61 62 static int 63 create_tmpfile_cloexec(char *tmpname) 64 { 65 int fd; 66 67 #ifdef HAVE_MKOSTEMP 68 fd = mkostemp(tmpname, O_CLOEXEC); 69 if (fd >= 0) 70 unlink(tmpname); 71 #else 72 fd = mkstemp(tmpname); 73 if (fd >= 0) { 74 fd = set_cloexec_or_close(fd); 75 unlink(tmpname); 76 } 77 #endif 78 79 return fd; 80 } 81 82 /* 83 * Create a new, unique, anonymous file of the given size, and 84 * return the file descriptor for it. The file descriptor is set 85 * CLOEXEC. The file is immediately suitable for mmap()'ing 86 * the given size at offset zero. 87 * 88 * The file should not have a permanent backing store like a disk, 89 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. 90 * 91 * The file name is deleted from the file system. 92 * 93 * The file is suitable for buffer sharing between processes by 94 * transmitting the file descriptor over Unix sockets using the 95 * SCM_RIGHTS methods. 96 * 97 * If the C library implements posix_fallocate(), it is used to 98 * guarantee that disk space is available for the file at the 99 * given size. If disk space is insufficent, errno is set to ENOSPC. 100 * If posix_fallocate() is not supported, program may receive 101 * SIGBUS on accessing mmap()'ed file contents instead. 102 */ 103 int 104 os_create_anonymous_file(off_t size) 105 { 106 static const char template[] = "/weston-shared-XXXXXX"; 107 const char *path; 108 char *name; 109 int fd; 110 int ret; 111 112 path = getenv("XDG_RUNTIME_DIR"); 113 if (!path) { 114 errno = ENOENT; 115 return -1; 116 } 117 118 name = malloc(strlen(path) + sizeof(template)); 119 if (!name) 120 return -1; 121 122 strcpy(name, path); 123 strcat(name, template); 124 125 fd = create_tmpfile_cloexec(name); 126 127 free(name); 128 129 if (fd < 0) 130 return -1; 131 132 #ifdef HAVE_POSIX_FALLOCATE 133 ret = posix_fallocate(fd, 0, size); 134 if (ret != 0) { 135 close(fd); 136 errno = ret; 137 return -1; 138 } 139 #else 140 ret = ftruncate(fd, size); 141 if (ret < 0) { 142 close(fd); 143 return -1; 144 } 145 #endif 146 147 return fd; 148 } 149