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