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 <string.h> 12 13 #include <OS.h> 14 15 #include <errno_private.h> 16 #include <syscall_utils.h> 17 #include <syscalls.h> 18 #include <vm_defs.h> 19 20 21 static const char* kSharedMemoryDir = "/var/shared_memory/"; 22 23 24 static bool 25 append_string(char*& path, size_t& bytesLeft, const char* toAppend, size_t size) 26 { 27 if (bytesLeft <= size) 28 return false; 29 30 memcpy(path, toAppend, size); 31 path += size; 32 path[0] = '\0'; 33 bytesLeft -= size; 34 35 return true; 36 } 37 38 39 static bool 40 append_string(char*& path, size_t& bytesLeft, const char* toAppend) 41 { 42 return append_string(path, bytesLeft, toAppend, strlen(toAppend)); 43 } 44 45 46 static status_t 47 shm_name_to_path(const char* name, char* path, size_t pathSize) 48 { 49 if (name == NULL) 50 return B_BAD_VALUE; 51 52 // skip leading slashes 53 while (*name == '/') 54 name++; 55 56 if (*name == '\0') 57 return B_BAD_VALUE; 58 59 // create the path; replace occurrences of '/' by "%s" and '%' by "%%" 60 if (!append_string(path, pathSize, kSharedMemoryDir)) 61 return ENAMETOOLONG; 62 63 while (const char* found = strpbrk(name, "%/")) { 64 // append section that doesn't need escaping 65 if (found != name) { 66 if (!append_string(path, pathSize, name, found - name)) 67 return ENAMETOOLONG; 68 } 69 70 // append escaped char 71 const char* append = (*found == '%' ? "%%" : "%s"); 72 if (!append_string(path, pathSize, append, 2)) 73 return ENAMETOOLONG; 74 name = found + 1; 75 } 76 77 // append remaining string 78 if (!append_string(path, pathSize, name)) 79 return ENAMETOOLONG; 80 81 return B_OK; 82 } 83 84 85 // #pragma mark - 86 87 88 void* 89 mmap(void* address, size_t length, int protection, int flags, int fd, 90 off_t offset) 91 { 92 // offset and length must be page-aligned 93 if (length == 0 || offset % B_PAGE_SIZE != 0) { 94 __set_errno(B_BAD_VALUE); 95 return MAP_FAILED; 96 } 97 98 // check anonymous mapping 99 if ((flags & MAP_ANONYMOUS) != 0) { 100 fd = -1; 101 } else if (fd < 0) { 102 __set_errno(EBADF); 103 return MAP_FAILED; 104 } 105 106 // either MAP_SHARED or MAP_PRIVATE must be specified 107 if (((flags & MAP_SHARED) != 0) == ((flags & MAP_PRIVATE) != 0)) { 108 __set_errno(B_BAD_VALUE); 109 return MAP_FAILED; 110 } 111 112 // translate mapping, address specification, and protection 113 int mapping = (flags & MAP_SHARED) != 0 114 ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP; 115 116 uint32 addressSpec; 117 if ((flags & MAP_FIXED) != 0) 118 addressSpec = B_EXACT_ADDRESS; 119 else if (address != NULL) 120 addressSpec = B_RANDOMIZED_BASE_ADDRESS; 121 else 122 addressSpec = B_RANDOMIZED_ANY_ADDRESS; 123 124 uint32 areaProtection = 0; 125 if ((protection & PROT_READ) != 0) 126 areaProtection |= B_READ_AREA; 127 if ((protection & PROT_WRITE) != 0) 128 areaProtection |= B_WRITE_AREA; 129 if ((protection & PROT_EXEC) != 0) 130 areaProtection |= B_EXECUTE_AREA; 131 132 // ask the kernel to map 133 area_id area = _kern_map_file("mmap area", &address, addressSpec, 134 length, areaProtection, mapping, true, fd, offset); 135 if (area < 0) { 136 __set_errno(area); 137 return MAP_FAILED; 138 } 139 140 return address; 141 } 142 143 144 int 145 munmap(void* address, size_t length) 146 { 147 RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length)); 148 } 149 150 151 int 152 mprotect(void* address, size_t length, int protection) 153 { 154 RETURN_AND_SET_ERRNO(_kern_set_memory_protection(address, length, 155 protection)); 156 } 157 158 159 int 160 msync(void* address, size_t length, int flags) 161 { 162 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sync_memory(address, length, flags)); 163 } 164 165 166 int 167 posix_madvise(void* address, size_t length, int advice) 168 { 169 RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice)); 170 } 171 172 173 int 174 shm_open(const char* name, int openMode, mode_t permissions) 175 { 176 char path[PATH_MAX]; 177 status_t error = shm_name_to_path(name, path, sizeof(path)); 178 if (error != B_OK) 179 RETURN_AND_SET_ERRNO(error); 180 181 return open(path, openMode, permissions); 182 } 183 184 185 int 186 shm_unlink(const char* name) 187 { 188 char path[PATH_MAX]; 189 status_t error = shm_name_to_path(name, path, sizeof(path)); 190 if (error != B_OK) 191 RETURN_AND_SET_ERRNO(error); 192 193 return unlink(path); 194 } 195