xref: /haiku/src/system/libroot/posix/sys/mman.cpp (revision 85fb3e7df81f8d5b6e47a9a64a53873ea906ea6e)
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 = address == NULL ? B_ANY_ADDRESS : B_BASE_ADDRESS;
117 	if ((flags & MAP_FIXED) != 0)
118 		addressSpec = B_EXACT_ADDRESS;
119 
120 	uint32 areaProtection = 0;
121 	if ((protection & PROT_READ) != 0)
122 		areaProtection |= B_READ_AREA;
123 	if ((protection & PROT_WRITE) != 0)
124 		areaProtection |= B_WRITE_AREA;
125 	if ((protection & PROT_EXEC) != 0)
126 		areaProtection |= B_EXECUTE_AREA;
127 
128 	// ask the kernel to map
129 	area_id area = _kern_map_file("mmap area", &address, addressSpec,
130 		length, areaProtection, mapping, true, fd, offset);
131 	if (area < 0) {
132 		__set_errno(area);
133 		return MAP_FAILED;
134 	}
135 
136 	return address;
137 }
138 
139 
140 int
141 munmap(void* address, size_t length)
142 {
143 	RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length));
144 }
145 
146 
147 int
148 mprotect(void* address, size_t length, int protection)
149 {
150 	RETURN_AND_SET_ERRNO(_kern_set_memory_protection(address, length,
151 		protection));
152 }
153 
154 
155 int
156 msync(void* address, size_t length, int flags)
157 {
158 	RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sync_memory(address, length, flags));
159 }
160 
161 
162 int
163 posix_madvise(void* address, size_t length, int advice)
164 {
165 	RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice));
166 }
167 
168 
169 int
170 shm_open(const char* name, int openMode, mode_t permissions)
171 {
172 	char path[PATH_MAX];
173 	status_t error = shm_name_to_path(name, path, sizeof(path));
174 	if (error != B_OK)
175 		RETURN_AND_SET_ERRNO(error);
176 
177 	return open(path, openMode, permissions);
178 }
179 
180 
181 int
182 shm_unlink(const char* name)
183 {
184 	char path[PATH_MAX];
185 	status_t error = shm_name_to_path(name, path, sizeof(path));
186 	if (error != B_OK)
187 		RETURN_AND_SET_ERRNO(error);
188 
189 	return unlink(path);
190 }
191