1 //! Safe wrappers around functions found in libc "unistd.h" header 2 3 #[cfg(not(target_os = "redox"))] 4 use cfg_if::cfg_if; 5 use crate::errno::{self, Errno}; 6 use crate::{Error, Result, NixPath}; 7 #[cfg(not(target_os = "redox"))] 8 use crate::fcntl::{AtFlags, at_rawfd}; 9 use crate::fcntl::{FdFlag, OFlag, fcntl}; 10 use crate::fcntl::FcntlArg::F_SETFD; 11 use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, 12 uid_t, gid_t, mode_t, PATH_MAX}; 13 use std::{fmt, mem, ptr}; 14 use std::convert::Infallible; 15 use std::ffi::{CStr, OsString}; 16 #[cfg(not(target_os = "redox"))] 17 use std::ffi::{CString, OsStr}; 18 use std::os::unix::ffi::OsStringExt; 19 #[cfg(not(target_os = "redox"))] 20 use std::os::unix::ffi::OsStrExt; 21 use std::os::unix::io::RawFd; 22 use std::path::PathBuf; 23 use crate::sys::stat::Mode; 24 25 #[cfg(any(target_os = "android", target_os = "linux"))] 26 pub use self::pivot_root::*; 27 28 #[cfg(any(target_os = "android", target_os = "freebsd", 29 target_os = "linux", target_os = "openbsd"))] 30 pub use self::setres::*; 31 32 /// User identifier 33 /// 34 /// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally 35 /// passing wrong value. 36 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 37 pub struct Uid(uid_t); 38 39 impl Uid { 40 /// Creates `Uid` from raw `uid_t`. from_raw(uid: uid_t) -> Self41 pub fn from_raw(uid: uid_t) -> Self { 42 Uid(uid) 43 } 44 45 /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. current() -> Self46 pub fn current() -> Self { 47 getuid() 48 } 49 50 /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. effective() -> Self51 pub fn effective() -> Self { 52 geteuid() 53 } 54 55 /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) is_root(self) -> bool56 pub fn is_root(self) -> bool { 57 self == ROOT 58 } 59 60 /// Get the raw `uid_t` wrapped by `self`. as_raw(self) -> uid_t61 pub fn as_raw(self) -> uid_t { 62 self.0 63 } 64 } 65 66 impl From<Uid> for uid_t { from(uid: Uid) -> Self67 fn from(uid: Uid) -> Self { 68 uid.0 69 } 70 } 71 72 impl fmt::Display for Uid { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 74 fmt::Display::fmt(&self.0, f) 75 } 76 } 77 78 /// Constant for UID = 0 79 pub const ROOT: Uid = Uid(0); 80 81 /// Group identifier 82 /// 83 /// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally 84 /// passing wrong value. 85 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 86 pub struct Gid(gid_t); 87 88 impl Gid { 89 /// Creates `Gid` from raw `gid_t`. from_raw(gid: gid_t) -> Self90 pub fn from_raw(gid: gid_t) -> Self { 91 Gid(gid) 92 } 93 94 /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. current() -> Self95 pub fn current() -> Self { 96 getgid() 97 } 98 99 /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. effective() -> Self100 pub fn effective() -> Self { 101 getegid() 102 } 103 104 /// Get the raw `gid_t` wrapped by `self`. as_raw(self) -> gid_t105 pub fn as_raw(self) -> gid_t { 106 self.0 107 } 108 } 109 110 impl From<Gid> for gid_t { from(gid: Gid) -> Self111 fn from(gid: Gid) -> Self { 112 gid.0 113 } 114 } 115 116 impl fmt::Display for Gid { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 118 fmt::Display::fmt(&self.0, f) 119 } 120 } 121 122 /// Process identifier 123 /// 124 /// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally 125 /// passing wrong value. 126 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] 127 pub struct Pid(pid_t); 128 129 impl Pid { 130 /// Creates `Pid` from raw `pid_t`. from_raw(pid: pid_t) -> Self131 pub fn from_raw(pid: pid_t) -> Self { 132 Pid(pid) 133 } 134 135 /// Returns PID of calling process this() -> Self136 pub fn this() -> Self { 137 getpid() 138 } 139 140 /// Returns PID of parent of calling process parent() -> Self141 pub fn parent() -> Self { 142 getppid() 143 } 144 145 /// Get the raw `pid_t` wrapped by `self`. as_raw(self) -> pid_t146 pub fn as_raw(self) -> pid_t { 147 self.0 148 } 149 } 150 151 impl From<Pid> for pid_t { from(pid: Pid) -> Self152 fn from(pid: Pid) -> Self { 153 pid.0 154 } 155 } 156 157 impl fmt::Display for Pid { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 159 fmt::Display::fmt(&self.0, f) 160 } 161 } 162 163 164 /// Represents the successful result of calling `fork` 165 /// 166 /// When `fork` is called, the process continues execution in the parent process 167 /// and in the new child. This return type can be examined to determine whether 168 /// you are now executing in the parent process or in the child. 169 #[derive(Clone, Copy, Debug)] 170 pub enum ForkResult { 171 Parent { child: Pid }, 172 Child, 173 } 174 175 impl ForkResult { 176 177 /// Return `true` if this is the child process of the `fork()` 178 #[inline] is_child(self) -> bool179 pub fn is_child(self) -> bool { 180 match self { 181 ForkResult::Child => true, 182 _ => false 183 } 184 } 185 186 /// Returns `true` if this is the parent process of the `fork()` 187 #[inline] is_parent(self) -> bool188 pub fn is_parent(self) -> bool { 189 !self.is_child() 190 } 191 } 192 193 /// Create a new child process duplicating the parent process ([see 194 /// fork(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). 195 /// 196 /// After calling the fork system call (successfully) two processes will 197 /// be created that are identical with the exception of their pid and the 198 /// return value of this function. As an example: 199 /// 200 /// ```no_run 201 /// use nix::unistd::{fork, ForkResult}; 202 /// 203 /// match unsafe{fork()} { 204 /// Ok(ForkResult::Parent { child, .. }) => { 205 /// println!("Continuing execution in parent process, new child has pid: {}", child); 206 /// } 207 /// Ok(ForkResult::Child) => println!("I'm a new child process"), 208 /// Err(_) => println!("Fork failed"), 209 /// } 210 /// ``` 211 /// 212 /// This will print something like the following (order indeterministic). The 213 /// thing to note is that you end up with two processes continuing execution 214 /// immediately after the fork call but with different match arms. 215 /// 216 /// ```text 217 /// Continuing execution in parent process, new child has pid: 1234 218 /// I'm a new child process 219 /// ``` 220 /// 221 /// # Safety 222 /// 223 /// In a multithreaded program, only [async-signal-safe] functions like `pause` 224 /// and `_exit` may be called by the child (the parent isn't restricted). Note 225 /// that memory allocation may **not** be async-signal-safe and thus must be 226 /// prevented. 227 /// 228 /// Those functions are only a small subset of your operating system's API, so 229 /// special care must be taken to only invoke code you can control and audit. 230 /// 231 /// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html 232 #[inline] fork() -> Result<ForkResult>233 pub unsafe fn fork() -> Result<ForkResult> { 234 use self::ForkResult::*; 235 let res = libc::fork(); 236 237 Errno::result(res).map(|res| match res { 238 0 => Child, 239 res => Parent { child: Pid(res) }, 240 }) 241 } 242 243 /// Get the pid of this process (see 244 /// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). 245 /// 246 /// Since you are running code, there is always a pid to return, so there 247 /// is no error case that needs to be handled. 248 #[inline] getpid() -> Pid249 pub fn getpid() -> Pid { 250 Pid(unsafe { libc::getpid() }) 251 } 252 253 /// Get the pid of this processes' parent (see 254 /// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). 255 /// 256 /// There is always a parent pid to return, so there is no error case that needs 257 /// to be handled. 258 #[inline] getppid() -> Pid259 pub fn getppid() -> Pid { 260 Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful." 261 } 262 263 /// Set a process group ID (see 264 /// [setpgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). 265 /// 266 /// Set the process group id (PGID) of a particular process. If a pid of zero 267 /// is specified, then the pid of the calling process is used. Process groups 268 /// may be used to group together a set of processes in order for the OS to 269 /// apply some operations across the group. 270 /// 271 /// `setsid()` may be used to create a new process group. 272 #[inline] setpgid(pid: Pid, pgid: Pid) -> Result<()>273 pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { 274 let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; 275 Errno::result(res).map(drop) 276 } 277 #[inline] getpgid(pid: Option<Pid>) -> Result<Pid>278 pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { 279 let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; 280 Errno::result(res).map(Pid) 281 } 282 283 /// Create new session and set process group id (see 284 /// [setsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). 285 #[inline] setsid() -> Result<Pid>286 pub fn setsid() -> Result<Pid> { 287 Errno::result(unsafe { libc::setsid() }).map(Pid) 288 } 289 290 /// Get the process group ID of a session leader 291 /// [getsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). 292 /// 293 /// Obtain the process group ID of the process that is the session leader of the process specified 294 /// by pid. If pid is zero, it specifies the calling process. 295 #[inline] 296 #[cfg(not(target_os = "redox"))] getsid(pid: Option<Pid>) -> Result<Pid>297 pub fn getsid(pid: Option<Pid>) -> Result<Pid> { 298 let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; 299 Errno::result(res).map(Pid) 300 } 301 302 303 /// Get the terminal foreground process group (see 304 /// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). 305 /// 306 /// Get the group process id (GPID) of the foreground process group on the 307 /// terminal associated to file descriptor (FD). 308 #[inline] tcgetpgrp(fd: c_int) -> Result<Pid>309 pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { 310 let res = unsafe { libc::tcgetpgrp(fd) }; 311 Errno::result(res).map(Pid) 312 } 313 /// Set the terminal foreground process group (see 314 /// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). 315 /// 316 /// Get the group process id (PGID) to the foreground process group on the 317 /// terminal associated to file descriptor (FD). 318 #[inline] tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()>319 pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { 320 let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; 321 Errno::result(res).map(drop) 322 } 323 324 325 /// Get the group id of the calling process (see 326 ///[getpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). 327 /// 328 /// Get the process group id (PGID) of the calling process. 329 /// According to the man page it is always successful. 330 #[inline] getpgrp() -> Pid331 pub fn getpgrp() -> Pid { 332 Pid(unsafe { libc::getpgrp() }) 333 } 334 335 /// Get the caller's thread ID (see 336 /// [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html). 337 /// 338 /// This function is only available on Linux based systems. In a single 339 /// threaded process, the main thread will have the same ID as the process. In 340 /// a multithreaded process, each thread will have a unique thread id but the 341 /// same process ID. 342 /// 343 /// No error handling is required as a thread id should always exist for any 344 /// process, even if threads are not being used. 345 #[cfg(any(target_os = "linux", target_os = "android"))] 346 #[inline] gettid() -> Pid347 pub fn gettid() -> Pid { 348 Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) 349 } 350 351 /// Create a copy of the specified file descriptor (see 352 /// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). 353 /// 354 /// The new file descriptor will be have a new index but refer to the same 355 /// resource as the old file descriptor and the old and new file descriptors may 356 /// be used interchangeably. The new and old file descriptor share the same 357 /// underlying resource, offset, and file status flags. The actual index used 358 /// for the file descriptor will be the lowest fd index that is available. 359 /// 360 /// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). 361 #[inline] dup(oldfd: RawFd) -> Result<RawFd>362 pub fn dup(oldfd: RawFd) -> Result<RawFd> { 363 let res = unsafe { libc::dup(oldfd) }; 364 365 Errno::result(res) 366 } 367 368 /// Create a copy of the specified file descriptor using the specified fd (see 369 /// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). 370 /// 371 /// This function behaves similar to `dup()` except that it will try to use the 372 /// specified fd instead of allocating a new one. See the man pages for more 373 /// detail on the exact behavior of this function. 374 #[inline] dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd>375 pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { 376 let res = unsafe { libc::dup2(oldfd, newfd) }; 377 378 Errno::result(res) 379 } 380 381 /// Create a new copy of the specified file descriptor using the specified fd 382 /// and flags (see [dup(2)](http://man7.org/linux/man-pages/man2/dup.2.html)). 383 /// 384 /// This function behaves similar to `dup2()` but allows for flags to be 385 /// specified. dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd>386 pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { 387 dup3_polyfill(oldfd, newfd, flags) 388 } 389 390 #[inline] dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd>391 fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { 392 if oldfd == newfd { 393 return Err(Error::Sys(Errno::EINVAL)); 394 } 395 396 let fd = dup2(oldfd, newfd)?; 397 398 if flags.contains(OFlag::O_CLOEXEC) { 399 if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { 400 let _ = close(fd); 401 return Err(e); 402 } 403 } 404 405 Ok(fd) 406 } 407 408 /// Change the current working directory of the calling process (see 409 /// [chdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). 410 /// 411 /// This function may fail in a number of different scenarios. See the man 412 /// pages for additional details on possible failure cases. 413 #[inline] chdir<P: ?Sized + NixPath>(path: &P) -> Result<()>414 pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { 415 let res = path.with_nix_path(|cstr| { 416 unsafe { libc::chdir(cstr.as_ptr()) } 417 })?; 418 419 Errno::result(res).map(drop) 420 } 421 422 /// Change the current working directory of the process to the one 423 /// given as an open file descriptor (see 424 /// [fchdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). 425 /// 426 /// This function may fail in a number of different scenarios. See the man 427 /// pages for additional details on possible failure cases. 428 #[inline] 429 #[cfg(not(target_os = "fuchsia"))] fchdir(dirfd: RawFd) -> Result<()>430 pub fn fchdir(dirfd: RawFd) -> Result<()> { 431 let res = unsafe { libc::fchdir(dirfd) }; 432 433 Errno::result(res).map(drop) 434 } 435 436 /// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) 437 /// 438 /// # Errors 439 /// 440 /// There are several situations where mkdir might fail: 441 /// 442 /// - current user has insufficient rights in the parent directory 443 /// - the path already exists 444 /// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) 445 /// 446 /// # Example 447 /// 448 /// ```rust 449 /// use nix::unistd; 450 /// use nix::sys::stat; 451 /// use tempfile::tempdir; 452 /// 453 /// fn main() { 454 /// let tmp_dir1 = tempdir().unwrap(); 455 /// let tmp_dir2 = tmp_dir1.path().join("new_dir"); 456 /// 457 /// // create new directory and give read, write and execute rights to the owner 458 /// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { 459 /// Ok(_) => println!("created {:?}", tmp_dir2), 460 /// Err(err) => println!("Error creating directory: {}", err), 461 /// } 462 /// } 463 /// ``` 464 #[inline] mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()>465 pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { 466 let res = path.with_nix_path(|cstr| { 467 unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } 468 })?; 469 470 Errno::result(res).map(drop) 471 } 472 473 /// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. 474 /// 475 /// # Errors 476 /// 477 /// There are several situations where mkfifo might fail: 478 /// 479 /// - current user has insufficient rights in the parent directory 480 /// - the path already exists 481 /// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) 482 /// 483 /// For a full list consult 484 /// [posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) 485 /// 486 /// # Example 487 /// 488 /// ```rust 489 /// use nix::unistd; 490 /// use nix::sys::stat; 491 /// use tempfile::tempdir; 492 /// 493 /// fn main() { 494 /// let tmp_dir = tempdir().unwrap(); 495 /// let fifo_path = tmp_dir.path().join("foo.pipe"); 496 /// 497 /// // create new fifo and give read, write and execute rights to the owner 498 /// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { 499 /// Ok(_) => println!("created {:?}", fifo_path), 500 /// Err(err) => println!("Error creating fifo: {}", err), 501 /// } 502 /// } 503 /// ``` 504 #[inline] 505 #[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()>506 pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { 507 let res = path.with_nix_path(|cstr| { 508 unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } 509 })?; 510 511 Errno::result(res).map(drop) 512 } 513 514 /// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. 515 /// 516 /// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. 517 /// 518 /// If `dirfd` is `None`, then `path` is relative to the current working directory. 519 /// 520 /// # References 521 /// 522 /// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). 523 // mkfifoat is not implemented in OSX or android 524 #[inline] 525 #[cfg(not(any( 526 target_os = "macos", target_os = "ios", 527 target_os = "android", target_os = "redox")))] mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()>528 pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> { 529 let res = path.with_nix_path(|cstr| unsafe { 530 libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) 531 })?; 532 533 Errno::result(res).map(drop) 534 } 535 536 /// Creates a symbolic link at `path2` which points to `path1`. 537 /// 538 /// If `dirfd` has a value, then `path2` is relative to directory associated 539 /// with the file descriptor. 540 /// 541 /// If `dirfd` is `None`, then `path2` is relative to the current working 542 /// directory. This is identical to `libc::symlink(path1, path2)`. 543 /// 544 /// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). 545 #[cfg(not(target_os = "redox"))] symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( path1: &P1, dirfd: Option<RawFd>, path2: &P2) -> Result<()>546 pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( 547 path1: &P1, 548 dirfd: Option<RawFd>, 549 path2: &P2) -> Result<()> { 550 let res = 551 path1.with_nix_path(|path1| { 552 path2.with_nix_path(|path2| { 553 unsafe { 554 libc::symlinkat( 555 path1.as_ptr(), 556 dirfd.unwrap_or(libc::AT_FDCWD), 557 path2.as_ptr() 558 ) 559 } 560 }) 561 })??; 562 Errno::result(res).map(drop) 563 } 564 565 // Double the buffer capacity up to limit. In case it already has 566 // reached the limit, return Errno::ERANGE. reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()>567 fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> { 568 use std::cmp::min; 569 570 if buf.capacity() >= limit { 571 return Err(Error::Sys(Errno::ERANGE)) 572 } 573 574 let capacity = min(buf.capacity() * 2, limit); 575 buf.reserve(capacity); 576 577 Ok(()) 578 } 579 580 /// Returns the current directory as a `PathBuf` 581 /// 582 /// Err is returned if the current user doesn't have the permission to read or search a component 583 /// of the current path. 584 /// 585 /// # Example 586 /// 587 /// ```rust 588 /// use nix::unistd; 589 /// 590 /// fn main() { 591 /// // assume that we are allowed to get current directory 592 /// let dir = unistd::getcwd().unwrap(); 593 /// println!("The current directory is {:?}", dir); 594 /// } 595 /// ``` 596 #[inline] getcwd() -> Result<PathBuf>597 pub fn getcwd() -> Result<PathBuf> { 598 let mut buf = Vec::with_capacity(512); 599 loop { 600 unsafe { 601 let ptr = buf.as_mut_ptr() as *mut c_char; 602 603 // The buffer must be large enough to store the absolute pathname plus 604 // a terminating null byte, or else null is returned. 605 // To safely handle this we start with a reasonable size (512 bytes) 606 // and double the buffer size upon every error 607 if !libc::getcwd(ptr, buf.capacity()).is_null() { 608 let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len(); 609 buf.set_len(len); 610 buf.shrink_to_fit(); 611 return Ok(PathBuf::from(OsString::from_vec(buf))); 612 } else { 613 let error = Errno::last(); 614 // ERANGE means buffer was too small to store directory name 615 if error != Errno::ERANGE { 616 return Err(Error::Sys(error)); 617 } 618 } 619 620 // Trigger the internal buffer resizing logic. 621 reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; 622 } 623 } 624 } 625 626 /// Computes the raw UID and GID values to pass to a `*chown` call. chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t)627 fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) { 628 // According to the POSIX specification, -1 is used to indicate that owner and group 629 // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap 630 // around to get -1. 631 let uid = owner.map(Into::into) 632 .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); 633 let gid = group.map(Into::into) 634 .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); 635 (uid, gid) 636 } 637 638 /// Change the ownership of the file at `path` to be owned by the specified 639 /// `owner` (user) and `group` (see 640 /// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). 641 /// 642 /// The owner/group for the provided path name will not be modified if `None` is 643 /// provided for that argument. Ownership change will be attempted for the path 644 /// only if `Some` owner/group is provided. 645 #[inline] chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()>646 pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { 647 let res = path.with_nix_path(|cstr| { 648 let (uid, gid) = chown_raw_ids(owner, group); 649 unsafe { libc::chown(cstr.as_ptr(), uid, gid) } 650 })?; 651 652 Errno::result(res).map(drop) 653 } 654 655 /// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by 656 /// the specified `owner` (user) and `group` (see 657 /// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)). 658 /// 659 /// The owner/group for the provided file will not be modified if `None` is 660 /// provided for that argument. Ownership change will be attempted for the path 661 /// only if `Some` owner/group is provided. 662 #[inline] fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()>663 pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { 664 let (uid, gid) = chown_raw_ids(owner, group); 665 let res = unsafe { libc::fchown(fd, uid, gid) }; 666 Errno::result(res).map(drop) 667 } 668 669 /// Flags for `fchownat` function. 670 #[derive(Clone, Copy, Debug)] 671 pub enum FchownatFlags { 672 FollowSymlink, 673 NoFollowSymlink, 674 } 675 676 /// Change the ownership of the file at `path` to be owned by the specified 677 /// `owner` (user) and `group`. 678 /// 679 /// The owner/group for the provided path name will not be modified if `None` is 680 /// provided for that argument. Ownership change will be attempted for the path 681 /// only if `Some` owner/group is provided. 682 /// 683 /// The file to be changed is determined relative to the directory associated 684 /// with the file descriptor `dirfd` or the current working directory 685 /// if `dirfd` is `None`. 686 /// 687 /// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, 688 /// then the mode of the symbolic link is changed. 689 /// 690 /// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to 691 /// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in 692 /// the `nix` crate. 693 /// 694 /// # References 695 /// 696 /// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). 697 #[cfg(not(target_os = "redox"))] fchownat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, owner: Option<Uid>, group: Option<Gid>, flag: FchownatFlags, ) -> Result<()>698 pub fn fchownat<P: ?Sized + NixPath>( 699 dirfd: Option<RawFd>, 700 path: &P, 701 owner: Option<Uid>, 702 group: Option<Gid>, 703 flag: FchownatFlags, 704 ) -> Result<()> { 705 let atflag = 706 match flag { 707 FchownatFlags::FollowSymlink => AtFlags::empty(), 708 FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, 709 }; 710 let res = path.with_nix_path(|cstr| unsafe { 711 let (uid, gid) = chown_raw_ids(owner, group); 712 libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, 713 atflag.bits() as libc::c_int) 714 })?; 715 716 Errno::result(res).map(drop) 717 } 718 to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char>719 fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> { 720 use std::iter::once; 721 args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect() 722 } 723 724 /// Replace the current process image with a new one (see 725 /// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). 726 /// 727 /// See the `::nix::unistd::execve` system call for additional details. `execv` 728 /// performs the same action but does not allow for customization of the 729 /// environment for the new process. 730 #[inline] execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible>731 pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> { 732 let args_p = to_exec_array(argv); 733 734 unsafe { 735 libc::execv(path.as_ptr(), args_p.as_ptr()) 736 }; 737 738 Err(Error::Sys(Errno::last())) 739 } 740 741 742 /// Replace the current process image with a new one (see 743 /// [execve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). 744 /// 745 /// The execve system call allows for another process to be "called" which will 746 /// replace the current process image. That is, this process becomes the new 747 /// command that is run. On success, this function will not return. Instead, 748 /// the new program will run until it exits. 749 /// 750 /// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice 751 /// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element 752 /// in the `args` list is an argument to the new process. Each element in the 753 /// `env` list should be a string in the form "key=value". 754 #[inline] execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible>755 pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { 756 let args_p = to_exec_array(args); 757 let env_p = to_exec_array(env); 758 759 unsafe { 760 libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) 761 }; 762 763 Err(Error::Sys(Errno::last())) 764 } 765 766 /// Replace the current process image with a new one and replicate shell `PATH` 767 /// searching behavior (see 768 /// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). 769 /// 770 /// See `::nix::unistd::execve` for additional details. `execvp` behaves the 771 /// same as execv except that it will examine the `PATH` environment variables 772 /// for file names not specified with a leading slash. For example, `execv` 773 /// would not work if "bash" was specified for the path argument, but `execvp` 774 /// would assuming that a bash executable was on the system `PATH`. 775 #[inline] execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible>776 pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> { 777 let args_p = to_exec_array(args); 778 779 unsafe { 780 libc::execvp(filename.as_ptr(), args_p.as_ptr()) 781 }; 782 783 Err(Error::Sys(Errno::last())) 784 } 785 786 /// Replace the current process image with a new one and replicate shell `PATH` 787 /// searching behavior (see 788 /// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)). 789 /// 790 /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an 791 /// environment and have a search path. See these two for additional 792 /// information. 793 #[cfg(any(target_os = "haiku", 794 target_os = "linux", 795 target_os = "openbsd"))] execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible>796 pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { 797 let args_p = to_exec_array(args); 798 let env_p = to_exec_array(env); 799 800 unsafe { 801 libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) 802 }; 803 804 Err(Error::Sys(Errno::last())) 805 } 806 807 /// Replace the current process image with a new one (see 808 /// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). 809 /// 810 /// The `fexecve` function allows for another process to be "called" which will 811 /// replace the current process image. That is, this process becomes the new 812 /// command that is run. On success, this function will not return. Instead, 813 /// the new program will run until it exits. 814 /// 815 /// This function is similar to `execve`, except that the program to be executed 816 /// is referenced as a file descriptor instead of a path. 817 // Note for NetBSD and OpenBSD: although rust-lang/libc includes it (under 818 // unix/bsd/netbsdlike/) fexecve is not currently implemented on NetBSD nor on 819 // OpenBSD. 820 #[cfg(any(target_os = "android", 821 target_os = "linux", 822 target_os = "freebsd"))] 823 #[inline] fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible>824 pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> { 825 let args_p = to_exec_array(args); 826 let env_p = to_exec_array(env); 827 828 unsafe { 829 libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) 830 }; 831 832 Err(Error::Sys(Errno::last())) 833 } 834 835 /// Execute program relative to a directory file descriptor (see 836 /// [execveat(2)](http://man7.org/linux/man-pages/man2/execveat.2.html)). 837 /// 838 /// The `execveat` function allows for another process to be "called" which will 839 /// replace the current process image. That is, this process becomes the new 840 /// command that is run. On success, this function will not return. Instead, 841 /// the new program will run until it exits. 842 /// 843 /// This function is similar to `execve`, except that the program to be executed 844 /// is referenced as a file descriptor to the base directory plus a path. 845 #[cfg(any(target_os = "android", target_os = "linux"))] 846 #[inline] execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible>847 pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], 848 env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> { 849 let args_p = to_exec_array(args); 850 let env_p = to_exec_array(env); 851 852 unsafe { 853 libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), 854 args_p.as_ptr(), env_p.as_ptr(), flags); 855 }; 856 857 Err(Error::Sys(Errno::last())) 858 } 859 860 /// Daemonize this process by detaching from the controlling terminal (see 861 /// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)). 862 /// 863 /// When a process is launched it is typically associated with a parent and it, 864 /// in turn, by its controlling terminal/process. In order for a process to run 865 /// in the "background" it must daemonize itself by detaching itself. Under 866 /// posix, this is done by doing the following: 867 /// 868 /// 1. Parent process (this one) forks 869 /// 2. Parent process exits 870 /// 3. Child process continues to run. 871 /// 872 /// `nochdir`: 873 /// 874 /// * `nochdir = true`: The current working directory after daemonizing will 875 /// be the current working directory. 876 /// * `nochdir = false`: The current working directory after daemonizing will 877 /// be the root direcory, `/`. 878 /// 879 /// `noclose`: 880 /// 881 /// * `noclose = true`: The process' current stdin, stdout, and stderr file 882 /// descriptors will remain identical after daemonizing. 883 /// * `noclose = false`: The process' stdin, stdout, and stderr will point to 884 /// `/dev/null` after daemonizing. 885 #[cfg(any(target_os = "android", 886 target_os = "dragonfly", 887 target_os = "freebsd", 888 target_os = "linux", 889 target_os = "netbsd", 890 target_os = "openbsd"))] daemon(nochdir: bool, noclose: bool) -> Result<()>891 pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { 892 let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; 893 Errno::result(res).map(drop) 894 } 895 896 /// Set the system host name (see 897 /// [sethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)). 898 /// 899 /// Given a name, attempt to update the system host name to the given string. 900 /// On some systems, the host name is limited to as few as 64 bytes. An error 901 /// will be return if the name is not valid or the current process does not have 902 /// permissions to update the host name. 903 #[cfg(not(target_os = "redox"))] sethostname<S: AsRef<OsStr>>(name: S) -> Result<()>904 pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { 905 // Handle some differences in type of the len arg across platforms. 906 cfg_if! { 907 if #[cfg(any(target_os = "dragonfly", 908 target_os = "freebsd", 909 target_os = "ios", 910 target_os = "macos", ))] { 911 type sethostname_len_t = c_int; 912 } else { 913 type sethostname_len_t = size_t; 914 } 915 } 916 let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; 917 let len = name.as_ref().len() as sethostname_len_t; 918 919 let res = unsafe { libc::sethostname(ptr, len) }; 920 Errno::result(res).map(drop) 921 } 922 923 /// Get the host name and store it in the provided buffer, returning a pointer 924 /// the `CStr` in that buffer on success (see 925 /// [gethostname(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). 926 /// 927 /// This function call attempts to get the host name for the running system and 928 /// store it in a provided buffer. The buffer will be populated with bytes up 929 /// to the length of the provided slice including a NUL terminating byte. If 930 /// the hostname is longer than the length provided, no error will be provided. 931 /// The posix specification does not specify whether implementations will 932 /// null-terminate in this case, but the nix implementation will ensure that the 933 /// buffer is null terminated in this case. 934 /// 935 /// ```no_run 936 /// use nix::unistd; 937 /// 938 /// let mut buf = [0u8; 64]; 939 /// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname"); 940 /// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8"); 941 /// println!("Hostname: {}", hostname); 942 /// ``` gethostname(buffer: &mut [u8]) -> Result<&CStr>943 pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { 944 let ptr = buffer.as_mut_ptr() as *mut c_char; 945 let len = buffer.len() as size_t; 946 947 let res = unsafe { libc::gethostname(ptr, len) }; 948 Errno::result(res).map(|_| { 949 buffer[len - 1] = 0; // ensure always null-terminated 950 unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) } 951 }) 952 } 953 954 /// Close a raw file descriptor 955 /// 956 /// Be aware that many Rust types implicitly close-on-drop, including 957 /// `std::fs::File`. Explicitly closing them with this method too can result in 958 /// a double-close condition, which can cause confusing `EBADF` errors in 959 /// seemingly unrelated code. Caveat programmer. See also 960 /// [close(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). 961 /// 962 /// # Examples 963 /// 964 /// ```no_run 965 /// use std::os::unix::io::AsRawFd; 966 /// use nix::unistd::close; 967 /// 968 /// fn main() { 969 /// let f = tempfile::tempfile().unwrap(); 970 /// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! 971 /// } 972 /// ``` 973 /// 974 /// ```rust 975 /// use std::os::unix::io::IntoRawFd; 976 /// use nix::unistd::close; 977 /// 978 /// fn main() { 979 /// let f = tempfile::tempfile().unwrap(); 980 /// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f 981 /// } 982 /// ``` close(fd: RawFd) -> Result<()>983 pub fn close(fd: RawFd) -> Result<()> { 984 let res = unsafe { libc::close(fd) }; 985 Errno::result(res).map(drop) 986 } 987 988 /// Read from a raw file descriptor. 989 /// 990 /// See also [read(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) read(fd: RawFd, buf: &mut [u8]) -> Result<usize>991 pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { 992 let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; 993 994 Errno::result(res).map(|r| r as usize) 995 } 996 997 /// Write to a raw file descriptor. 998 /// 999 /// See also [write(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) write(fd: RawFd, buf: &[u8]) -> Result<usize>1000 pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> { 1001 let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; 1002 1003 Errno::result(res).map(|r| r as usize) 1004 } 1005 1006 /// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to. 1007 /// 1008 /// [`lseek`]: ./fn.lseek.html 1009 /// [`lseek64`]: ./fn.lseek64.html 1010 #[repr(i32)] 1011 #[derive(Clone, Copy, Debug)] 1012 pub enum Whence { 1013 /// Specify an offset relative to the start of the file. 1014 SeekSet = libc::SEEK_SET, 1015 /// Specify an offset relative to the current file location. 1016 SeekCur = libc::SEEK_CUR, 1017 /// Specify an offset relative to the end of the file. 1018 SeekEnd = libc::SEEK_END, 1019 /// Specify an offset relative to the next location in the file greater than or 1020 /// equal to offset that contains some data. If offset points to 1021 /// some data, then the file offset is set to offset. 1022 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] 1023 SeekData = libc::SEEK_DATA, 1024 /// Specify an offset relative to the next hole in the file greater than 1025 /// or equal to offset. If offset points into the middle of a hole, then 1026 /// the file offset should be set to offset. If there is no hole past offset, 1027 /// then the file offset should be adjusted to the end of the file (i.e., there 1028 /// is an implicit hole at the end of any file). 1029 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] 1030 SeekHole = libc::SEEK_HOLE 1031 } 1032 1033 /// Move the read/write file offset. 1034 /// 1035 /// See also [lseek(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t>1036 pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { 1037 let res = unsafe { libc::lseek(fd, offset, whence as i32) }; 1038 1039 Errno::result(res).map(|r| r as off_t) 1040 } 1041 1042 #[cfg(any(target_os = "linux", target_os = "android"))] lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t>1043 pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> { 1044 let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; 1045 1046 Errno::result(res).map(|r| r as libc::off64_t) 1047 } 1048 1049 /// Create an interprocess channel. 1050 /// 1051 /// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) pipe() -> Result<(RawFd, RawFd)>1052 pub fn pipe() -> Result<(RawFd, RawFd)> { 1053 unsafe { 1054 let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); 1055 1056 let res = libc::pipe(fds.as_mut_ptr() as *mut c_int); 1057 1058 Errno::result(res)?; 1059 1060 Ok((fds.assume_init()[0], fds.assume_init()[1])) 1061 } 1062 } 1063 1064 /// Like `pipe`, but allows setting certain file descriptor flags. 1065 /// 1066 /// The following flags are supported, and will be set atomically as the pipe is 1067 /// created: 1068 /// 1069 /// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. 1070 #[cfg_attr(target_os = "linux", doc = "`O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode. ")] 1071 #[cfg_attr(target_os = "netbsd", doc = "`O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`. ")] 1072 /// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. 1073 /// 1074 /// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html) 1075 #[cfg(any(target_os = "android", 1076 target_os = "dragonfly", 1077 target_os = "emscripten", 1078 target_os = "freebsd", 1079 target_os = "linux", 1080 target_os = "redox", 1081 target_os = "netbsd", 1082 target_os = "openbsd"))] pipe2(flags: OFlag) -> Result<(RawFd, RawFd)>1083 pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { 1084 let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); 1085 1086 let res = unsafe { 1087 libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) 1088 }; 1089 1090 Errno::result(res)?; 1091 1092 unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } 1093 } 1094 1095 /// Truncate a file to a specified length 1096 /// 1097 /// See also 1098 /// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) 1099 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()>1100 pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { 1101 let res = path.with_nix_path(|cstr| { 1102 unsafe { 1103 libc::truncate(cstr.as_ptr(), len) 1104 } 1105 })?; 1106 1107 Errno::result(res).map(drop) 1108 } 1109 1110 /// Truncate a file to a specified length 1111 /// 1112 /// See also 1113 /// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) ftruncate(fd: RawFd, len: off_t) -> Result<()>1114 pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { 1115 Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) 1116 } 1117 isatty(fd: RawFd) -> Result<bool>1118 pub fn isatty(fd: RawFd) -> Result<bool> { 1119 unsafe { 1120 // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so 1121 // we return `Ok(false)` 1122 if libc::isatty(fd) == 1 { 1123 Ok(true) 1124 } else { 1125 match Errno::last() { 1126 Errno::ENOTTY => Ok(false), 1127 err => Err(Error::Sys(err)), 1128 } 1129 } 1130 } 1131 } 1132 1133 /// Flags for `linkat` function. 1134 #[derive(Clone, Copy, Debug)] 1135 pub enum LinkatFlags { 1136 SymlinkFollow, 1137 NoSymlinkFollow, 1138 } 1139 1140 /// Link one file to another file 1141 /// 1142 /// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the 1143 /// case of a relative `oldpath`, the path is interpreted relative to the directory associated 1144 /// with file descriptor `olddirfd` instead of the current working directory and similiarly for 1145 /// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and 1146 /// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. 1147 /// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` 1148 /// and/or `newpath` is then interpreted relative to the current working directory of the calling 1149 /// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored. 1150 /// 1151 /// # References 1152 /// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) 1153 #[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet linkat<P: ?Sized + NixPath>( olddirfd: Option<RawFd>, oldpath: &P, newdirfd: Option<RawFd>, newpath: &P, flag: LinkatFlags, ) -> Result<()>1154 pub fn linkat<P: ?Sized + NixPath>( 1155 olddirfd: Option<RawFd>, 1156 oldpath: &P, 1157 newdirfd: Option<RawFd>, 1158 newpath: &P, 1159 flag: LinkatFlags, 1160 ) -> Result<()> { 1161 1162 let atflag = 1163 match flag { 1164 LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, 1165 LinkatFlags::NoSymlinkFollow => AtFlags::empty(), 1166 }; 1167 1168 let res = 1169 oldpath.with_nix_path(|oldcstr| { 1170 newpath.with_nix_path(|newcstr| { 1171 unsafe { 1172 libc::linkat( 1173 at_rawfd(olddirfd), 1174 oldcstr.as_ptr(), 1175 at_rawfd(newdirfd), 1176 newcstr.as_ptr(), 1177 atflag.bits() as libc::c_int 1178 ) 1179 } 1180 }) 1181 })??; 1182 Errno::result(res).map(drop) 1183 } 1184 1185 1186 /// Remove a directory entry 1187 /// 1188 /// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) unlink<P: ?Sized + NixPath>(path: &P) -> Result<()>1189 pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { 1190 let res = path.with_nix_path(|cstr| { 1191 unsafe { 1192 libc::unlink(cstr.as_ptr()) 1193 } 1194 })?; 1195 Errno::result(res).map(drop) 1196 } 1197 1198 /// Flags for `unlinkat` function. 1199 #[derive(Clone, Copy, Debug)] 1200 pub enum UnlinkatFlags { 1201 RemoveDir, 1202 NoRemoveDir, 1203 } 1204 1205 /// Remove a directory entry 1206 /// 1207 /// In the case of a relative path, the directory entry to be removed is determined relative to 1208 /// the directory associated with the file descriptor `dirfd` or the current working directory 1209 /// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is 1210 /// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path` 1211 /// is performed. 1212 /// 1213 /// # References 1214 /// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) 1215 #[cfg(not(target_os = "redox"))] unlinkat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, flag: UnlinkatFlags, ) -> Result<()>1216 pub fn unlinkat<P: ?Sized + NixPath>( 1217 dirfd: Option<RawFd>, 1218 path: &P, 1219 flag: UnlinkatFlags, 1220 ) -> Result<()> { 1221 let atflag = 1222 match flag { 1223 UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, 1224 UnlinkatFlags::NoRemoveDir => AtFlags::empty(), 1225 }; 1226 let res = path.with_nix_path(|cstr| { 1227 unsafe { 1228 libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) 1229 } 1230 })?; 1231 Errno::result(res).map(drop) 1232 } 1233 1234 1235 #[inline] 1236 #[cfg(not(target_os = "fuchsia"))] chroot<P: ?Sized + NixPath>(path: &P) -> Result<()>1237 pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { 1238 let res = path.with_nix_path(|cstr| { 1239 unsafe { libc::chroot(cstr.as_ptr()) } 1240 })?; 1241 1242 Errno::result(res).map(drop) 1243 } 1244 1245 /// Commit filesystem caches to disk 1246 /// 1247 /// See also [sync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) 1248 #[cfg(any( 1249 target_os = "dragonfly", 1250 target_os = "freebsd", 1251 target_os = "linux", 1252 target_os = "netbsd", 1253 target_os = "openbsd" 1254 ))] sync()1255 pub fn sync() { 1256 unsafe { libc::sync() }; 1257 } 1258 1259 /// Synchronize changes to a file 1260 /// 1261 /// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) 1262 #[inline] fsync(fd: RawFd) -> Result<()>1263 pub fn fsync(fd: RawFd) -> Result<()> { 1264 let res = unsafe { libc::fsync(fd) }; 1265 1266 Errno::result(res).map(drop) 1267 } 1268 1269 /// Synchronize the data of a file 1270 /// 1271 /// See also 1272 /// [fdatasync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) 1273 // `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`. 1274 // TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211 1275 #[cfg(any(target_os = "linux", 1276 target_os = "android", 1277 target_os = "emscripten"))] 1278 #[inline] fdatasync(fd: RawFd) -> Result<()>1279 pub fn fdatasync(fd: RawFd) -> Result<()> { 1280 let res = unsafe { libc::fdatasync(fd) }; 1281 1282 Errno::result(res).map(drop) 1283 } 1284 1285 /// Get a real user ID 1286 /// 1287 /// See also [getuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) 1288 // POSIX requires that getuid is always successful, so no need to check return 1289 // value or errno. 1290 #[inline] getuid() -> Uid1291 pub fn getuid() -> Uid { 1292 Uid(unsafe { libc::getuid() }) 1293 } 1294 1295 /// Get the effective user ID 1296 /// 1297 /// See also [geteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) 1298 // POSIX requires that geteuid is always successful, so no need to check return 1299 // value or errno. 1300 #[inline] geteuid() -> Uid1301 pub fn geteuid() -> Uid { 1302 Uid(unsafe { libc::geteuid() }) 1303 } 1304 1305 /// Get the real group ID 1306 /// 1307 /// See also [getgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) 1308 // POSIX requires that getgid is always successful, so no need to check return 1309 // value or errno. 1310 #[inline] getgid() -> Gid1311 pub fn getgid() -> Gid { 1312 Gid(unsafe { libc::getgid() }) 1313 } 1314 1315 /// Get the effective group ID 1316 /// 1317 /// See also [getegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) 1318 // POSIX requires that getegid is always successful, so no need to check return 1319 // value or errno. 1320 #[inline] getegid() -> Gid1321 pub fn getegid() -> Gid { 1322 Gid(unsafe { libc::getegid() }) 1323 } 1324 1325 /// Set the effective user ID 1326 /// 1327 /// See also [seteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) 1328 #[inline] seteuid(euid: Uid) -> Result<()>1329 pub fn seteuid(euid: Uid) -> Result<()> { 1330 let res = unsafe { libc::seteuid(euid.into()) }; 1331 1332 Errno::result(res).map(drop) 1333 } 1334 1335 /// Set the effective group ID 1336 /// 1337 /// See also [setegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) 1338 #[inline] setegid(egid: Gid) -> Result<()>1339 pub fn setegid(egid: Gid) -> Result<()> { 1340 let res = unsafe { libc::setegid(egid.into()) }; 1341 1342 Errno::result(res).map(drop) 1343 } 1344 1345 /// Set the user ID 1346 /// 1347 /// See also [setuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) 1348 #[inline] setuid(uid: Uid) -> Result<()>1349 pub fn setuid(uid: Uid) -> Result<()> { 1350 let res = unsafe { libc::setuid(uid.into()) }; 1351 1352 Errno::result(res).map(drop) 1353 } 1354 1355 /// Set the group ID 1356 /// 1357 /// See also [setgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) 1358 #[inline] setgid(gid: Gid) -> Result<()>1359 pub fn setgid(gid: Gid) -> Result<()> { 1360 let res = unsafe { libc::setgid(gid.into()) }; 1361 1362 Errno::result(res).map(drop) 1363 } 1364 1365 /// Set the user identity used for filesystem checks per-thread. 1366 /// On both success and failure, this call returns the previous filesystem user 1367 /// ID of the caller. 1368 /// 1369 /// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html) 1370 #[cfg(any(target_os = "linux", target_os = "android"))] setfsuid(uid: Uid) -> Uid1371 pub fn setfsuid(uid: Uid) -> Uid { 1372 let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; 1373 Uid::from_raw(prev_fsuid as uid_t) 1374 } 1375 1376 /// Set the group identity used for filesystem checks per-thread. 1377 /// On both success and failure, this call returns the previous filesystem group 1378 /// ID of the caller. 1379 /// 1380 /// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html) 1381 #[cfg(any(target_os = "linux", target_os = "android"))] setfsgid(gid: Gid) -> Gid1382 pub fn setfsgid(gid: Gid) -> Gid { 1383 let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; 1384 Gid::from_raw(prev_fsgid as gid_t) 1385 } 1386 1387 /// Get the list of supplementary group IDs of the calling process. 1388 /// 1389 /// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) 1390 /// 1391 /// **Note:** This function is not available for Apple platforms. On those 1392 /// platforms, checking group membership should be achieved via communication 1393 /// with the `opendirectoryd` service. 1394 #[cfg(not(any(target_os = "ios", target_os = "macos")))] getgroups() -> Result<Vec<Gid>>1395 pub fn getgroups() -> Result<Vec<Gid>> { 1396 // First get the maximum number of groups. The value returned 1397 // shall always be greater than or equal to one and less than or 1398 // equal to the value of {NGROUPS_MAX} + 1. 1399 let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { 1400 Ok(Some(n)) => (n + 1) as usize, 1401 Ok(None) | Err(_) => <usize>::max_value(), 1402 }; 1403 1404 // Next, get the number of groups so we can size our Vec 1405 let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; 1406 1407 // Now actually get the groups. We try multiple times in case the number of 1408 // groups has changed since the first call to getgroups() and the buffer is 1409 // now too small. 1410 let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize); 1411 loop { 1412 // FIXME: On the platforms we currently support, the `Gid` struct has 1413 // the same representation in memory as a bare `gid_t`. This is not 1414 // necessarily the case on all Rust platforms, though. See RFC 1785. 1415 let ngroups = unsafe { 1416 libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) 1417 }; 1418 1419 match Errno::result(ngroups) { 1420 Ok(s) => { 1421 unsafe { groups.set_len(s as usize) }; 1422 return Ok(groups); 1423 }, 1424 Err(Error::Sys(Errno::EINVAL)) => { 1425 // EINVAL indicates that the buffer size was too 1426 // small, resize it up to ngroups_max as limit. 1427 reserve_double_buffer_size(&mut groups, ngroups_max) 1428 .or(Err(Error::Sys(Errno::EINVAL)))?; 1429 }, 1430 Err(e) => return Err(e) 1431 } 1432 } 1433 } 1434 1435 /// Set the list of supplementary group IDs for the calling process. 1436 /// 1437 /// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html) 1438 /// 1439 /// **Note:** This function is not available for Apple platforms. On those 1440 /// platforms, group membership management should be achieved via communication 1441 /// with the `opendirectoryd` service. 1442 /// 1443 /// # Examples 1444 /// 1445 /// `setgroups` can be used when dropping privileges from the root user to a 1446 /// specific user and group. For example, given the user `www-data` with UID 1447 /// `33` and the group `backup` with the GID `34`, one could switch the user as 1448 /// follows: 1449 /// 1450 /// ```rust,no_run 1451 /// # use std::error::Error; 1452 /// # use nix::unistd::*; 1453 /// # 1454 /// # fn try_main() -> Result<(), Box<Error>> { 1455 /// let uid = Uid::from_raw(33); 1456 /// let gid = Gid::from_raw(34); 1457 /// setgroups(&[gid])?; 1458 /// setgid(gid)?; 1459 /// setuid(uid)?; 1460 /// # 1461 /// # Ok(()) 1462 /// # } 1463 /// # 1464 /// # try_main().unwrap(); 1465 /// ``` 1466 #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] setgroups(groups: &[Gid]) -> Result<()>1467 pub fn setgroups(groups: &[Gid]) -> Result<()> { 1468 cfg_if! { 1469 if #[cfg(any(target_os = "dragonfly", 1470 target_os = "freebsd", 1471 target_os = "ios", 1472 target_os = "macos", 1473 target_os = "netbsd", 1474 target_os = "openbsd"))] { 1475 type setgroups_ngroups_t = c_int; 1476 } else { 1477 type setgroups_ngroups_t = size_t; 1478 } 1479 } 1480 // FIXME: On the platforms we currently support, the `Gid` struct has the 1481 // same representation in memory as a bare `gid_t`. This is not necessarily 1482 // the case on all Rust platforms, though. See RFC 1785. 1483 let res = unsafe { 1484 libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) 1485 }; 1486 1487 Errno::result(res).map(drop) 1488 } 1489 1490 /// Calculate the supplementary group access list. 1491 /// 1492 /// Gets the group IDs of all groups that `user` is a member of. The additional 1493 /// group `group` is also added to the list. 1494 /// 1495 /// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html) 1496 /// 1497 /// **Note:** This function is not available for Apple platforms. On those 1498 /// platforms, checking group membership should be achieved via communication 1499 /// with the `opendirectoryd` service. 1500 /// 1501 /// # Errors 1502 /// 1503 /// Although the `getgrouplist()` call does not return any specific 1504 /// errors on any known platforms, this implementation will return a system 1505 /// error of `EINVAL` if the number of groups to be fetched exceeds the 1506 /// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()` 1507 /// and `setgroups()`. Additionally, while some implementations will return a 1508 /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation 1509 /// will only ever return the complete list or else an error. 1510 #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>>1511 pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { 1512 let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { 1513 Ok(Some(n)) => n as c_int, 1514 Ok(None) | Err(_) => <c_int>::max_value(), 1515 }; 1516 use std::cmp::min; 1517 let mut ngroups = min(ngroups_max, 8); 1518 let mut groups = Vec::<Gid>::with_capacity(ngroups as usize); 1519 cfg_if! { 1520 if #[cfg(any(target_os = "ios", target_os = "macos"))] { 1521 type getgrouplist_group_t = c_int; 1522 } else { 1523 type getgrouplist_group_t = gid_t; 1524 } 1525 } 1526 let gid: gid_t = group.into(); 1527 loop { 1528 let ret = unsafe { 1529 libc::getgrouplist(user.as_ptr(), 1530 gid as getgrouplist_group_t, 1531 groups.as_mut_ptr() as *mut getgrouplist_group_t, 1532 &mut ngroups) 1533 }; 1534 1535 // BSD systems only return 0 or -1, Linux returns ngroups on success. 1536 if ret >= 0 { 1537 unsafe { groups.set_len(ngroups as usize) }; 1538 return Ok(groups); 1539 } else if ret == -1 { 1540 // Returns -1 if ngroups is too small, but does not set errno. 1541 // BSD systems will still fill the groups buffer with as many 1542 // groups as possible, but Linux manpages do not mention this 1543 // behavior. 1544 reserve_double_buffer_size(&mut groups, ngroups_max as usize) 1545 .or_else(|_| Err(Error::invalid_argument()))?; 1546 } 1547 } 1548 } 1549 1550 /// Initialize the supplementary group access list. 1551 /// 1552 /// Sets the supplementary group IDs for the calling process using all groups 1553 /// that `user` is a member of. The additional group `group` is also added to 1554 /// the list. 1555 /// 1556 /// [Further reading](http://man7.org/linux/man-pages/man3/initgroups.3.html) 1557 /// 1558 /// **Note:** This function is not available for Apple platforms. On those 1559 /// platforms, group membership management should be achieved via communication 1560 /// with the `opendirectoryd` service. 1561 /// 1562 /// # Examples 1563 /// 1564 /// `initgroups` can be used when dropping privileges from the root user to 1565 /// another user. For example, given the user `www-data`, we could look up the 1566 /// UID and GID for the user in the system's password database (usually found 1567 /// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`, 1568 /// respectively, one could switch the user as follows: 1569 /// 1570 /// ```rust,no_run 1571 /// # use std::error::Error; 1572 /// # use std::ffi::CString; 1573 /// # use nix::unistd::*; 1574 /// # 1575 /// # fn try_main() -> Result<(), Box<Error>> { 1576 /// let user = CString::new("www-data").unwrap(); 1577 /// let uid = Uid::from_raw(33); 1578 /// let gid = Gid::from_raw(33); 1579 /// initgroups(&user, gid)?; 1580 /// setgid(gid)?; 1581 /// setuid(uid)?; 1582 /// # 1583 /// # Ok(()) 1584 /// # } 1585 /// # 1586 /// # try_main().unwrap(); 1587 /// ``` 1588 #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] initgroups(user: &CStr, group: Gid) -> Result<()>1589 pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { 1590 cfg_if! { 1591 if #[cfg(any(target_os = "ios", target_os = "macos"))] { 1592 type initgroups_group_t = c_int; 1593 } else { 1594 type initgroups_group_t = gid_t; 1595 } 1596 } 1597 let gid: gid_t = group.into(); 1598 let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; 1599 1600 Errno::result(res).map(drop) 1601 } 1602 1603 /// Suspend the thread until a signal is received. 1604 /// 1605 /// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). 1606 #[inline] 1607 #[cfg(not(target_os = "redox"))] pause()1608 pub fn pause() { 1609 unsafe { libc::pause() }; 1610 } 1611 1612 pub mod alarm { 1613 //! Alarm signal scheduling. 1614 //! 1615 //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has 1616 //! elapsed, which has to be caught, because the default action for the 1617 //! signal is to terminate the program. This signal also can't be ignored 1618 //! because the system calls like `pause` will not be interrupted, see the 1619 //! second example below. 1620 //! 1621 //! # Examples 1622 //! 1623 //! Canceling an alarm: 1624 //! 1625 //! ``` 1626 //! use nix::unistd::alarm; 1627 //! 1628 //! // Set an alarm for 60 seconds from now. 1629 //! alarm::set(60); 1630 //! 1631 //! // Cancel the above set alarm, which returns the number of seconds left 1632 //! // of the previously set alarm. 1633 //! assert_eq!(alarm::cancel(), Some(60)); 1634 //! ``` 1635 //! 1636 //! Scheduling an alarm and waiting for the signal: 1637 //! 1638 #![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] 1639 #![cfg_attr(not(target_os = "redox"), doc = " ```rust")] 1640 //! use std::time::{Duration, Instant}; 1641 //! 1642 //! use nix::unistd::{alarm, pause}; 1643 //! use nix::sys::signal::*; 1644 //! 1645 //! // We need to setup an empty signal handler to catch the alarm signal, 1646 //! // otherwise the program will be terminated once the signal is delivered. 1647 //! extern fn signal_handler(_: nix::libc::c_int) { } 1648 //! let sa = SigAction::new( 1649 //! SigHandler::Handler(signal_handler), 1650 //! SaFlags::empty(), 1651 //! SigSet::empty() 1652 //! ); 1653 //! unsafe { 1654 //! sigaction(Signal::SIGALRM, &sa); 1655 //! } 1656 //! 1657 //! // Set an alarm for 1 second from now. 1658 //! alarm::set(1); 1659 //! 1660 //! let start = Instant::now(); 1661 //! // Pause the process until the alarm signal is received. 1662 //! let mut sigset = SigSet::empty(); 1663 //! sigset.add(Signal::SIGALRM); 1664 //! sigset.wait(); 1665 //! 1666 //! assert!(start.elapsed() >= Duration::from_secs(1)); 1667 //! ``` 1668 //! 1669 //! # References 1670 //! 1671 //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). 1672 1673 /// Schedule an alarm signal. 1674 /// 1675 /// This will cause the system to generate a `SIGALRM` signal for the 1676 /// process after the specified number of seconds have elapsed. 1677 /// 1678 /// Returns the leftover time of a previously set alarm if there was one. set(secs: libc::c_uint) -> Option<libc::c_uint>1679 pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> { 1680 assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`"); 1681 alarm(secs) 1682 } 1683 1684 /// Cancel an previously set alarm signal. 1685 /// 1686 /// Returns the leftover time of a previously set alarm if there was one. cancel() -> Option<libc::c_uint>1687 pub fn cancel() -> Option<libc::c_uint> { 1688 alarm(0) 1689 } 1690 alarm(secs: libc::c_uint) -> Option<libc::c_uint>1691 fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> { 1692 match unsafe { libc::alarm(secs) } { 1693 0 => None, 1694 secs => Some(secs), 1695 } 1696 } 1697 } 1698 1699 /// Suspend execution for an interval of time 1700 /// 1701 /// See also [sleep(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) 1702 // Per POSIX, does not fail 1703 #[inline] sleep(seconds: c_uint) -> c_uint1704 pub fn sleep(seconds: c_uint) -> c_uint { 1705 unsafe { libc::sleep(seconds) } 1706 } 1707 1708 #[cfg(not(target_os = "redox"))] 1709 pub mod acct { 1710 use crate::{Result, NixPath}; 1711 use crate::errno::Errno; 1712 use std::ptr; 1713 1714 /// Enable process accounting 1715 /// 1716 /// See also [acct(2)](https://linux.die.net/man/2/acct) enable<P: ?Sized + NixPath>(filename: &P) -> Result<()>1717 pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> { 1718 let res = filename.with_nix_path(|cstr| { 1719 unsafe { libc::acct(cstr.as_ptr()) } 1720 })?; 1721 1722 Errno::result(res).map(drop) 1723 } 1724 1725 /// Disable process accounting disable() -> Result<()>1726 pub fn disable() -> Result<()> { 1727 let res = unsafe { libc::acct(ptr::null()) }; 1728 1729 Errno::result(res).map(drop) 1730 } 1731 } 1732 1733 /// Creates a regular file which persists even after process termination 1734 /// 1735 /// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX` 1736 /// * returns: tuple of file descriptor and filename 1737 /// 1738 /// Err is returned either if no temporary filename could be created or the template doesn't 1739 /// end with XXXXXX 1740 /// 1741 /// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) 1742 /// 1743 /// # Example 1744 /// 1745 /// ```rust 1746 /// use nix::unistd; 1747 /// 1748 /// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") { 1749 /// Ok((fd, path)) => { 1750 /// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination 1751 /// fd 1752 /// } 1753 /// Err(e) => panic!("mkstemp failed: {}", e) 1754 /// }; 1755 /// // do something with fd 1756 /// ``` 1757 #[inline] mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)>1758 pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { 1759 let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; 1760 let p = path.as_mut_ptr() as *mut _; 1761 let fd = unsafe { libc::mkstemp(p) }; 1762 let last = path.pop(); // drop the trailing nul 1763 debug_assert!(last == Some(b'\0')); 1764 let pathname = OsString::from_vec(path); 1765 Errno::result(fd)?; 1766 Ok((fd, PathBuf::from(pathname))) 1767 } 1768 1769 /// Variable names for `pathconf` 1770 /// 1771 /// Nix uses the same naming convention for these variables as the 1772 /// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. 1773 /// That is, `PathconfVar` variables have the same name as the abstract 1774 /// variables shown in the `pathconf(2)` man page. Usually, it's the same as 1775 /// the C variable name without the leading `_PC_`. 1776 /// 1777 /// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose 1778 /// not to implement variables that cannot change at runtime. 1779 /// 1780 /// # References 1781 /// 1782 /// - [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) 1783 /// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) 1784 /// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) 1785 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1786 #[repr(i32)] 1787 pub enum PathconfVar { 1788 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", 1789 target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] 1790 /// Minimum number of bits needed to represent, as a signed integer value, 1791 /// the maximum size of a regular file allowed in the specified directory. 1792 FILESIZEBITS = libc::_PC_FILESIZEBITS, 1793 /// Maximum number of links to a single file. 1794 LINK_MAX = libc::_PC_LINK_MAX, 1795 /// Maximum number of bytes in a terminal canonical input line. 1796 MAX_CANON = libc::_PC_MAX_CANON, 1797 /// Minimum number of bytes for which space is available in a terminal input 1798 /// queue; therefore, the maximum number of bytes a conforming application 1799 /// may require to be typed as input before reading them. 1800 MAX_INPUT = libc::_PC_MAX_INPUT, 1801 /// Maximum number of bytes in a filename (not including the terminating 1802 /// null of a filename string). 1803 NAME_MAX = libc::_PC_NAME_MAX, 1804 /// Maximum number of bytes the implementation will store as a pathname in a 1805 /// user-supplied buffer of unspecified size, including the terminating null 1806 /// character. Minimum number the implementation will accept as the maximum 1807 /// number of bytes in a pathname. 1808 PATH_MAX = libc::_PC_PATH_MAX, 1809 /// Maximum number of bytes that is guaranteed to be atomic when writing to 1810 /// a pipe. 1811 PIPE_BUF = libc::_PC_PIPE_BUF, 1812 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux", 1813 target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] 1814 /// Symbolic links can be created. 1815 POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, 1816 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1817 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1818 /// Minimum number of bytes of storage actually allocated for any portion of 1819 /// a file. 1820 POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, 1821 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1822 target_os = "linux", target_os = "openbsd"))] 1823 /// Recommended increment for file transfer sizes between the 1824 /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. 1825 POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, 1826 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1827 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1828 /// Maximum recommended file transfer size. 1829 POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, 1830 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1831 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1832 /// Minimum recommended file transfer size. 1833 POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, 1834 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1835 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1836 /// Recommended file transfer buffer alignment. 1837 POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, 1838 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1839 target_os = "linux", target_os = "netbsd", target_os = "openbsd", 1840 target_os = "redox"))] 1841 /// Maximum number of bytes in a symbolic link. 1842 SYMLINK_MAX = libc::_PC_SYMLINK_MAX, 1843 /// The use of `chown` and `fchown` is restricted to a process with 1844 /// appropriate privileges, and to changing the group ID of a file only to 1845 /// the effective group ID of the process or to one of its supplementary 1846 /// group IDs. 1847 _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED, 1848 /// Pathname components longer than {NAME_MAX} generate an error. 1849 _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC, 1850 /// This symbol shall be defined to be the value of a character that shall 1851 /// disable terminal special character handling. 1852 _POSIX_VDISABLE = libc::_PC_VDISABLE, 1853 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1854 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1855 /// Asynchronous input or output operations may be performed for the 1856 /// associated file. 1857 _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, 1858 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1859 target_os = "linux", target_os = "openbsd", target_os = "redox"))] 1860 /// Prioritized input or output operations may be performed for the 1861 /// associated file. 1862 _POSIX_PRIO_IO = libc::_PC_PRIO_IO, 1863 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", 1864 target_os = "linux", target_os = "netbsd", target_os = "openbsd", 1865 target_os = "redox"))] 1866 /// Synchronized input or output operations may be performed for the 1867 /// associated file. 1868 _POSIX_SYNC_IO = libc::_PC_SYNC_IO, 1869 #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] 1870 /// The resolution in nanoseconds for all file timestamps. 1871 _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION 1872 } 1873 1874 /// Like `pathconf`, but works with file descriptors instead of paths (see 1875 /// [fpathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) 1876 /// 1877 /// # Parameters 1878 /// 1879 /// - `fd`: The file descriptor whose variable should be interrogated 1880 /// - `var`: The pathconf variable to lookup 1881 /// 1882 /// # Returns 1883 /// 1884 /// - `Ok(Some(x))`: the variable's limit (for limit variables) or its 1885 /// implementation level (for option variables). Implementation levels are 1886 /// usually a decimal-coded date, such as 200112 for POSIX 2001.12 1887 /// - `Ok(None)`: the variable has no limit (for limit variables) or is 1888 /// unsupported (for option variables) 1889 /// - `Err(x)`: an error occurred fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>>1890 pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { 1891 let raw = unsafe { 1892 Errno::clear(); 1893 libc::fpathconf(fd, var as c_int) 1894 }; 1895 if raw == -1 { 1896 if errno::errno() == 0 { 1897 Ok(None) 1898 } else { 1899 Err(Error::Sys(Errno::last())) 1900 } 1901 } else { 1902 Ok(Some(raw)) 1903 } 1904 } 1905 1906 /// Get path-dependent configurable system variables (see 1907 /// [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) 1908 /// 1909 /// Returns the value of a path-dependent configurable system variable. Most 1910 /// supported variables also have associated compile-time constants, but POSIX 1911 /// allows their values to change at runtime. There are generally two types of 1912 /// `pathconf` variables: options and limits. See [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. 1913 /// 1914 /// # Parameters 1915 /// 1916 /// - `path`: Lookup the value of `var` for this file or directory 1917 /// - `var`: The `pathconf` variable to lookup 1918 /// 1919 /// # Returns 1920 /// 1921 /// - `Ok(Some(x))`: the variable's limit (for limit variables) or its 1922 /// implementation level (for option variables). Implementation levels are 1923 /// usually a decimal-coded date, such as 200112 for POSIX 2001.12 1924 /// - `Ok(None)`: the variable has no limit (for limit variables) or is 1925 /// unsupported (for option variables) 1926 /// - `Err(x)`: an error occurred pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>>1927 pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> { 1928 let raw = path.with_nix_path(|cstr| { 1929 unsafe { 1930 Errno::clear(); 1931 libc::pathconf(cstr.as_ptr(), var as c_int) 1932 } 1933 })?; 1934 if raw == -1 { 1935 if errno::errno() == 0 { 1936 Ok(None) 1937 } else { 1938 Err(Error::Sys(Errno::last())) 1939 } 1940 } else { 1941 Ok(Some(raw)) 1942 } 1943 } 1944 1945 /// Variable names for `sysconf` 1946 /// 1947 /// Nix uses the same naming convention for these variables as the 1948 /// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. 1949 /// That is, `SysconfVar` variables have the same name as the abstract variables 1950 /// shown in the `sysconf(3)` man page. Usually, it's the same as the C 1951 /// variable name without the leading `_SC_`. 1952 /// 1953 /// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been 1954 /// implemented by all platforms. 1955 /// 1956 /// # References 1957 /// 1958 /// - [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) 1959 /// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) 1960 /// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) 1961 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1962 #[repr(i32)] 1963 pub enum SysconfVar { 1964 /// Maximum number of I/O operations in a single list I/O call supported by 1965 /// the implementation. 1966 #[cfg(not(target_os = "redox"))] 1967 AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, 1968 /// Maximum number of outstanding asynchronous I/O operations supported by 1969 /// the implementation. 1970 #[cfg(not(target_os = "redox"))] 1971 AIO_MAX = libc::_SC_AIO_MAX, 1972 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 1973 target_os = "ios", target_os="linux", target_os = "macos", 1974 target_os="openbsd"))] 1975 /// The maximum amount by which a process can decrease its asynchronous I/O 1976 /// priority level from its own scheduling priority. 1977 AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, 1978 /// Maximum length of argument to the exec functions including environment data. 1979 ARG_MAX = libc::_SC_ARG_MAX, 1980 /// Maximum number of functions that may be registered with `atexit`. 1981 #[cfg(not(target_os = "redox"))] 1982 ATEXIT_MAX = libc::_SC_ATEXIT_MAX, 1983 /// Maximum obase values allowed by the bc utility. 1984 #[cfg(not(target_os = "redox"))] 1985 BC_BASE_MAX = libc::_SC_BC_BASE_MAX, 1986 /// Maximum number of elements permitted in an array by the bc utility. 1987 #[cfg(not(target_os = "redox"))] 1988 BC_DIM_MAX = libc::_SC_BC_DIM_MAX, 1989 /// Maximum scale value allowed by the bc utility. 1990 #[cfg(not(target_os = "redox"))] 1991 BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, 1992 /// Maximum length of a string constant accepted by the bc utility. 1993 #[cfg(not(target_os = "redox"))] 1994 BC_STRING_MAX = libc::_SC_BC_STRING_MAX, 1995 /// Maximum number of simultaneous processes per real user ID. 1996 CHILD_MAX = libc::_SC_CHILD_MAX, 1997 // The number of clock ticks per second. 1998 CLK_TCK = libc::_SC_CLK_TCK, 1999 /// Maximum number of weights that can be assigned to an entry of the 2000 /// LC_COLLATE order keyword in the locale definition file 2001 #[cfg(not(target_os = "redox"))] 2002 COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, 2003 /// Maximum number of timer expiration overruns. 2004 #[cfg(not(target_os = "redox"))] 2005 DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, 2006 /// Maximum number of expressions that can be nested within parentheses by 2007 /// the expr utility. 2008 #[cfg(not(target_os = "redox"))] 2009 EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, 2010 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2011 target_os="linux", target_os = "macos", target_os="netbsd", 2012 target_os="openbsd"))] 2013 /// Maximum length of a host name (not including the terminating null) as 2014 /// returned from the `gethostname` function 2015 HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, 2016 /// Maximum number of iovec structures that one process has available for 2017 /// use with `readv` or `writev`. 2018 #[cfg(not(target_os = "redox"))] 2019 IOV_MAX = libc::_SC_IOV_MAX, 2020 /// Unless otherwise noted, the maximum length, in bytes, of a utility's 2021 /// input line (either standard input or another file), when the utility is 2022 /// described as processing text files. The length includes room for the 2023 /// trailing <newline>. 2024 #[cfg(not(target_os = "redox"))] 2025 LINE_MAX = libc::_SC_LINE_MAX, 2026 /// Maximum length of a login name. 2027 LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, 2028 /// Maximum number of simultaneous supplementary group IDs per process. 2029 NGROUPS_MAX = libc::_SC_NGROUPS_MAX, 2030 /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers 2031 #[cfg(not(target_os = "redox"))] 2032 GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, 2033 /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers 2034 #[cfg(not(target_os = "redox"))] 2035 GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, 2036 /// The maximum number of open message queue descriptors a process may hold. 2037 #[cfg(not(target_os = "redox"))] 2038 MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, 2039 /// The maximum number of message priorities supported by the implementation. 2040 #[cfg(not(target_os = "redox"))] 2041 MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, 2042 /// A value one greater than the maximum value that the system may assign to 2043 /// a newly-created file descriptor. 2044 OPEN_MAX = libc::_SC_OPEN_MAX, 2045 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2046 target_os="linux", target_os = "macos", target_os="openbsd"))] 2047 /// The implementation supports the Advisory Information option. 2048 _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, 2049 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2050 target_os="linux", target_os = "macos", target_os="netbsd", 2051 target_os="openbsd"))] 2052 /// The implementation supports barriers. 2053 _POSIX_BARRIERS = libc::_SC_BARRIERS, 2054 /// The implementation supports asynchronous input and output. 2055 #[cfg(not(target_os = "redox"))] 2056 _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, 2057 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2058 target_os="linux", target_os = "macos", target_os="netbsd", 2059 target_os="openbsd"))] 2060 /// The implementation supports clock selection. 2061 _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, 2062 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2063 target_os="linux", target_os = "macos", target_os="netbsd", 2064 target_os="openbsd"))] 2065 /// The implementation supports the Process CPU-Time Clocks option. 2066 _POSIX_CPUTIME = libc::_SC_CPUTIME, 2067 /// The implementation supports the File Synchronization option. 2068 #[cfg(not(target_os = "redox"))] 2069 _POSIX_FSYNC = libc::_SC_FSYNC, 2070 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2071 target_os="linux", target_os = "macos", target_os="openbsd"))] 2072 /// The implementation supports the IPv6 option. 2073 _POSIX_IPV6 = libc::_SC_IPV6, 2074 /// The implementation supports job control. 2075 #[cfg(not(target_os = "redox"))] 2076 _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, 2077 /// The implementation supports memory mapped Files. 2078 #[cfg(not(target_os = "redox"))] 2079 _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, 2080 /// The implementation supports the Process Memory Locking option. 2081 #[cfg(not(target_os = "redox"))] 2082 _POSIX_MEMLOCK = libc::_SC_MEMLOCK, 2083 /// The implementation supports the Range Memory Locking option. 2084 #[cfg(not(target_os = "redox"))] 2085 _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, 2086 /// The implementation supports memory protection. 2087 #[cfg(not(target_os = "redox"))] 2088 _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, 2089 /// The implementation supports the Message Passing option. 2090 #[cfg(not(target_os = "redox"))] 2091 _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, 2092 /// The implementation supports the Monotonic Clock option. 2093 #[cfg(not(target_os = "redox"))] 2094 _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, 2095 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2096 target_os = "ios", target_os="linux", target_os = "macos", 2097 target_os="openbsd"))] 2098 /// The implementation supports the Prioritized Input and Output option. 2099 _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, 2100 /// The implementation supports the Process Scheduling option. 2101 #[cfg(not(target_os = "redox"))] 2102 _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, 2103 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2104 target_os="linux", target_os = "macos", target_os="openbsd"))] 2105 /// The implementation supports the Raw Sockets option. 2106 _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, 2107 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2108 target_os="linux", target_os = "macos", target_os="netbsd", 2109 target_os="openbsd"))] 2110 /// The implementation supports read-write locks. 2111 _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, 2112 #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", 2113 target_os = "ios", target_os="linux", target_os = "macos", 2114 target_os = "openbsd"))] 2115 /// The implementation supports realtime signals. 2116 _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, 2117 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2118 target_os="linux", target_os = "macos", target_os="netbsd", 2119 target_os="openbsd"))] 2120 /// The implementation supports the Regular Expression Handling option. 2121 _POSIX_REGEXP = libc::_SC_REGEXP, 2122 /// Each process has a saved set-user-ID and a saved set-group-ID. 2123 #[cfg(not(target_os = "redox"))] 2124 _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, 2125 /// The implementation supports semaphores. 2126 #[cfg(not(target_os = "redox"))] 2127 _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, 2128 /// The implementation supports the Shared Memory Objects option. 2129 #[cfg(not(target_os = "redox"))] 2130 _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, 2131 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2132 target_os="linux", target_os = "macos", target_os="netbsd", 2133 target_os="openbsd"))] 2134 /// The implementation supports the POSIX shell. 2135 _POSIX_SHELL = libc::_SC_SHELL, 2136 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2137 target_os="linux", target_os = "macos", target_os="netbsd", 2138 target_os="openbsd"))] 2139 /// The implementation supports the Spawn option. 2140 _POSIX_SPAWN = libc::_SC_SPAWN, 2141 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2142 target_os="linux", target_os = "macos", target_os="netbsd", 2143 target_os="openbsd"))] 2144 /// The implementation supports spin locks. 2145 _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, 2146 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2147 target_os="linux", target_os = "macos", target_os="openbsd"))] 2148 /// The implementation supports the Process Sporadic Server option. 2149 _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, 2150 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2151 target_os="openbsd"))] 2152 _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, 2153 /// The implementation supports the Synchronized Input and Output option. 2154 #[cfg(not(target_os = "redox"))] 2155 _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, 2156 /// The implementation supports the Thread Stack Address Attribute option. 2157 #[cfg(not(target_os = "redox"))] 2158 _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, 2159 /// The implementation supports the Thread Stack Size Attribute option. 2160 #[cfg(not(target_os = "redox"))] 2161 _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, 2162 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2163 target_os="netbsd", target_os="openbsd"))] 2164 /// The implementation supports the Thread CPU-Time Clocks option. 2165 _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, 2166 /// The implementation supports the Non-Robust Mutex Priority Inheritance 2167 /// option. 2168 #[cfg(not(target_os = "redox"))] 2169 _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, 2170 /// The implementation supports the Non-Robust Mutex Priority Protection option. 2171 #[cfg(not(target_os = "redox"))] 2172 _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, 2173 /// The implementation supports the Thread Execution Scheduling option. 2174 #[cfg(not(target_os = "redox"))] 2175 _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, 2176 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2177 target_os="linux", target_os = "macos", target_os="netbsd", 2178 target_os="openbsd"))] 2179 /// The implementation supports the Thread Process-Shared Synchronization 2180 /// option. 2181 _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, 2182 #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] 2183 /// The implementation supports the Robust Mutex Priority Inheritance option. 2184 _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, 2185 #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] 2186 /// The implementation supports the Robust Mutex Priority Protection option. 2187 _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, 2188 /// The implementation supports thread-safe functions. 2189 #[cfg(not(target_os = "redox"))] 2190 _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, 2191 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2192 target_os="linux", target_os = "macos", target_os="openbsd"))] 2193 /// The implementation supports the Thread Sporadic Server option. 2194 _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, 2195 /// The implementation supports threads. 2196 #[cfg(not(target_os = "redox"))] 2197 _POSIX_THREADS = libc::_SC_THREADS, 2198 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2199 target_os="linux", target_os = "macos", target_os="openbsd"))] 2200 /// The implementation supports timeouts. 2201 _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, 2202 /// The implementation supports timers. 2203 #[cfg(not(target_os = "redox"))] 2204 _POSIX_TIMERS = libc::_SC_TIMERS, 2205 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2206 target_os="linux", target_os = "macos", target_os="openbsd"))] 2207 /// The implementation supports the Trace option. 2208 _POSIX_TRACE = libc::_SC_TRACE, 2209 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2210 target_os="linux", target_os = "macos", target_os="openbsd"))] 2211 /// The implementation supports the Trace Event Filter option. 2212 _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, 2213 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2214 target_os="openbsd"))] 2215 _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, 2216 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2217 target_os="linux", target_os = "macos", target_os="openbsd"))] 2218 /// The implementation supports the Trace Inherit option. 2219 _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, 2220 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2221 target_os="linux", target_os = "macos", target_os="openbsd"))] 2222 /// The implementation supports the Trace Log option. 2223 _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, 2224 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2225 target_os="openbsd"))] 2226 _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, 2227 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2228 target_os="openbsd"))] 2229 _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, 2230 #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", 2231 target_os="openbsd"))] 2232 _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, 2233 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2234 target_os="linux", target_os = "macos", target_os="openbsd"))] 2235 /// The implementation supports the Typed Memory Objects option. 2236 _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, 2237 /// Integer value indicating version of this standard (C-language binding) 2238 /// to which the implementation conforms. For implementations conforming to 2239 /// POSIX.1-2008, the value shall be 200809L. 2240 _POSIX_VERSION = libc::_SC_VERSION, 2241 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2242 target_os="linux", target_os = "macos", target_os="netbsd", 2243 target_os="openbsd"))] 2244 /// The implementation provides a C-language compilation environment with 2245 /// 32-bit `int`, `long`, `pointer`, and `off_t` types. 2246 _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, 2247 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2248 target_os="linux", target_os = "macos", target_os="netbsd", 2249 target_os="openbsd"))] 2250 /// The implementation provides a C-language compilation environment with 2251 /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at 2252 /// least 64 bits. 2253 _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, 2254 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2255 target_os="linux", target_os = "macos", target_os="netbsd", 2256 target_os="openbsd"))] 2257 /// The implementation provides a C-language compilation environment with 2258 /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. 2259 _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, 2260 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2261 target_os="linux", target_os = "macos", target_os="netbsd", 2262 target_os="openbsd"))] 2263 /// The implementation provides a C-language compilation environment with an 2264 /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types 2265 /// using at least 64 bits. 2266 _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, 2267 /// The implementation supports the C-Language Binding option. 2268 #[cfg(not(target_os = "redox"))] 2269 _POSIX2_C_BIND = libc::_SC_2_C_BIND, 2270 /// The implementation supports the C-Language Development Utilities option. 2271 #[cfg(not(target_os = "redox"))] 2272 _POSIX2_C_DEV = libc::_SC_2_C_DEV, 2273 /// The implementation supports the Terminal Characteristics option. 2274 #[cfg(not(target_os = "redox"))] 2275 _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, 2276 /// The implementation supports the FORTRAN Development Utilities option. 2277 #[cfg(not(target_os = "redox"))] 2278 _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, 2279 /// The implementation supports the FORTRAN Runtime Utilities option. 2280 #[cfg(not(target_os = "redox"))] 2281 _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, 2282 /// The implementation supports the creation of locales by the localedef 2283 /// utility. 2284 #[cfg(not(target_os = "redox"))] 2285 _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, 2286 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2287 target_os="linux", target_os = "macos", target_os="netbsd", 2288 target_os="openbsd"))] 2289 /// The implementation supports the Batch Environment Services and Utilities 2290 /// option. 2291 _POSIX2_PBS = libc::_SC_2_PBS, 2292 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2293 target_os="linux", target_os = "macos", target_os="netbsd", 2294 target_os="openbsd"))] 2295 /// The implementation supports the Batch Accounting option. 2296 _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, 2297 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2298 target_os="linux", target_os = "macos", target_os="netbsd", 2299 target_os="openbsd"))] 2300 /// The implementation supports the Batch Checkpoint/Restart option. 2301 _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, 2302 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2303 target_os="linux", target_os = "macos", target_os="netbsd", 2304 target_os="openbsd"))] 2305 /// The implementation supports the Locate Batch Job Request option. 2306 _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, 2307 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2308 target_os="linux", target_os = "macos", target_os="netbsd", 2309 target_os="openbsd"))] 2310 /// The implementation supports the Batch Job Message Request option. 2311 _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, 2312 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2313 target_os="linux", target_os = "macos", target_os="netbsd", 2314 target_os="openbsd"))] 2315 /// The implementation supports the Track Batch Job Request option. 2316 _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, 2317 /// The implementation supports the Software Development Utilities option. 2318 #[cfg(not(target_os = "redox"))] 2319 _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, 2320 /// The implementation supports the User Portability Utilities option. 2321 #[cfg(not(target_os = "redox"))] 2322 _POSIX2_UPE = libc::_SC_2_UPE, 2323 /// Integer value indicating version of the Shell and Utilities volume of 2324 /// POSIX.1 to which the implementation conforms. 2325 #[cfg(not(target_os = "redox"))] 2326 _POSIX2_VERSION = libc::_SC_2_VERSION, 2327 /// The size of a system page in bytes. 2328 /// 2329 /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two 2330 /// enum constants to have the same value, so nix omits `PAGESIZE`. 2331 PAGE_SIZE = libc::_SC_PAGE_SIZE, 2332 #[cfg(not(target_os = "redox"))] 2333 PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, 2334 #[cfg(not(target_os = "redox"))] 2335 PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, 2336 #[cfg(not(target_os = "redox"))] 2337 PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, 2338 #[cfg(not(target_os = "redox"))] 2339 PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, 2340 RE_DUP_MAX = libc::_SC_RE_DUP_MAX, 2341 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2342 target_os = "ios", target_os="linux", target_os = "macos", 2343 target_os="openbsd"))] 2344 RTSIG_MAX = libc::_SC_RTSIG_MAX, 2345 #[cfg(not(target_os = "redox"))] 2346 SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, 2347 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2348 target_os = "ios", target_os="linux", target_os = "macos", 2349 target_os="openbsd"))] 2350 SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, 2351 #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", 2352 target_os = "ios", target_os="linux", target_os = "macos", 2353 target_os = "openbsd"))] 2354 SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, 2355 STREAM_MAX = libc::_SC_STREAM_MAX, 2356 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2357 target_os="linux", target_os = "macos", target_os="netbsd", 2358 target_os="openbsd"))] 2359 SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, 2360 #[cfg(not(target_os = "redox"))] 2361 TIMER_MAX = libc::_SC_TIMER_MAX, 2362 TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, 2363 TZNAME_MAX = libc::_SC_TZNAME_MAX, 2364 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2365 target_os = "ios", target_os="linux", target_os = "macos", 2366 target_os="openbsd"))] 2367 /// The implementation supports the X/Open Encryption Option Group. 2368 _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, 2369 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2370 target_os = "ios", target_os="linux", target_os = "macos", 2371 target_os="openbsd"))] 2372 /// The implementation supports the Issue 4, Version 2 Enhanced 2373 /// Internationalization Option Group. 2374 _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, 2375 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2376 target_os = "ios", target_os="linux", target_os = "macos", 2377 target_os="openbsd"))] 2378 _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, 2379 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2380 target_os = "ios", target_os="linux", target_os = "macos", 2381 target_os="openbsd"))] 2382 /// The implementation supports the X/Open Realtime Option Group. 2383 _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, 2384 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2385 target_os = "ios", target_os="linux", target_os = "macos", 2386 target_os="openbsd"))] 2387 /// The implementation supports the X/Open Realtime Threads Option Group. 2388 _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, 2389 /// The implementation supports the Issue 4, Version 2 Shared Memory Option 2390 /// Group. 2391 #[cfg(not(target_os = "redox"))] 2392 _XOPEN_SHM = libc::_SC_XOPEN_SHM, 2393 #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", 2394 target_os="linux", target_os = "macos", target_os="openbsd"))] 2395 /// The implementation supports the XSI STREAMS Option Group. 2396 _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, 2397 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2398 target_os = "ios", target_os="linux", target_os = "macos", 2399 target_os="openbsd"))] 2400 /// The implementation supports the XSI option 2401 _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, 2402 #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", 2403 target_os = "ios", target_os="linux", target_os = "macos", 2404 target_os="openbsd"))] 2405 /// Integer value indicating version of the X/Open Portability Guide to 2406 /// which the implementation conforms. 2407 _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, 2408 } 2409 2410 /// Get configurable system variables (see 2411 /// [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) 2412 /// 2413 /// Returns the value of a configurable system variable. Most supported 2414 /// variables also have associated compile-time constants, but POSIX 2415 /// allows their values to change at runtime. There are generally two types of 2416 /// sysconf variables: options and limits. See sysconf(3) for more details. 2417 /// 2418 /// # Returns 2419 /// 2420 /// - `Ok(Some(x))`: the variable's limit (for limit variables) or its 2421 /// implementation level (for option variables). Implementation levels are 2422 /// usually a decimal-coded date, such as 200112 for POSIX 2001.12 2423 /// - `Ok(None)`: the variable has no limit (for limit variables) or is 2424 /// unsupported (for option variables) 2425 /// - `Err(x)`: an error occurred sysconf(var: SysconfVar) -> Result<Option<c_long>>2426 pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { 2427 let raw = unsafe { 2428 Errno::clear(); 2429 libc::sysconf(var as c_int) 2430 }; 2431 if raw == -1 { 2432 if errno::errno() == 0 { 2433 Ok(None) 2434 } else { 2435 Err(Error::Sys(Errno::last())) 2436 } 2437 } else { 2438 Ok(Some(raw)) 2439 } 2440 } 2441 2442 #[cfg(any(target_os = "android", target_os = "linux"))] 2443 mod pivot_root { 2444 use crate::{Result, NixPath}; 2445 use crate::errno::Errno; 2446 pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( new_root: &P1, put_old: &P2) -> Result<()>2447 pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( 2448 new_root: &P1, put_old: &P2) -> Result<()> { 2449 let res = new_root.with_nix_path(|new_root| { 2450 put_old.with_nix_path(|put_old| { 2451 unsafe { 2452 libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) 2453 } 2454 }) 2455 })??; 2456 2457 Errno::result(res).map(drop) 2458 } 2459 } 2460 2461 #[cfg(any(target_os = "android", target_os = "freebsd", 2462 target_os = "linux", target_os = "openbsd"))] 2463 mod setres { 2464 use crate::Result; 2465 use crate::errno::Errno; 2466 use super::{Uid, Gid}; 2467 2468 /// Sets the real, effective, and saved uid. 2469 /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) 2470 /// 2471 /// * `ruid`: real user id 2472 /// * `euid`: effective user id 2473 /// * `suid`: saved user id 2474 /// * returns: Ok or libc error code. 2475 /// 2476 /// Err is returned if the user doesn't have permission to set this UID. 2477 #[inline] setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()>2478 pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { 2479 let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; 2480 2481 Errno::result(res).map(drop) 2482 } 2483 2484 /// Sets the real, effective, and saved gid. 2485 /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) 2486 /// 2487 /// * `rgid`: real group id 2488 /// * `egid`: effective group id 2489 /// * `sgid`: saved group id 2490 /// * returns: Ok or libc error code. 2491 /// 2492 /// Err is returned if the user doesn't have permission to set this GID. 2493 #[inline] setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()>2494 pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { 2495 let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; 2496 2497 Errno::result(res).map(drop) 2498 } 2499 } 2500 2501 libc_bitflags!{ 2502 /// Options for access() 2503 pub struct AccessFlags : c_int { 2504 /// Test for existence of file. 2505 F_OK; 2506 /// Test for read permission. 2507 R_OK; 2508 /// Test for write permission. 2509 W_OK; 2510 /// Test for execute (search) permission. 2511 X_OK; 2512 } 2513 } 2514 2515 /// Checks the file named by `path` for accessibility according to the flags given by `amode` 2516 /// See [access(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()>2517 pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> { 2518 let res = path.with_nix_path(|cstr| { 2519 unsafe { 2520 libc::access(cstr.as_ptr(), amode.bits) 2521 } 2522 })?; 2523 Errno::result(res).map(drop) 2524 } 2525 2526 /// Representation of a User, based on `libc::passwd` 2527 /// 2528 /// The reason some fields in this struct are `String` and others are `CString` is because some 2529 /// fields are based on the user's locale, which could be non-UTF8, while other fields are 2530 /// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only 2531 /// contains ASCII. 2532 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2533 #[derive(Debug, Clone, PartialEq)] 2534 pub struct User { 2535 /// Username 2536 pub name: String, 2537 /// User password (probably encrypted) 2538 pub passwd: CString, 2539 /// User ID 2540 pub uid: Uid, 2541 /// Group ID 2542 pub gid: Gid, 2543 /// User information 2544 #[cfg(not(target_os = "android"))] 2545 pub gecos: CString, 2546 /// Home directory 2547 pub dir: PathBuf, 2548 /// Path to shell 2549 pub shell: PathBuf, 2550 /// Login class 2551 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2552 target_os = "linux")))] 2553 pub class: CString, 2554 /// Last password change 2555 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2556 target_os = "linux")))] 2557 pub change: libc::time_t, 2558 /// Expiration time of account 2559 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2560 target_os = "linux")))] 2561 pub expire: libc::time_t 2562 } 2563 2564 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2565 impl From<&libc::passwd> for User { from(pw: &libc::passwd) -> User2566 fn from(pw: &libc::passwd) -> User { 2567 unsafe { 2568 User { 2569 name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(), 2570 passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(), 2571 #[cfg(not(target_os = "android"))] 2572 gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(), 2573 dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())), 2574 shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())), 2575 uid: Uid::from_raw((*pw).pw_uid), 2576 gid: Gid::from_raw((*pw).pw_gid), 2577 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2578 target_os = "linux")))] 2579 class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(), 2580 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2581 target_os = "linux")))] 2582 change: (*pw).pw_change, 2583 #[cfg(not(any(target_os = "android", target_os = "fuchsia", 2584 target_os = "linux")))] 2585 expire: (*pw).pw_expire 2586 } 2587 } 2588 } 2589 } 2590 2591 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2592 impl User { from_anything<F>(f: F) -> Result<Option<Self>> where F: Fn(*mut libc::passwd, *mut libc::c_char, libc::size_t, *mut *mut libc::passwd) -> libc::c_int2593 fn from_anything<F>(f: F) -> Result<Option<Self>> 2594 where 2595 F: Fn(*mut libc::passwd, 2596 *mut libc::c_char, 2597 libc::size_t, 2598 *mut *mut libc::passwd) -> libc::c_int 2599 { 2600 let buflimit = 16384; 2601 let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { 2602 Ok(Some(n)) => n as usize, 2603 Ok(None) | Err(_) => buflimit as usize, 2604 }; 2605 2606 let mut cbuf = Vec::with_capacity(bufsize); 2607 let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit(); 2608 let mut res = ptr::null_mut(); 2609 2610 loop { 2611 let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); 2612 if error == 0 { 2613 if res.is_null() { 2614 return Ok(None); 2615 } else { 2616 let pwd = unsafe { pwd.assume_init() }; 2617 return Ok(Some(User::from(&pwd))); 2618 } 2619 } else if Errno::last() == Errno::ERANGE { 2620 // Trigger the internal buffer resizing logic. 2621 reserve_double_buffer_size(&mut cbuf, buflimit)?; 2622 } else { 2623 return Err(Error::Sys(Errno::last())); 2624 } 2625 } 2626 } 2627 2628 /// Get a user by UID. 2629 /// 2630 /// Internally, this function calls 2631 /// [getpwuid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) 2632 /// 2633 /// # Examples 2634 /// 2635 /// ``` 2636 /// use nix::unistd::{Uid, User}; 2637 /// // Returns an Result<Option<User>>, thus the double unwrap. 2638 /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap(); 2639 /// assert!(res.name == "root"); 2640 /// ``` from_uid(uid: Uid) -> Result<Option<Self>>2641 pub fn from_uid(uid: Uid) -> Result<Option<Self>> { 2642 User::from_anything(|pwd, cbuf, cap, res| { 2643 unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) } 2644 }) 2645 } 2646 2647 /// Get a user by name. 2648 /// 2649 /// Internally, this function calls 2650 /// [getpwnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) 2651 /// 2652 /// # Examples 2653 /// 2654 /// ``` 2655 /// use nix::unistd::User; 2656 /// // Returns an Result<Option<User>>, thus the double unwrap. 2657 /// let res = User::from_name("root").unwrap().unwrap(); 2658 /// assert!(res.name == "root"); 2659 /// ``` from_name(name: &str) -> Result<Option<Self>>2660 pub fn from_name(name: &str) -> Result<Option<Self>> { 2661 let name = CString::new(name).unwrap(); 2662 User::from_anything(|pwd, cbuf, cap, res| { 2663 unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } 2664 }) 2665 } 2666 } 2667 2668 /// Representation of a Group, based on `libc::group` 2669 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2670 #[derive(Debug, Clone, PartialEq)] 2671 pub struct Group { 2672 /// Group name 2673 pub name: String, 2674 /// Group password 2675 pub passwd: CString, 2676 /// Group ID 2677 pub gid: Gid, 2678 /// List of Group members 2679 pub mem: Vec<String> 2680 } 2681 2682 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2683 impl From<&libc::group> for Group { from(gr: &libc::group) -> Group2684 fn from(gr: &libc::group) -> Group { 2685 unsafe { 2686 Group { 2687 name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(), 2688 passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(), 2689 gid: Gid::from_raw((*gr).gr_gid), 2690 mem: Group::members((*gr).gr_mem) 2691 } 2692 } 2693 } 2694 } 2695 2696 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd 2697 impl Group { members(mem: *mut *mut c_char) -> Vec<String>2698 unsafe fn members(mem: *mut *mut c_char) -> Vec<String> { 2699 let mut ret = Vec::new(); 2700 2701 for i in 0.. { 2702 let u = mem.offset(i); 2703 if (*u).is_null() { 2704 break; 2705 } else { 2706 let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); 2707 ret.push(s); 2708 } 2709 } 2710 2711 ret 2712 } 2713 from_anything<F>(f: F) -> Result<Option<Self>> where F: Fn(*mut libc::group, *mut libc::c_char, libc::size_t, *mut *mut libc::group) -> libc::c_int2714 fn from_anything<F>(f: F) -> Result<Option<Self>> 2715 where 2716 F: Fn(*mut libc::group, 2717 *mut libc::c_char, 2718 libc::size_t, 2719 *mut *mut libc::group) -> libc::c_int 2720 { 2721 let buflimit = 16384; 2722 let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { 2723 Ok(Some(n)) => n as usize, 2724 Ok(None) | Err(_) => buflimit as usize, 2725 }; 2726 2727 let mut cbuf = Vec::with_capacity(bufsize); 2728 let mut grp = mem::MaybeUninit::<libc::group>::uninit(); 2729 let mut res = ptr::null_mut(); 2730 2731 loop { 2732 let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); 2733 if error == 0 { 2734 if res.is_null() { 2735 return Ok(None); 2736 } else { 2737 let grp = unsafe { grp.assume_init() }; 2738 return Ok(Some(Group::from(&grp))); 2739 } 2740 } else if Errno::last() == Errno::ERANGE { 2741 // Trigger the internal buffer resizing logic. 2742 reserve_double_buffer_size(&mut cbuf, buflimit)?; 2743 } else { 2744 return Err(Error::Sys(Errno::last())); 2745 } 2746 } 2747 } 2748 2749 /// Get a group by GID. 2750 /// 2751 /// Internally, this function calls 2752 /// [getgrgid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) 2753 /// 2754 /// # Examples 2755 /// 2756 // Disable this test on all OS except Linux as root group may not exist. 2757 #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] 2758 #[cfg_attr(target_os = "linux", doc = " ```")] 2759 /// use nix::unistd::{Gid, Group}; 2760 /// // Returns an Result<Option<Group>>, thus the double unwrap. 2761 /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap(); 2762 /// assert!(res.name == "root"); 2763 /// ``` from_gid(gid: Gid) -> Result<Option<Self>>2764 pub fn from_gid(gid: Gid) -> Result<Option<Self>> { 2765 Group::from_anything(|grp, cbuf, cap, res| { 2766 unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) } 2767 }) 2768 } 2769 2770 /// Get a group by name. 2771 /// 2772 /// Internally, this function calls 2773 /// [getgrnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) 2774 /// 2775 /// # Examples 2776 /// 2777 // Disable this test on all OS except Linux as root group may not exist. 2778 #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] 2779 #[cfg_attr(target_os = "linux", doc = " ```")] 2780 /// use nix::unistd::Group; 2781 /// // Returns an Result<Option<Group>>, thus the double unwrap. 2782 /// let res = Group::from_name("root").unwrap().unwrap(); 2783 /// assert!(res.name == "root"); 2784 /// ``` from_name(name: &str) -> Result<Option<Self>>2785 pub fn from_name(name: &str) -> Result<Option<Self>> { 2786 let name = CString::new(name).unwrap(); 2787 Group::from_anything(|grp, cbuf, cap, res| { 2788 unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } 2789 }) 2790 } 2791 } 2792 2793 /// Get the name of the terminal device that is open on file descriptor fd 2794 /// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)). 2795 #[cfg(not(target_os = "fuchsia"))] ttyname(fd: RawFd) -> Result<PathBuf>2796 pub fn ttyname(fd: RawFd) -> Result<PathBuf> { 2797 const PATH_MAX: usize = libc::PATH_MAX as usize; 2798 let mut buf = vec![0_u8; PATH_MAX]; 2799 let c_buf = buf.as_mut_ptr() as *mut libc::c_char; 2800 2801 let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; 2802 if ret != 0 { 2803 return Err(Error::Sys(Errno::from_i32(ret))); 2804 } 2805 2806 let nul = buf.iter().position(|c| *c == b'\0').unwrap(); 2807 buf.truncate(nul); 2808 Ok(OsString::from_vec(buf).into()) 2809 } 2810 2811 /// Get the effective user ID and group ID associated with a Unix domain socket. 2812 /// 2813 /// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) 2814 #[cfg(any( 2815 target_os = "macos", 2816 target_os = "ios", 2817 target_os = "freebsd", 2818 target_os = "openbsd", 2819 target_os = "netbsd", 2820 target_os = "dragonfly", 2821 ))] getpeereid(fd: RawFd) -> Result<(Uid, Gid)>2822 pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { 2823 let mut uid = 1; 2824 let mut gid = 1; 2825 2826 let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; 2827 2828 Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) 2829 } 2830