1 use crate::{Error, Result};
2 #[cfg(not(target_os = "android"))]
3 use crate::NixPath;
4 use crate::errno::Errno;
5 #[cfg(not(target_os = "android"))]
6 use crate::fcntl::OFlag;
7 use libc::{self, c_int, c_void, size_t, off_t};
8 #[cfg(not(target_os = "android"))]
9 use crate::sys::stat::Mode;
10 use std::os::unix::io::RawFd;
11
12 libc_bitflags!{
13 /// Desired memory protection of a memory mapping.
14 pub struct ProtFlags: c_int {
15 /// Pages cannot be accessed.
16 PROT_NONE;
17 /// Pages can be read.
18 PROT_READ;
19 /// Pages can be written.
20 PROT_WRITE;
21 /// Pages can be executed
22 PROT_EXEC;
23 /// Apply protection up to the end of a mapping that grows upwards.
24 #[cfg(any(target_os = "android", target_os = "linux"))]
25 PROT_GROWSDOWN;
26 /// Apply protection down to the beginning of a mapping that grows downwards.
27 #[cfg(any(target_os = "android", target_os = "linux"))]
28 PROT_GROWSUP;
29 }
30 }
31
32 libc_bitflags!{
33 /// Additional parameters for `mmap()`.
34 pub struct MapFlags: c_int {
35 /// Compatibility flag. Ignored.
36 MAP_FILE;
37 /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
38 MAP_SHARED;
39 /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
40 MAP_PRIVATE;
41 /// Place the mapping at exactly the address specified in `addr`.
42 MAP_FIXED;
43 /// Synonym for `MAP_ANONYMOUS`.
44 MAP_ANON;
45 /// The mapping is not backed by any file.
46 #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
47 MAP_ANONYMOUS;
48 /// Put the mapping into the first 2GB of the process address space.
49 #[cfg(any(all(any(target_os = "android", target_os = "linux"),
50 any(target_arch = "x86", target_arch = "x86_64")),
51 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
52 all(target_os = "freebsd", target_pointer_width = "64")))]
53 MAP_32BIT;
54 /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
55 #[cfg(any(target_os = "android", target_os = "linux"))]
56 MAP_GROWSDOWN;
57 /// Compatibility flag. Ignored.
58 #[cfg(any(target_os = "android", target_os = "linux"))]
59 MAP_DENYWRITE;
60 /// Compatibility flag. Ignored.
61 #[cfg(any(target_os = "android", target_os = "linux"))]
62 MAP_EXECUTABLE;
63 /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
64 #[cfg(any(target_os = "android", target_os = "linux"))]
65 MAP_LOCKED;
66 /// Do not reserve swap space for this mapping.
67 ///
68 /// This was removed in FreeBSD 11.
69 #[cfg(not(target_os = "freebsd"))]
70 MAP_NORESERVE;
71 /// Populate page tables for a mapping.
72 #[cfg(any(target_os = "android", target_os = "linux"))]
73 MAP_POPULATE;
74 /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
75 #[cfg(any(target_os = "android", target_os = "linux"))]
76 MAP_NONBLOCK;
77 /// Allocate the mapping using "huge pages."
78 #[cfg(any(target_os = "android", target_os = "linux"))]
79 MAP_HUGETLB;
80 /// Make use of 64KB huge page (must be supported by the system)
81 #[cfg(target_os = "linux")]
82 MAP_HUGE_64KB;
83 /// Make use of 512KB huge page (must be supported by the system)
84 #[cfg(target_os = "linux")]
85 MAP_HUGE_512KB;
86 /// Make use of 1MB huge page (must be supported by the system)
87 #[cfg(target_os = "linux")]
88 MAP_HUGE_1MB;
89 /// Make use of 2MB huge page (must be supported by the system)
90 #[cfg(target_os = "linux")]
91 MAP_HUGE_2MB;
92 /// Make use of 8MB huge page (must be supported by the system)
93 #[cfg(target_os = "linux")]
94 MAP_HUGE_8MB;
95 /// Make use of 16MB huge page (must be supported by the system)
96 #[cfg(target_os = "linux")]
97 MAP_HUGE_16MB;
98 /// Make use of 32MB huge page (must be supported by the system)
99 #[cfg(target_os = "linux")]
100 MAP_HUGE_32MB;
101 /// Make use of 256MB huge page (must be supported by the system)
102 #[cfg(target_os = "linux")]
103 MAP_HUGE_256MB;
104 /// Make use of 512MB huge page (must be supported by the system)
105 #[cfg(target_os = "linux")]
106 MAP_HUGE_512MB;
107 /// Make use of 1GB huge page (must be supported by the system)
108 #[cfg(target_os = "linux")]
109 MAP_HUGE_1GB;
110 /// Make use of 2GB huge page (must be supported by the system)
111 #[cfg(target_os = "linux")]
112 MAP_HUGE_2GB;
113 /// Make use of 16GB huge page (must be supported by the system)
114 #[cfg(target_os = "linux")]
115 MAP_HUGE_16GB;
116
117 /// Lock the mapped region into memory as with `mlock(2)`.
118 #[cfg(target_os = "netbsd")]
119 MAP_WIRED;
120 /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
121 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
122 MAP_NOSYNC;
123 /// Rename private pages to a file.
124 ///
125 /// This was removed in FreeBSD 11.
126 #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))]
127 MAP_RENAME;
128 /// Region may contain semaphores.
129 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
130 MAP_HASSEMAPHORE;
131 /// Region grows down, like a stack.
132 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
133 MAP_STACK;
134 /// Pages in this mapping are not retained in the kernel's memory cache.
135 #[cfg(any(target_os = "ios", target_os = "macos"))]
136 MAP_NOCACHE;
137 #[cfg(any(target_os = "ios", target_os = "macos"))]
138 MAP_JIT;
139 }
140 }
141
142 #[cfg(target_os = "linux")]
143 libc_bitflags!{
144 /// Options for `mremap()`.
145 pub struct MRemapFlags: c_int {
146 /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
147 MREMAP_MAYMOVE;
148 /// Place the mapping at exactly the address specified in `new_address`.
149 MREMAP_FIXED;
150 }
151 }
152
153 libc_enum!{
154 /// Usage information for a range of memory to allow for performance optimizations by the kernel.
155 ///
156 /// Used by [`madvise`](./fn.madvise.html).
157 #[repr(i32)]
158 pub enum MmapAdvise {
159 /// No further special treatment. This is the default.
160 MADV_NORMAL,
161 /// Expect random page references.
162 MADV_RANDOM,
163 /// Expect sequential page references.
164 MADV_SEQUENTIAL,
165 /// Expect access in the near future.
166 MADV_WILLNEED,
167 /// Do not expect access in the near future.
168 MADV_DONTNEED,
169 /// Free up a given range of pages and its associated backing store.
170 #[cfg(any(target_os = "android", target_os = "linux"))]
171 MADV_REMOVE,
172 /// Do not make pages in this range available to the child after a `fork(2)`.
173 #[cfg(any(target_os = "android", target_os = "linux"))]
174 MADV_DONTFORK,
175 /// Undo the effect of `MADV_DONTFORK`.
176 #[cfg(any(target_os = "android", target_os = "linux"))]
177 MADV_DOFORK,
178 /// Poison the given pages.
179 ///
180 /// Subsequent references to those pages are treated like hardware memory corruption.
181 #[cfg(any(target_os = "android", target_os = "linux"))]
182 MADV_HWPOISON,
183 /// Enable Kernel Samepage Merging (KSM) for the given pages.
184 #[cfg(any(target_os = "android", target_os = "linux"))]
185 MADV_MERGEABLE,
186 /// Undo the effect of `MADV_MERGEABLE`
187 #[cfg(any(target_os = "android", target_os = "linux"))]
188 MADV_UNMERGEABLE,
189 /// Preserve the memory of each page but offline the original page.
190 #[cfg(any(target_os = "android",
191 all(target_os = "linux", any(
192 target_arch = "aarch64",
193 target_arch = "arm",
194 target_arch = "ppc",
195 target_arch = "s390x",
196 target_arch = "x86",
197 target_arch = "x86_64",
198 target_arch = "sparc64"))))]
199 MADV_SOFT_OFFLINE,
200 /// Enable Transparent Huge Pages (THP) for pages in the given range.
201 #[cfg(any(target_os = "android", target_os = "linux"))]
202 MADV_HUGEPAGE,
203 /// Undo the effect of `MADV_HUGEPAGE`.
204 #[cfg(any(target_os = "android", target_os = "linux"))]
205 MADV_NOHUGEPAGE,
206 /// Exclude the given range from a core dump.
207 #[cfg(any(target_os = "android", target_os = "linux"))]
208 MADV_DONTDUMP,
209 /// Undo the effect of an earlier `MADV_DONTDUMP`.
210 #[cfg(any(target_os = "android", target_os = "linux"))]
211 MADV_DODUMP,
212 /// Specify that the application no longer needs the pages in the given range.
213 MADV_FREE,
214 /// Request that the system not flush the current range to disk unless it needs to.
215 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
216 MADV_NOSYNC,
217 /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
218 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
219 MADV_AUTOSYNC,
220 /// Region is not included in a core file.
221 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
222 MADV_NOCORE,
223 /// Include region in a core file
224 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
225 MADV_CORE,
226 #[cfg(any(target_os = "freebsd"))]
227 MADV_PROTECT,
228 /// Invalidate the hardware page table for the given region.
229 #[cfg(target_os = "dragonfly")]
230 MADV_INVAL,
231 /// Set the offset of the page directory page to `value` for the virtual page table.
232 #[cfg(target_os = "dragonfly")]
233 MADV_SETMAP,
234 /// Indicates that the application will not need the data in the given range.
235 #[cfg(any(target_os = "ios", target_os = "macos"))]
236 MADV_ZERO_WIRED_PAGES,
237 #[cfg(any(target_os = "ios", target_os = "macos"))]
238 MADV_FREE_REUSABLE,
239 #[cfg(any(target_os = "ios", target_os = "macos"))]
240 MADV_FREE_REUSE,
241 #[cfg(any(target_os = "ios", target_os = "macos"))]
242 MADV_CAN_REUSE,
243 }
244 }
245
246 libc_bitflags!{
247 /// Configuration flags for `msync`.
248 pub struct MsFlags: c_int {
249 /// Schedule an update but return immediately.
250 MS_ASYNC;
251 /// Invalidate all cached data.
252 MS_INVALIDATE;
253 /// Invalidate pages, but leave them mapped.
254 #[cfg(any(target_os = "ios", target_os = "macos"))]
255 MS_KILLPAGES;
256 /// Deactivate pages, but leave them mapped.
257 #[cfg(any(target_os = "ios", target_os = "macos"))]
258 MS_DEACTIVATE;
259 /// Perform an update and wait for it to complete.
260 MS_SYNC;
261 }
262 }
263
264 libc_bitflags!{
265 /// Flags for `mlockall`.
266 pub struct MlockAllFlags: c_int {
267 /// Lock pages that are currently mapped into the address space of the process.
268 MCL_CURRENT;
269 /// Lock pages which will become mapped into the address space of the process in the future.
270 MCL_FUTURE;
271 }
272 }
273
274 /// Locks all memory pages that contain part of the address range with `length`
275 /// bytes starting at `addr`.
276 ///
277 /// Locked pages never move to the swap area.
278 ///
279 /// # Safety
280 ///
281 /// `addr` must meet all the requirements described in the `mlock(2)` man page.
mlock(addr: *const c_void, length: size_t) -> Result<()>282 pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
283 Errno::result(libc::mlock(addr, length)).map(drop)
284 }
285
286 /// Unlocks all memory pages that contain part of the address range with
287 /// `length` bytes starting at `addr`.
288 ///
289 /// # Safety
290 ///
291 /// `addr` must meet all the requirements described in the `munlock(2)` man
292 /// page.
munlock(addr: *const c_void, length: size_t) -> Result<()>293 pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
294 Errno::result(libc::munlock(addr, length)).map(drop)
295 }
296
297 /// Locks all memory pages mapped into this process' address space.
298 ///
299 /// Locked pages never move to the swap area.
300 ///
301 /// # Safety
302 ///
303 /// `addr` must meet all the requirements described in the `mlockall(2)` man
304 /// page.
mlockall(flags: MlockAllFlags) -> Result<()>305 pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
306 unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
307 }
308
309 /// Unlocks all memory pages mapped into this process' address space.
munlockall() -> Result<()>310 pub fn munlockall() -> Result<()> {
311 unsafe { Errno::result(libc::munlockall()) }.map(drop)
312 }
313
314 /// allocate memory, or map files or devices into memory
315 ///
316 /// # Safety
317 ///
318 /// See the `mmap(2)` man page for detailed requirements.
mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void>319 pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
320 let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
321
322 if ret == libc::MAP_FAILED {
323 Err(Error::from(Errno::last()))
324 } else {
325 Ok(ret)
326 }
327 }
328
329 /// Expands (or shrinks) an existing memory mapping, potentially moving it at
330 /// the same time.
331 ///
332 /// # Safety
333 ///
334 /// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
335 /// detailed requirements.
336 #[cfg(target_os = "linux")]
mremap( addr: *mut c_void, old_size: size_t, new_size: size_t, flags: MRemapFlags, new_address: Option<* mut c_void>, ) -> Result<*mut c_void>337 pub unsafe fn mremap(
338 addr: *mut c_void,
339 old_size: size_t,
340 new_size: size_t,
341 flags: MRemapFlags,
342 new_address: Option<* mut c_void>,
343 ) -> Result<*mut c_void> {
344 let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
345
346 if ret == libc::MAP_FAILED {
347 Err(Error::from(Errno::last()))
348 } else {
349 Ok(ret)
350 }
351 }
352
353 /// remove a mapping
354 ///
355 /// # Safety
356 ///
357 /// `addr` must meet all the requirements described in the `munmap(2)` man
358 /// page.
munmap(addr: *mut c_void, len: size_t) -> Result<()>359 pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
360 Errno::result(libc::munmap(addr, len)).map(drop)
361 }
362
363 /// give advice about use of memory
364 ///
365 /// # Safety
366 ///
367 /// See the `madvise(2)` man page. Take special care when using
368 /// `MmapAdvise::MADV_FREE`.
madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()>369 pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
370 Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
371 }
372
373 /// Set protection of memory mapping.
374 ///
375 /// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for
376 /// details.
377 ///
378 /// # Safety
379 ///
380 /// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to
381 /// SIGSEGVs.
382 ///
383 /// ```
384 /// # use nix::libc::size_t;
385 /// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
386 /// # use std::ptr;
387 /// const ONE_K: size_t = 1024;
388 /// let mut slice: &mut [u8] = unsafe {
389 /// let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE,
390 /// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
391 /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
392 /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
393 /// };
394 /// assert_eq!(slice[0], 0x00);
395 /// slice[0] = 0xFF;
396 /// assert_eq!(slice[0], 0xFF);
397 /// ```
mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()>398 pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> {
399 Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
400 }
401
402 /// synchronize a mapped region
403 ///
404 /// # Safety
405 ///
406 /// `addr` must meet all the requirements described in the `msync(2)` man
407 /// page.
msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()>408 pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
409 Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
410 }
411
412 #[cfg(not(target_os = "android"))]
shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd>413 pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
414 let ret = name.with_nix_path(|cstr| {
415 #[cfg(any(target_os = "macos", target_os = "ios"))]
416 unsafe {
417 libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
418 }
419 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
420 unsafe {
421 libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
422 }
423 })?;
424
425 Errno::result(ret)
426 }
427
428 #[cfg(not(target_os = "android"))]
shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()>429 pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
430 let ret = name.with_nix_path(|cstr| {
431 unsafe { libc::shm_unlink(cstr.as_ptr()) }
432 })?;
433
434 Errno::result(ret).map(drop)
435 }
436