xref: /haiku/src/system/libroot/posix/sys/mman.cpp (revision 6011ce6c7495e4e707bd33b12a7e22d66c710aad)
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 | FD_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