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
append_string(char * & path,size_t & bytesLeft,const char * toAppend,size_t size)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
append_string(char * & path,size_t & bytesLeft,const char * toAppend)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
shm_name_to_path(const char * name,char * path,size_t pathSize)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*
mmap(void * address,size_t length,int protection,int flags,int fd,off_t offset)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
munmap(void * address,size_t length)162 munmap(void* address, size_t length)
163 {
164 RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length));
165 }
166
167
168 int
mprotect(void * address,size_t length,int protection)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
msync(void * address,size_t length,int flags)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
madvise(void * address,size_t length,int advice)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
posix_madvise(void * address,size_t length,int advice)191 posix_madvise(void* address, size_t length, int advice)
192 {
193 return madvise(address, length, advice);
194 }
195
196
197 int
mlock(const void * address,size_t length)198 mlock(const void* address, size_t length)
199 {
200 RETURN_AND_SET_ERRNO(_kern_mlock(address, length));
201 }
202
203
204 int
munlock(const void * address,size_t length)205 munlock(const void* address, size_t length)
206 {
207 RETURN_AND_SET_ERRNO(_kern_munlock(address, length));
208 }
209
210
211 int
shm_open(const char * name,int openMode,mode_t permissions)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
shm_unlink(const char * name)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