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