• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Rust friendly bindings to the various *nix system functions.
2 //!
3 //! Modules are structured according to the C header file that they would be
4 //! defined in.
5 //!
6 //! # Features
7 //!
8 //! Nix uses the following Cargo features to enable optional functionality.
9 //! They may be enabled in any combination.
10 //! * `acct` - Process accounting
11 //! * `aio` - POSIX AIO
12 //! * `dir` - Stuff relating to directory iteration
13 //! * `env` - Manipulate environment variables
14 //! * `event` - Event-driven APIs, like `kqueue` and `epoll`
15 //! * `fanotify` - Linux's `fanotify` filesystem events monitoring API
16 //! * `feature` - Query characteristics of the OS at runtime
17 //! * `fs` - File system functionality
18 //! * `hostname` - Get and set the system's hostname
19 //! * `inotify` - Linux's `inotify` file system notification API
20 //! * `ioctl` - The `ioctl` syscall, and wrappers for many specific instances
21 //! * `kmod` - Load and unload kernel modules
22 //! * `mman` - Stuff relating to memory management
23 //! * `mount` - Mount and unmount file systems
24 //! * `mqueue` - POSIX message queues
25 //! * `net` - Networking-related functionality
26 //! * `personality` - Set the process execution domain
27 //! * `poll` - APIs like `poll` and `select`
28 //! * `process` - Stuff relating to running processes
29 //! * `pthread` - POSIX threads
30 //! * `ptrace` - Process tracing and debugging
31 //! * `quota` - File system quotas
32 //! * `reboot` - Reboot the system
33 //! * `resource` - Process resource limits
34 //! * `sched` - Manipulate process's scheduling
35 //! * `socket` - Sockets, whether for networking or local use
36 //! * `signal` - Send and receive signals to processes
37 //! * `term` - Terminal control APIs
38 //! * `time` - Query the operating system's clocks
39 //! * `ucontext` - User thread context
40 //! * `uio` - Vectored I/O
41 //! * `user` - Stuff relating to users and groups
42 //! * `zerocopy` - APIs like `sendfile` and `copy_file_range`
43 #![crate_name = "nix"]
44 #![cfg(unix)]
45 #![allow(non_camel_case_types)]
46 #![cfg_attr(test, deny(warnings))]
47 #![recursion_limit = "500"]
48 #![deny(unused)]
49 #![allow(unused_macros)]
50 #![cfg_attr(
51     not(all(
52         feature = "acct",
53         feature = "aio",
54         feature = "dir",
55         feature = "env",
56         feature = "event",
57         feature = "fanotify",
58         feature = "feature",
59         feature = "fs",
60         feature = "hostname",
61         feature = "inotify",
62         feature = "ioctl",
63         feature = "kmod",
64         feature = "mman",
65         feature = "mount",
66         feature = "mqueue",
67         feature = "net",
68         feature = "personality",
69         feature = "poll",
70         feature = "process",
71         feature = "pthread",
72         feature = "ptrace",
73         feature = "quota",
74         feature = "reboot",
75         feature = "resource",
76         feature = "sched",
77         feature = "socket",
78         feature = "signal",
79         feature = "term",
80         feature = "time",
81         feature = "ucontext",
82         feature = "uio",
83         feature = "user",
84         feature = "zerocopy",
85     )),
86     allow(unused_imports)
87 )]
88 #![deny(unstable_features)]
89 #![deny(missing_copy_implementations)]
90 #![deny(missing_debug_implementations)]
91 #![warn(missing_docs)]
92 #![cfg_attr(docsrs, feature(doc_cfg))]
93 #![deny(clippy::cast_ptr_alignment)]
94 #![deny(unsafe_op_in_unsafe_fn)]
95 
96 // Re-exported external crates
97 pub use libc;
98 
99 // Private internal modules
100 #[macro_use]
101 mod macros;
102 
103 // Public crates
104 #[cfg(not(target_os = "redox"))]
105 feature! {
106     #![feature = "dir"]
107     pub mod dir;
108 }
109 feature! {
110     #![feature = "env"]
111     pub mod env;
112 }
113 #[allow(missing_docs)]
114 pub mod errno;
115 feature! {
116     #![feature = "feature"]
117 
118     #[deny(missing_docs)]
119     pub mod features;
120 }
121 pub mod fcntl;
122 feature! {
123     #![feature = "net"]
124 
125     #[cfg(any(linux_android,
126               bsd,
127               solarish))]
128     #[deny(missing_docs)]
129     pub mod ifaddrs;
130     #[cfg(not(target_os = "redox"))]
131     #[deny(missing_docs)]
132     pub mod net;
133 }
134 #[cfg(linux_android)]
135 feature! {
136     #![feature = "kmod"]
137     pub mod kmod;
138 }
139 feature! {
140     #![feature = "mount"]
141     pub mod mount;
142 }
143 #[cfg(any(freebsdlike, target_os = "linux", target_os = "netbsd"))]
144 feature! {
145     #![feature = "mqueue"]
146     pub mod mqueue;
147 }
148 feature! {
149     #![feature = "poll"]
150     pub mod poll;
151 }
152 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
153 feature! {
154     #![feature = "term"]
155     #[deny(missing_docs)]
156     pub mod pty;
157 }
158 feature! {
159     #![feature = "sched"]
160     pub mod sched;
161 }
162 pub mod sys;
163 feature! {
164     #![feature = "time"]
165     pub mod time;
166 }
167 // This can be implemented for other platforms as soon as libc
168 // provides bindings for them.
169 #[cfg(all(
170     target_os = "linux",
171     any(
172         target_arch = "aarch64",
173         target_arch = "s390x",
174         target_arch = "x86",
175         target_arch = "x86_64"
176     )
177 ))]
178 feature! {
179     #![feature = "ucontext"]
180     #[allow(missing_docs)]
181     pub mod ucontext;
182 }
183 pub mod unistd;
184 
185 #[cfg(any(feature = "poll", feature = "event"))]
186 mod poll_timeout;
187 
188 use std::ffi::{CStr, CString, OsStr};
189 use std::mem::MaybeUninit;
190 use std::os::unix::ffi::OsStrExt;
191 use std::path::{Path, PathBuf};
192 use std::{ptr, result, slice};
193 
194 use errno::Errno;
195 
196 /// Nix Result Type
197 pub type Result<T> = result::Result<T, Errno>;
198 
199 /// Nix's main error type.
200 ///
201 /// It's a wrapper around Errno.  As such, it's very interoperable with
202 /// [`std::io::Error`], but it has the advantages of:
203 /// * `Clone`
204 /// * `Copy`
205 /// * `Eq`
206 /// * Small size
207 /// * Represents all of the system's errnos, instead of just the most common
208 /// ones.
209 pub type Error = Errno;
210 
211 /// Common trait used to represent file system paths by many Nix functions.
212 pub trait NixPath {
213     /// Is the path empty?
is_empty(&self) -> bool214     fn is_empty(&self) -> bool;
215 
216     /// Length of the path in bytes
len(&self) -> usize217     fn len(&self) -> usize;
218 
219     /// Execute a function with this path as a `CStr`.
220     ///
221     /// Mostly used internally by Nix.
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T222     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
223     where
224         F: FnOnce(&CStr) -> T;
225 }
226 
227 impl NixPath for str {
is_empty(&self) -> bool228     fn is_empty(&self) -> bool {
229         NixPath::is_empty(OsStr::new(self))
230     }
231 
len(&self) -> usize232     fn len(&self) -> usize {
233         NixPath::len(OsStr::new(self))
234     }
235 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,236     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
237     where
238         F: FnOnce(&CStr) -> T,
239     {
240         OsStr::new(self).with_nix_path(f)
241     }
242 }
243 
244 impl NixPath for OsStr {
is_empty(&self) -> bool245     fn is_empty(&self) -> bool {
246         self.as_bytes().is_empty()
247     }
248 
len(&self) -> usize249     fn len(&self) -> usize {
250         self.as_bytes().len()
251     }
252 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,253     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
254     where
255         F: FnOnce(&CStr) -> T,
256     {
257         self.as_bytes().with_nix_path(f)
258     }
259 }
260 
261 impl NixPath for CStr {
is_empty(&self) -> bool262     fn is_empty(&self) -> bool {
263         self.to_bytes().is_empty()
264     }
265 
len(&self) -> usize266     fn len(&self) -> usize {
267         self.to_bytes().len()
268     }
269 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,270     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
271     where
272         F: FnOnce(&CStr) -> T,
273     {
274         Ok(f(self))
275     }
276 }
277 
278 impl NixPath for [u8] {
is_empty(&self) -> bool279     fn is_empty(&self) -> bool {
280         self.is_empty()
281     }
282 
len(&self) -> usize283     fn len(&self) -> usize {
284         self.len()
285     }
286 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,287     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
288     where
289         F: FnOnce(&CStr) -> T,
290     {
291         // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path
292         // longer than ~300 bytes. See the the PR description to get stats for your own machine.
293         // https://github.com/nix-rust/nix/pull/1656
294         //
295         // By being smaller than a memory page, we also avoid the compiler inserting a probe frame:
296         // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html
297         const MAX_STACK_ALLOCATION: usize = 1024;
298 
299         if self.len() >= MAX_STACK_ALLOCATION {
300             return with_nix_path_allocating(self, f);
301         }
302 
303         let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
304         let buf_ptr = buf.as_mut_ptr().cast();
305 
306         unsafe {
307             ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
308             buf_ptr.add(self.len()).write(0);
309         }
310 
311         match CStr::from_bytes_with_nul(unsafe {
312             slice::from_raw_parts(buf_ptr, self.len() + 1)
313         }) {
314             Ok(s) => Ok(f(s)),
315             Err(_) => Err(Errno::EINVAL),
316         }
317     }
318 }
319 
320 #[cold]
321 #[inline(never)]
with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T> where F: FnOnce(&CStr) -> T,322 fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
323 where
324     F: FnOnce(&CStr) -> T,
325 {
326     match CString::new(from) {
327         Ok(s) => Ok(f(&s)),
328         Err(_) => Err(Errno::EINVAL),
329     }
330 }
331 
332 impl NixPath for Path {
is_empty(&self) -> bool333     fn is_empty(&self) -> bool {
334         NixPath::is_empty(self.as_os_str())
335     }
336 
len(&self) -> usize337     fn len(&self) -> usize {
338         NixPath::len(self.as_os_str())
339     }
340 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,341     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
342     where
343         F: FnOnce(&CStr) -> T,
344     {
345         self.as_os_str().with_nix_path(f)
346     }
347 }
348 
349 impl NixPath for PathBuf {
is_empty(&self) -> bool350     fn is_empty(&self) -> bool {
351         NixPath::is_empty(self.as_os_str())
352     }
353 
len(&self) -> usize354     fn len(&self) -> usize {
355         NixPath::len(self.as_os_str())
356     }
357 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T,358     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
359     where
360         F: FnOnce(&CStr) -> T,
361     {
362         self.as_os_str().with_nix_path(f)
363     }
364 }
365 
366 /// Like `NixPath::with_nix_path()`, but allow the `path` argument to be optional.
367 ///
368 /// A NULL pointer will be provided if `path.is_none()`.
369 #[cfg(any(
370     all(apple_targets, feature = "mount"),
371     all(linux_android, any(feature = "mount", feature = "fanotify"))
372 ))]
with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T> where P: ?Sized + NixPath, F: FnOnce(*const libc::c_char) -> T,373 pub(crate) fn with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T>
374 where
375     P: ?Sized + NixPath,
376     F: FnOnce(*const libc::c_char) -> T,
377 {
378     match path {
379         Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
380         None => Ok(f(ptr::null())),
381     }
382 }
383