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