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