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