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
56#![cfg_attr(docsrs, feature(doc_cfg))]
57
58pub use libc;
60
61#[macro_use] mod macros;
63
64#[cfg(not(target_os = "redox"))]
66feature! {
67 #![feature = "dir"]
68 #[allow(missing_docs)]
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",
104 target_os = "linux"))]
105feature! {
106 #![feature = "kmod"]
107 #[allow(missing_docs)]
108 pub mod kmod;
109}
110#[cfg(any(target_os = "android",
111 target_os = "freebsd",
112 target_os = "linux"))]
113feature! {
114 #![feature = "mount"]
115 pub mod mount;
116}
117#[cfg(any(target_os = "dragonfly",
118 target_os = "freebsd",
119 target_os = "fushsia",
120 target_os = "linux",
121 target_os = "netbsd"))]
122feature! {
123 #![feature = "mqueue"]
124 #[allow(missing_docs)]
125 pub mod mqueue;
126}
127feature! {
128 #![feature = "poll"]
129 pub mod poll;
130}
131#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
132feature! {
133 #![feature = "term"]
134 #[deny(missing_docs)]
135 pub mod pty;
136}
137feature! {
138 #![feature = "sched"]
139 pub mod sched;
140}
141pub mod sys;
142feature! {
143 #![feature = "time"]
144 #[allow(missing_docs)]
145 pub mod time;
146}
147#[cfg(all(target_os = "linux",
150 any(target_arch = "s390x", target_arch = "x86",
151 target_arch = "x86_64")))]
152feature! {
153 #![feature = "ucontext"]
154 #[allow(missing_docs)]
155 pub mod ucontext;
156}
157#[allow(missing_docs)]
158pub mod unistd;
159
160use std::ffi::{CStr, CString, OsStr};
161use std::mem::MaybeUninit;
162use std::os::unix::ffi::OsStrExt;
163use std::path::{Path, PathBuf};
164use std::{ptr, result, slice};
165
166use errno::Errno;
167
168pub type Result<T> = result::Result<T, Errno>;
170
171pub type Error = Errno;
182
183pub trait NixPath {
185 fn is_empty(&self) -> bool;
187
188 fn len(&self) -> usize;
190
191 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
195 where F: FnOnce(&CStr) -> T;
196}
197
198impl NixPath for str {
199 fn is_empty(&self) -> bool {
200 NixPath::is_empty(OsStr::new(self))
201 }
202
203 fn len(&self) -> usize {
204 NixPath::len(OsStr::new(self))
205 }
206
207 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
208 where F: FnOnce(&CStr) -> T {
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 F: FnOnce(&CStr) -> T {
224 self.as_bytes().with_nix_path(f)
225 }
226}
227
228impl NixPath for CStr {
229 fn is_empty(&self) -> bool {
230 self.to_bytes().is_empty()
231 }
232
233 fn len(&self) -> usize {
234 self.to_bytes().len()
235 }
236
237 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
238 where
239 F: FnOnce(&CStr) -> T,
240 {
241 Ok(f(self))
242 }
243}
244
245impl NixPath for [u8] {
246 fn is_empty(&self) -> bool {
247 self.is_empty()
248 }
249
250 fn len(&self) -> usize {
251 self.len()
252 }
253
254 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
255 where
256 F: FnOnce(&CStr) -> T,
257 {
258 const MAX_STACK_ALLOCATION: usize = 1024;
265
266 if self.len() >= MAX_STACK_ALLOCATION {
267 return with_nix_path_allocating(self, f);
268 }
269
270 let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
271 let buf_ptr = buf.as_mut_ptr() as *mut u8;
272
273 unsafe {
274 ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
275 buf_ptr.add(self.len()).write(0);
276 }
277
278 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, self.len() + 1) }) {
279 Ok(s) => Ok(f(s)),
280 Err(_) => Err(Errno::EINVAL),
281 }
282 }
283}
284
285#[cold]
286#[inline(never)]
287fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
288where
289 F: FnOnce(&CStr) -> T,
290{
291 match CString::new(from) {
292 Ok(s) => Ok(f(&s)),
293 Err(_) => Err(Errno::EINVAL),
294 }
295}
296
297impl NixPath for Path {
298 fn is_empty(&self) -> bool {
299 NixPath::is_empty(self.as_os_str())
300 }
301
302 fn len(&self) -> usize {
303 NixPath::len(self.as_os_str())
304 }
305
306 fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
307 self.as_os_str().with_nix_path(f)
308 }
309}
310
311impl NixPath for PathBuf {
312 fn is_empty(&self) -> bool {
313 NixPath::is_empty(self.as_os_str())
314 }
315
316 fn len(&self) -> usize {
317 NixPath::len(self.as_os_str())
318 }
319
320 fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
321 self.as_os_str().with_nix_path(f)
322 }
323}