1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <sys/mman.h> 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <pthread.h> 14 15 #include <OS.h> 16 17 #include <runtime_loader/runtime_loader.h> 18 #include <errno_private.h> 19 #include <syscall_utils.h> 20 #include <syscalls.h> 21 #include <vm_defs.h> 22 23 24 static const char* kSharedMemoryDir = "/var/shared_memory/"; 25 26 27 static bool 28 append_string(char*& path, size_t& bytesLeft, const char* toAppend, size_t size) 29 { 30 if (bytesLeft <= size) 31 return false; 32 33 memcpy(path, toAppend, size); 34 path += size; 35 path[0] = '\0'; 36 bytesLeft -= size; 37 38 return true; 39 } 40 41 42 static bool 43 append_string(char*& path, size_t& bytesLeft, const char* toAppend) 44 { 45 return append_string(path, bytesLeft, toAppend, strlen(toAppend)); 46 } 47 48 49 static status_t 50 shm_name_to_path(const char* name, char* path, size_t pathSize) 51 { 52 if (name == NULL) 53 return B_BAD_VALUE; 54 55 // skip leading slashes 56 while (*name == '/') 57 name++; 58 59 if (*name == '\0') 60 return B_BAD_VALUE; 61 62 // create the path; replace occurrences of '/' by "%s" and '%' by "%%" 63 if (!append_string(path, pathSize, kSharedMemoryDir)) 64 return ENAMETOOLONG; 65 66 while (const char* found = strpbrk(name, "%/")) { 67 // append section that doesn't need escaping 68 if (found != name) { 69 if (!append_string(path, pathSize, name, found - name)) 70 return ENAMETOOLONG; 71 } 72 73 // append escaped char 74 const char* append = (*found == '%' ? "%%" : "%s"); 75 if (!append_string(path, pathSize, append, 2)) 76 return ENAMETOOLONG; 77 name = found + 1; 78 } 79 80 // append remaining string 81 if (!append_string(path, pathSize, name)) 82 return ENAMETOOLONG; 83 84 return B_OK; 85 } 86 87 88 // #pragma mark - 89 90 91 void* 92 mmap(void* address, size_t length, int protection, int flags, int fd, 93 off_t offset) 94 { 95 // offset and length must be page-aligned 96 if (length == 0 || offset % B_PAGE_SIZE != 0) { 97 __set_errno(B_BAD_VALUE); 98 return MAP_FAILED; 99 } 100 101 // check anonymous mapping 102 if ((flags & MAP_ANONYMOUS) != 0) { 103 fd = -1; 104 } else if (fd < 0) { 105 __set_errno(EBADF); 106 return MAP_FAILED; 107 } 108 109 // either MAP_SHARED or MAP_PRIVATE must be specified 110 if (((flags & MAP_SHARED) != 0) == ((flags & MAP_PRIVATE) != 0)) { 111 __set_errno(B_BAD_VALUE); 112 return MAP_FAILED; 113 } 114 115 // translate mapping, address specification, and protection 116 int mapping = (flags & MAP_SHARED) != 0 117 ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP; 118 119 uint32 addressSpec; 120 if ((flags & MAP_FIXED) != 0) 121 addressSpec = B_EXACT_ADDRESS; 122 else if (address != NULL) 123 addressSpec = B_BASE_ADDRESS; 124 else 125 addressSpec = B_RANDOMIZED_ANY_ADDRESS; 126 127 uint32 areaProtection = 0; 128 if ((protection & PROT_READ) != 0) 129 areaProtection |= B_READ_AREA; 130 if ((protection & PROT_WRITE) != 0) 131 areaProtection |= B_WRITE_AREA; 132 if ((protection & PROT_EXEC) != 0) 133 areaProtection |= B_EXECUTE_AREA; 134 135 if ((flags & MAP_NORESERVE) != 0) 136 areaProtection |= B_OVERCOMMITTING_AREA; 137 138 // create a name for this area based on calling image 139 void* addr = __builtin_return_address(0); 140 char* imageName; 141 char areaName[B_OS_NAME_LENGTH]; 142 status_t status = __gRuntimeLoader->get_nearest_symbol_at_address( 143 addr, NULL, NULL, &imageName, NULL, NULL, NULL, NULL); 144 if (status == B_OK) 145 snprintf(areaName, sizeof(areaName), "%s mmap area", imageName); 146 else 147 strlcpy(areaName, "mmap area", sizeof(areaName)); 148 149 // ask the kernel to map 150 area_id area = _kern_map_file(areaName, &address, addressSpec, 151 length, areaProtection, mapping, true, fd, offset); 152 if (area < 0) { 153 __set_errno(area); 154 return MAP_FAILED; 155 } 156 157 return address; 158 } 159 160 161 int 162 munmap(void* address, size_t length) 163 { 164 RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length)); 165 } 166 167 168 int 169 mprotect(void* address, size_t length, int protection) 170 { 171 RETURN_AND_SET_ERRNO(_kern_set_memory_protection(address, length, 172 protection)); 173 } 174 175 176 int 177 msync(void* address, size_t length, int flags) 178 { 179 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sync_memory(address, length, flags)); 180 } 181 182 183 int 184 madvise(void* address, size_t length, int advice) 185 { 186 RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice)); 187 } 188 189 190 int 191 posix_madvise(void* address, size_t length, int advice) 192 { 193 return madvise(address, length, advice); 194 } 195 196 197 int 198 mlock(const void* address, size_t length) 199 { 200 RETURN_AND_SET_ERRNO(_kern_mlock(address, length)); 201 } 202 203 204 int 205 munlock(const void* address, size_t length) 206 { 207 RETURN_AND_SET_ERRNO(_kern_munlock(address, length)); 208 } 209 210 211 int 212 shm_open(const char* name, int openMode, mode_t permissions) 213 { 214 char path[PATH_MAX]; 215 status_t error = shm_name_to_path(name, path, sizeof(path)); 216 if (error != B_OK) 217 RETURN_AND_SET_ERRNO(error); 218 219 return open(path, openMode | O_CLOEXEC, permissions); 220 } 221 222 223 int 224 shm_unlink(const char* name) 225 { 226 char path[PATH_MAX]; 227 status_t error = shm_name_to_path(name, path, sizeof(path)); 228 if (error != B_OK) 229 RETURN_AND_SET_ERRNO(error); 230 231 return unlink(path); 232 } 233