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 24static const char* kSharedMemoryDir = "/var/shared_memory/"; 25 26 27static bool 28append_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 42static bool 43append_string(char*& path, size_t& bytesLeft, const char* toAppend) 44{ 45 return append_string(path, bytesLeft, toAppend, strlen(toAppend)); 46} 47 48 49static status_t 50shm_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 91void* 92mmap(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 161int 162munmap(void* address, size_t length) 163{ 164 RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length)); 165} 166 167 168int 169mprotect(void* address, size_t length, int protection) 170{ 171 RETURN_AND_SET_ERRNO(_kern_set_memory_protection(address, length, 172 protection)); 173} 174 175 176int 177msync(void* address, size_t length, int flags) 178{ 179 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sync_memory(address, length, flags)); 180} 181 182 183int 184madvise(void* address, size_t length, int advice) 185{ 186 RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice)); 187} 188 189 190int 191posix_madvise(void* address, size_t length, int advice) 192{ 193 return madvise(address, length, advice); 194} 195 196 197int 198mlock(const void* address, size_t length) 199{ 200 RETURN_AND_SET_ERRNO(_kern_mlock(address, length)); 201} 202 203 204int 205munlock(const void* address, size_t length) 206{ 207 RETURN_AND_SET_ERRNO(_kern_munlock(address, length)); 208} 209 210 211int 212shm_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 223int 224shm_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