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