1#![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
96pub use libc;
98
99#[macro_use]
101mod macros;
102
103#[cfg(not(target_os = "redox"))]
105feature! {
106 #![feature = "dir"]
107 pub mod dir;
108}
109feature! {
110 #![feature = "env"]
111 pub mod env;
112}
113#[allow(missing_docs)]
114pub mod errno;
115feature! {
116 #![feature = "feature"]
117
118 #[deny(missing_docs)]
119 pub mod features;
120}
121pub mod fcntl;
122feature! {
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)]
135feature! {
136 #![feature = "kmod"]
137 pub mod kmod;
138}
139feature! {
140 #![feature = "mount"]
141 pub mod mount;
142}
143#[cfg(any(freebsdlike, target_os = "linux", target_os = "netbsd"))]
144feature! {
145 #![feature = "mqueue"]
146 pub mod mqueue;
147}
148feature! {
149 #![feature = "poll"]
150 pub mod poll;
151}
152#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
153feature! {
154 #![feature = "term"]
155 #[deny(missing_docs)]
156 pub mod pty;
157}
158feature! {
159 #![feature = "sched"]
160 pub mod sched;
161}
162pub mod sys;
163feature! {
164 #![feature = "time"]
165 pub mod time;
166}
167#[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))]
178feature! {
179 #![feature = "ucontext"]
180 #[allow(missing_docs)]
181 pub mod ucontext;
182}
183pub mod unistd;
184
185#[cfg(any(feature = "poll", feature = "event"))]
186mod poll_timeout;
187
188use std::ffi::{CStr, CString, OsStr};
189use std::mem::MaybeUninit;
190use std::os::unix::ffi::OsStrExt;
191use std::path::{Path, PathBuf};
192use std::{ptr, result, slice};
193
194use errno::Errno;
195
196pub type Result<T> = result::Result<T, Errno>;
198
199pub type Error = Errno;
210
211pub trait NixPath {
213 fn is_empty(&self) -> bool;
215
216 fn len(&self) -> usize;
218
219 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
223 where
224 F: FnOnce(&CStr) -> T;
225}
226
227impl NixPath for str {
228 fn is_empty(&self) -> bool {
229 NixPath::is_empty(OsStr::new(self))
230 }
231
232 fn len(&self) -> usize {
233 NixPath::len(OsStr::new(self))
234 }
235
236 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
237 where
238 F: FnOnce(&CStr) -> T,
239 {
240 OsStr::new(self).with_nix_path(f)
241 }
242}
243
244impl NixPath for OsStr {
245 fn is_empty(&self) -> bool {
246 self.as_bytes().is_empty()
247 }
248
249 fn len(&self) -> usize {
250 self.as_bytes().len()
251 }
252
253 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
254 where
255 F: FnOnce(&CStr) -> T,
256 {
257 self.as_bytes().with_nix_path(f)
258 }
259}
260
261impl NixPath for CStr {
262 fn is_empty(&self) -> bool {
263 self.to_bytes().is_empty()
264 }
265
266 fn len(&self) -> usize {
267 self.to_bytes().len()
268 }
269
270 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
271 where
272 F: FnOnce(&CStr) -> T,
273 {
274 Ok(f(self))
275 }
276}
277
278impl NixPath for [u8] {
279 fn is_empty(&self) -> bool {
280 self.is_empty()
281 }
282
283 fn len(&self) -> usize {
284 self.len()
285 }
286
287 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
288 where
289 F: FnOnce(&CStr) -> T,
290 {
291 const MAX_STACK_ALLOCATION: usize = 1024;
298
299 if self.len() >= MAX_STACK_ALLOCATION {
300 return with_nix_path_allocating(self, f);
301 }
302
303 let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
304 let buf_ptr = buf.as_mut_ptr().cast();
305
306 unsafe {
307 ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
308 buf_ptr.add(self.len()).write(0);
309 }
310
311 match CStr::from_bytes_with_nul(unsafe {
312 slice::from_raw_parts(buf_ptr, self.len() + 1)
313 }) {
314 Ok(s) => Ok(f(s)),
315 Err(_) => Err(Errno::EINVAL),
316 }
317 }
318}
319
320#[cold]
321#[inline(never)]
322fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
323where
324 F: FnOnce(&CStr) -> T,
325{
326 match CString::new(from) {
327 Ok(s) => Ok(f(&s)),
328 Err(_) => Err(Errno::EINVAL),
329 }
330}
331
332impl NixPath for Path {
333 fn is_empty(&self) -> bool {
334 NixPath::is_empty(self.as_os_str())
335 }
336
337 fn len(&self) -> usize {
338 NixPath::len(self.as_os_str())
339 }
340
341 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
342 where
343 F: FnOnce(&CStr) -> T,
344 {
345 self.as_os_str().with_nix_path(f)
346 }
347}
348
349impl NixPath for PathBuf {
350 fn is_empty(&self) -> bool {
351 NixPath::is_empty(self.as_os_str())
352 }
353
354 fn len(&self) -> usize {
355 NixPath::len(self.as_os_str())
356 }
357
358 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
359 where
360 F: FnOnce(&CStr) -> T,
361 {
362 self.as_os_str().with_nix_path(f)
363 }
364}
365
366#[cfg(any(
370 all(apple_targets, feature = "mount"),
371 all(linux_android, any(feature = "mount", feature = "fanotify"))
372))]
373pub(crate) fn with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T>
374where
375 P: ?Sized + NixPath,
376 F: FnOnce(*const libc::c_char) -> T,
377{
378 match path {
379 Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
380 None => Ok(f(ptr::null())),
381 }
382}