xref: /haiku/src/system/libroot/posix/sys/mman.cpp (revision 4a3268e14fff4dd5a456d824b48ce6503368e4c1)
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_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