1#![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(not(feature = "default"), allow(unused_imports))]
51#![deny(unstable_features)]
52#![deny(missing_copy_implementations)]
53#![deny(missing_debug_implementations)]
54#![warn(missing_docs)]
55#![cfg_attr(docsrs, feature(doc_cfg))]
56#![deny(clippy::cast_ptr_alignment)]
57
58pub use libc;
60
61#[macro_use]
63mod macros;
64
65#[cfg(not(target_os = "redox"))]
67feature! {
68 #![feature = "dir"]
69 pub mod dir;
70}
71feature! {
72 #![feature = "env"]
73 pub mod env;
74}
75#[allow(missing_docs)]
76pub mod errno;
77feature! {
78 #![feature = "feature"]
79
80 #[deny(missing_docs)]
81 pub mod features;
82}
83#[allow(missing_docs)]
84pub mod fcntl;
85feature! {
86 #![feature = "net"]
87
88 #[cfg(any(target_os = "android",
89 target_os = "dragonfly",
90 target_os = "freebsd",
91 target_os = "ios",
92 target_os = "linux",
93 target_os = "macos",
94 target_os = "netbsd",
95 target_os = "illumos",
96 target_os = "openbsd"))]
97 #[deny(missing_docs)]
98 pub mod ifaddrs;
99 #[cfg(not(target_os = "redox"))]
100 #[deny(missing_docs)]
101 pub mod net;
102}
103#[cfg(any(target_os = "android", target_os = "linux"))]
104feature! {
105 #![feature = "kmod"]
106 #[allow(missing_docs)]
107 pub mod kmod;
108}
109feature! {
110 #![feature = "mount"]
111 pub mod mount;
112}
113#[cfg(any(
114 target_os = "dragonfly",
115 target_os = "freebsd",
116 target_os = "linux",
117 target_os = "netbsd"
118))]
119feature! {
120 #![feature = "mqueue"]
121 pub mod mqueue;
122}
123feature! {
124 #![feature = "poll"]
125 pub mod poll;
126}
127#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
128feature! {
129 #![feature = "term"]
130 #[deny(missing_docs)]
131 pub mod pty;
132}
133feature! {
134 #![feature = "sched"]
135 pub mod sched;
136}
137pub mod sys;
138feature! {
139 #![feature = "time"]
140 #[allow(missing_docs)]
141 pub mod time;
142}
143#[cfg(all(
146 target_os = "linux",
147 any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64")
148))]
149feature! {
150 #![feature = "ucontext"]
151 #[allow(missing_docs)]
152 pub mod ucontext;
153}
154#[allow(missing_docs)]
155pub mod unistd;
156
157use std::ffi::{CStr, CString, OsStr};
158use std::mem::MaybeUninit;
159use std::os::unix::ffi::OsStrExt;
160use std::path::{Path, PathBuf};
161use std::{ptr, result, slice};
162
163use errno::Errno;
164
165pub type Result<T> = result::Result<T, Errno>;
167
168pub type Error = Errno;
179
180pub trait NixPath {
182 fn is_empty(&self) -> bool;
184
185 fn len(&self) -> usize;
187
188 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
192 where
193 F: FnOnce(&CStr) -> T;
194}
195
196impl NixPath for str {
197 fn is_empty(&self) -> bool {
198 NixPath::is_empty(OsStr::new(self))
199 }
200
201 fn len(&self) -> usize {
202 NixPath::len(OsStr::new(self))
203 }
204
205 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
206 where
207 F: FnOnce(&CStr) -> T,
208 {
209 OsStr::new(self).with_nix_path(f)
210 }
211}
212
213impl NixPath for OsStr {
214 fn is_empty(&self) -> bool {
215 self.as_bytes().is_empty()
216 }
217
218 fn len(&self) -> usize {
219 self.as_bytes().len()
220 }
221
222 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
223 where
224 F: FnOnce(&CStr) -> T,
225 {
226 self.as_bytes().with_nix_path(f)
227 }
228}
229
230impl NixPath for CStr {
231 fn is_empty(&self) -> bool {
232 self.to_bytes().is_empty()
233 }
234
235 fn len(&self) -> usize {
236 self.to_bytes().len()
237 }
238
239 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
240 where
241 F: FnOnce(&CStr) -> T,
242 {
243 Ok(f(self))
244 }
245}
246
247impl NixPath for [u8] {
248 fn is_empty(&self) -> bool {
249 self.is_empty()
250 }
251
252 fn len(&self) -> usize {
253 self.len()
254 }
255
256 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
257 where
258 F: FnOnce(&CStr) -> T,
259 {
260 const MAX_STACK_ALLOCATION: usize = 1024;
267
268 if self.len() >= MAX_STACK_ALLOCATION {
269 return with_nix_path_allocating(self, f);
270 }
271
272 let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
273 let buf_ptr = buf.as_mut_ptr() as *mut u8;
274
275 unsafe {
276 ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
277 buf_ptr.add(self.len()).write(0);
278 }
279
280 match CStr::from_bytes_with_nul(unsafe {
281 slice::from_raw_parts(buf_ptr, self.len() + 1)
282 }) {
283 Ok(s) => Ok(f(s)),
284 Err(_) => Err(Errno::EINVAL),
285 }
286 }
287}
288
289#[cold]
290#[inline(never)]
291fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
292where
293 F: FnOnce(&CStr) -> T,
294{
295 match CString::new(from) {
296 Ok(s) => Ok(f(&s)),
297 Err(_) => Err(Errno::EINVAL),
298 }
299}
300
301impl NixPath for Path {
302 fn is_empty(&self) -> bool {
303 NixPath::is_empty(self.as_os_str())
304 }
305
306 fn len(&self) -> usize {
307 NixPath::len(self.as_os_str())
308 }
309
310 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
311 where
312 F: FnOnce(&CStr) -> T,
313 {
314 self.as_os_str().with_nix_path(f)
315 }
316}
317
318impl NixPath for PathBuf {
319 fn is_empty(&self) -> bool {
320 NixPath::is_empty(self.as_os_str())
321 }
322
323 fn len(&self) -> usize {
324 NixPath::len(self.as_os_str())
325 }
326
327 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
328 where
329 F: FnOnce(&CStr) -> T,
330 {
331 self.as_os_str().with_nix_path(f)
332 }
333}