Coverage Report

Created: 2026-03-28 06:55

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