Coverage Report

Created: 2025-02-25 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.29.0/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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?
214
    fn is_empty(&self) -> bool;
215
216
    /// Length of the path in bytes
217
    fn len(&self) -> usize;
218
219
    /// Execute a function with this path as a `CStr`.
220
    ///
221
    /// Mostly used internally by Nix.
222
    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 {
228
0
    fn is_empty(&self) -> bool {
229
0
        NixPath::is_empty(OsStr::new(self))
230
0
    }
231
232
0
    fn len(&self) -> usize {
233
0
        NixPath::len(OsStr::new(self))
234
0
    }
235
236
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
237
0
    where
238
0
        F: FnOnce(&CStr) -> T,
239
0
    {
240
0
        OsStr::new(self).with_nix_path(f)
241
0
    }
242
}
243
244
impl NixPath for OsStr {
245
0
    fn is_empty(&self) -> bool {
246
0
        self.as_bytes().is_empty()
247
0
    }
248
249
0
    fn len(&self) -> usize {
250
0
        self.as_bytes().len()
251
0
    }
252
253
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
254
0
    where
255
0
        F: FnOnce(&CStr) -> T,
256
0
    {
257
0
        self.as_bytes().with_nix_path(f)
258
0
    }
Unexecuted instantiation: <std::ffi::os_str::OsStr as nix::NixPath>::with_nix_path::<core::result::Result<nix::sys::socket::addr::UnixAddr, nix::errno::consts::Errno>, <nix::sys::socket::addr::UnixAddr>::new<std::path::Path>::{closure#0}>
Unexecuted instantiation: <std::ffi::os_str::OsStr as nix::NixPath>::with_nix_path::<_, _>
259
}
260
261
impl NixPath for CStr {
262
0
    fn is_empty(&self) -> bool {
263
0
        self.to_bytes().is_empty()
264
0
    }
265
266
0
    fn len(&self) -> usize {
267
0
        self.to_bytes().len()
268
0
    }
269
270
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
271
0
    where
272
0
        F: FnOnce(&CStr) -> T,
273
0
    {
274
0
        Ok(f(self))
275
0
    }
276
}
277
278
impl NixPath for [u8] {
279
0
    fn is_empty(&self) -> bool {
280
0
        self.is_empty()
281
0
    }
282
283
0
    fn len(&self) -> usize {
284
0
        self.len()
285
0
    }
286
287
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
288
0
    where
289
0
        F: FnOnce(&CStr) -> T,
290
0
    {
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
0
        if self.len() >= MAX_STACK_ALLOCATION {
300
0
            return with_nix_path_allocating(self, f);
301
0
        }
302
0
303
0
        let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
304
0
        let buf_ptr = buf.as_mut_ptr().cast();
305
0
306
0
        unsafe {
307
0
            ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
308
0
            buf_ptr.add(self.len()).write(0);
309
0
        }
310
0
311
0
        match CStr::from_bytes_with_nul(unsafe {
312
0
            slice::from_raw_parts(buf_ptr, self.len() + 1)
313
0
        }) {
314
0
            Ok(s) => Ok(f(s)),
315
0
            Err(_) => Err(Errno::EINVAL),
316
        }
317
0
    }
Unexecuted instantiation: <[u8] as nix::NixPath>::with_nix_path::<core::result::Result<nix::sys::socket::addr::UnixAddr, nix::errno::consts::Errno>, <nix::sys::socket::addr::UnixAddr>::new<std::path::Path>::{closure#0}>
Unexecuted instantiation: <[u8] as nix::NixPath>::with_nix_path::<_, _>
318
}
319
320
#[cold]
321
#[inline(never)]
322
0
fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
323
0
where
324
0
    F: FnOnce(&CStr) -> T,
325
0
{
326
0
    match CString::new(from) {
327
0
        Ok(s) => Ok(f(&s)),
328
0
        Err(_) => Err(Errno::EINVAL),
329
    }
330
0
}
Unexecuted instantiation: nix::with_nix_path_allocating::<core::result::Result<nix::sys::socket::addr::UnixAddr, nix::errno::consts::Errno>, <nix::sys::socket::addr::UnixAddr>::new<std::path::Path>::{closure#0}>
Unexecuted instantiation: nix::with_nix_path_allocating::<_, _>
331
332
impl NixPath for Path {
333
0
    fn is_empty(&self) -> bool {
334
0
        NixPath::is_empty(self.as_os_str())
335
0
    }
336
337
0
    fn len(&self) -> usize {
338
0
        NixPath::len(self.as_os_str())
339
0
    }
340
341
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
342
0
    where
343
0
        F: FnOnce(&CStr) -> T,
344
0
    {
345
0
        self.as_os_str().with_nix_path(f)
346
0
    }
Unexecuted instantiation: <std::path::Path as nix::NixPath>::with_nix_path::<core::result::Result<nix::sys::socket::addr::UnixAddr, nix::errno::consts::Errno>, <nix::sys::socket::addr::UnixAddr>::new<std::path::Path>::{closure#0}>
Unexecuted instantiation: <std::path::Path as nix::NixPath>::with_nix_path::<_, _>
347
}
348
349
impl NixPath for PathBuf {
350
0
    fn is_empty(&self) -> bool {
351
0
        NixPath::is_empty(self.as_os_str())
352
0
    }
353
354
0
    fn len(&self) -> usize {
355
0
        NixPath::len(self.as_os_str())
356
0
    }
357
358
0
    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
359
0
    where
360
0
        F: FnOnce(&CStr) -> T,
361
0
    {
362
0
        self.as_os_str().with_nix_path(f)
363
0
    }
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
))]
373
0
pub(crate) fn with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T>
374
0
where
375
0
    P: ?Sized + NixPath,
376
0
    F: FnOnce(*const libc::c_char) -> T,
377
0
{
378
0
    match path {
379
0
        Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
380
0
        None => Ok(f(ptr::null())),
381
    }
382
0
}