diff options
Diffstat (limited to 'vendor/nix/src/sys')
37 files changed, 0 insertions, 19932 deletions
diff --git a/vendor/nix/src/sys/aio.rs b/vendor/nix/src/sys/aio.rs deleted file mode 100644 index e2ce19b79..000000000 --- a/vendor/nix/src/sys/aio.rs +++ /dev/null @@ -1,1241 +0,0 @@ -// vim: tw=80 -//! POSIX Asynchronous I/O -//! -//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like -//! devices. It supports [`read`](struct.AioRead.html#method.new), -//! [`write`](struct.AioWrite.html#method.new), -//! [`fsync`](struct.AioFsync.html#method.new), -//! [`readv`](struct.AioReadv.html#method.new), and -//! [`writev`](struct.AioWritev.html#method.new), operations, subject to -//! platform support. Completion -//! notifications can optionally be delivered via -//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the -//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some -//! platforms support other completion -//! notifications, such as -//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent). -//! -//! Multiple operations may be submitted in a batch with -//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee -//! that they will be executed atomically. -//! -//! Outstanding operations may be cancelled with -//! [`cancel`](trait.Aio.html#method.cancel) or -//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may -//! not support this for all filesystems and devices. -#[cfg(target_os = "freebsd")] -use std::io::{IoSlice, IoSliceMut}; -use std::{ - convert::TryFrom, - fmt::{self, Debug}, - marker::{PhantomData, PhantomPinned}, - mem, - os::unix::io::RawFd, - pin::Pin, - ptr, thread, -}; - -use libc::{c_void, off_t}; -use pin_utils::unsafe_pinned; - -use crate::{ - errno::Errno, - sys::{signal::*, time::TimeSpec}, - Result, -}; - -libc_enum! { - /// Mode for `AioCb::fsync`. Controls whether only data or both data and - /// metadata are synced. - #[repr(i32)] - #[non_exhaustive] - pub enum AioFsyncMode { - /// do it like `fsync` - O_SYNC, - /// on supported operating systems only, do it like `fdatasync` - #[cfg(any(target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_DSYNC - } - impl TryFrom<i32> -} - -libc_enum! { - /// Mode for [`lio_listio`](fn.lio_listio.html) - #[repr(i32)] - pub enum LioMode { - /// Requests that [`lio_listio`](fn.lio_listio.html) block until all - /// requested operations have been completed - LIO_WAIT, - /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately - LIO_NOWAIT, - } -} - -/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and -/// [`aio_cancel_all`](fn.aio_cancel_all.html) -#[repr(i32)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum AioCancelStat { - /// All outstanding requests were canceled - AioCanceled = libc::AIO_CANCELED, - /// Some requests were not canceled. Their status should be checked with - /// `AioCb::error` - AioNotCanceled = libc::AIO_NOTCANCELED, - /// All of the requests have already finished - AioAllDone = libc::AIO_ALLDONE, -} - -/// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers -#[repr(transparent)] -struct LibcAiocb(libc::aiocb); - -unsafe impl Send for LibcAiocb {} -unsafe impl Sync for LibcAiocb {} - -/// Base class for all AIO operations. Should only be used directly when -/// checking for completion. -// We could create some kind of AsPinnedMut trait, and implement it for all aio -// ops, allowing the crate's users to get pinned references to `AioCb`. That -// could save some code for things like polling methods. But IMHO it would -// provide polymorphism at the wrong level. Instead, the best place for -// polymorphism is at the level of `Futures`. -#[repr(C)] -struct AioCb { - aiocb: LibcAiocb, - /// Could this `AioCb` potentially have any in-kernel state? - // It would be really nice to perform the in-progress check entirely at - // compile time. But I can't figure out how, because: - // * Future::poll takes a `Pin<&mut self>` rather than `self`, and - // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means - // that there's no way to write an AioCb constructor that neither boxes - // the object itself, nor moves it during return. - in_progress: bool, -} - -impl AioCb { - pin_utils::unsafe_unpinned!(aiocb: LibcAiocb); - - fn aio_return(mut self: Pin<&mut Self>) -> Result<usize> { - self.in_progress = false; - unsafe { - let p: *mut libc::aiocb = &mut self.aiocb.0; - Errno::result(libc::aio_return(p)) - } - .map(|r| r as usize) - } - - fn cancel(mut self: Pin<&mut Self>) -> Result<AioCancelStat> { - let r = unsafe { - libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0) - }; - match r { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value"), - } - } - - fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self { - // Use mem::zeroed instead of explicitly zeroing each field, because the - // number and name of reserved fields is OS-dependent. On some OSes, - // some reserved fields are used the kernel for state, and must be - // explicitly zeroed when allocated. - let mut a = unsafe { mem::zeroed::<libc::aiocb>() }; - a.aio_fildes = fd; - a.aio_reqprio = prio; - a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - AioCb { - aiocb: LibcAiocb(a), - in_progress: false, - } - } - - fn error(self: Pin<&mut Self>) -> Result<()> { - let r = unsafe { libc::aio_error(&self.aiocb().0) }; - match r { - 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), - -1 => Err(Errno::last()), - num => panic!("unknown aio_error return value {:?}", num), - } - } - - fn in_progress(&self) -> bool { - self.in_progress - } - - fn set_in_progress(mut self: Pin<&mut Self>) { - self.as_mut().in_progress = true; - } - - /// Update the notification settings for an existing AIO operation that has - /// not yet been submitted. - // Takes a normal reference rather than a pinned one because this method is - // normally called before the object needs to be pinned, that is, before - // it's been submitted to the kernel. - fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { - assert!( - !self.in_progress, - "Can't change notification settings for an in-progress operation" - ); - self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - } -} - -impl Debug for AioCb { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("AioCb") - .field("aiocb", &self.aiocb.0) - .field("in_progress", &self.in_progress) - .finish() - } -} - -impl Drop for AioCb { - /// If the `AioCb` has no remaining state in the kernel, just drop it. - /// Otherwise, dropping constitutes a resource leak, which is an error - fn drop(&mut self) { - assert!( - thread::panicking() || !self.in_progress, - "Dropped an in-progress AioCb" - ); - } -} - -/// Methods common to all AIO operations -pub trait Aio { - /// The return type of [`Aio::aio_return`]. - type Output; - - /// Retrieve return status of an asynchronous operation. - /// - /// Should only be called once for each operation, after [`Aio::error`] - /// indicates that it has completed. The result is the same as for the - /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions. - /// - /// # References - /// - /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) - fn aio_return(self: Pin<&mut Self>) -> Result<Self::Output>; - - /// Cancels an outstanding AIO request. - /// - /// The operating system is not required to implement cancellation for all - /// file and device types. Even if it does, there is no guarantee that the - /// operation has not already completed. So the caller must check the - /// result and handle operations that were not canceled or that have already - /// completed. - /// - /// # Examples - /// - /// Cancel an outstanding aio operation. Note that we must still call - /// `aio_return` to free resources, even though we don't care about the - /// result. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::io::Write; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// let wbuf = b"CDEF"; - /// let mut f = tempfile().unwrap(); - /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), - /// 2, //offset - /// &wbuf[..], - /// 0, //priority - /// SigevNotify::SigevNone)); - /// aiocb.as_mut().submit().unwrap(); - /// let cs = aiocb.as_mut().cancel().unwrap(); - /// if cs == AioCancelStat::AioNotCanceled { - /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// } - /// // Must call `aio_return`, but ignore the result - /// let _ = aiocb.as_mut().aio_return(); - /// ``` - /// - /// # References - /// - /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) - fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat>; - - /// Retrieve error status of an asynchronous operation. - /// - /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise, - /// returns `Ok` or any other error. - /// - /// # Examples - /// - /// Issue an aio operation and use `error` to poll for completion. Polling - /// is an alternative to `aio_suspend`, used by most of the other examples. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// const WBUF: &[u8] = b"abcdef123456"; - /// let mut f = tempfile().unwrap(); - /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone)); - /// aiocb.as_mut().submit().unwrap(); - /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len()); - /// ``` - /// - /// # References - /// - /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) - fn error(self: Pin<&mut Self>) -> Result<()>; - - /// Returns the underlying file descriptor associated with the operation. - fn fd(&self) -> RawFd; - - /// Does this operation currently have any in-kernel state? - /// - /// Dropping an operation that does have in-kernel state constitutes a - /// resource leak. - /// - /// # Examples - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify::SigevNone; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// let f = tempfile().unwrap(); - /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, - /// 0, SigevNone)); - /// assert!(!aiof.as_mut().in_progress()); - /// aiof.as_mut().submit().expect("aio_fsync failed early"); - /// assert!(aiof.as_mut().in_progress()); - /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); - /// assert!(!aiof.as_mut().in_progress()); - /// ``` - fn in_progress(&self) -> bool; - - /// Returns the priority of the `AioCb` - fn priority(&self) -> i32; - - /// Update the notification settings for an existing AIO operation that has - /// not yet been submitted. - fn set_sigev_notify(&mut self, sev: SigevNotify); - - /// Returns the `SigEvent` that will be used for notification. - fn sigevent(&self) -> SigEvent; - - /// Actually start the I/O operation. - /// - /// After calling this method and until [`Aio::aio_return`] returns `Ok`, - /// the structure may not be moved in memory. - fn submit(self: Pin<&mut Self>) -> Result<()>; -} - -macro_rules! aio_methods { - () => { - fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat> { - self.aiocb().cancel() - } - - fn error(self: Pin<&mut Self>) -> Result<()> { - self.aiocb().error() - } - - fn fd(&self) -> RawFd { - self.aiocb.aiocb.0.aio_fildes - } - - fn in_progress(&self) -> bool { - self.aiocb.in_progress() - } - - fn priority(&self) -> i32 { - self.aiocb.aiocb.0.aio_reqprio - } - - fn set_sigev_notify(&mut self, sev: SigevNotify) { - self.aiocb.set_sigev_notify(sev) - } - - fn sigevent(&self) -> SigEvent { - SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent) - } - }; - ($func:ident) => { - aio_methods!(); - - fn aio_return(self: Pin<&mut Self>) -> Result<<Self as Aio>::Output> { - self.aiocb().aio_return() - } - - fn submit(mut self: Pin<&mut Self>) -> Result<()> { - let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0; - Errno::result({ unsafe { libc::$func(p) } }).map(|_| { - self.aiocb().set_in_progress(); - }) - } - }; -} - -/// An asynchronous version of `fsync(2)`. -/// -/// # References -/// -/// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) -/// # Examples -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify::SigevNone; -/// # use std::{thread, time}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// let f = tempfile().unwrap(); -/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, -/// 0, SigevNone)); -/// aiof.as_mut().submit().expect("aio_fsync failed early"); -/// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// aiof.as_mut().aio_return().expect("aio_fsync failed late"); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioFsync { - aiocb: AioCb, - _pin: PhantomPinned, -} - -impl AioFsync { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the operation's fsync mode: data and metadata or data only? - pub fn mode(&self) -> AioFsyncMode { - AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap() - } - - /// Create a new `AioFsync`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to sync. - /// * `mode`: Whether to sync file metadata too, or just data. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio`. - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - mode: AioFsyncMode, - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // To save some memory, store mode in an unused field of the AioCb. - // True it isn't very much memory, but downstream creates will likely - // create an enum containing this and other AioCb variants and pack - // those enums into data structures like Vec, so it adds up. - aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int; - AioFsync { - aiocb, - _pin: PhantomPinned, - } - } -} - -impl Aio for AioFsync { - type Output = (); - - aio_methods!(); - - fn aio_return(self: Pin<&mut Self>) -> Result<()> { - self.aiocb().aio_return().map(drop) - } - - fn submit(mut self: Pin<&mut Self>) -> Result<()> { - let aiocb = &mut self.as_mut().aiocb().aiocb.0; - let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0); - let p: *mut libc::aiocb = aiocb; - Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| { - self.aiocb().set_in_progress(); - }) - } -} - -// AioFsync does not need AsMut, since it can't be used with lio_listio - -impl AsRef<libc::aiocb> for AioFsync { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously reads from a file descriptor into a buffer -/// -/// # References -/// -/// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) -/// -/// # Examples -/// -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::Write; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"abcdef123456"; -/// const LEN: usize = 4; -/// let mut rbuf = vec![0; LEN]; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// { -/// let mut aior = Box::pin( -/// AioRead::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &mut rbuf, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aior.as_mut().submit().unwrap(); -/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aior.as_mut().aio_return().unwrap(), LEN); -/// } -/// assert_eq!(rbuf, b"cdef"); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioRead<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, -} - -impl<'a> AioRead<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the requested length of the aio operation in bytes - /// - /// This method returns the *requested* length of the operation. To get the - /// number of bytes actually read or written by a completed operation, use - /// `aio_return` instead. - pub fn nbytes(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Create a new `AioRead`, placing the data in a mutable slice. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to read from - /// * `offs`: File offset - /// * `buf`: A memory buffer. It must outlive the `AioRead`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - buf: &'a mut [u8], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - aiocb.aiocb.0.aio_nbytes = buf.len(); - aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; - aiocb.aiocb.0.aio_offset = offs; - AioRead { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -impl<'a> Aio for AioRead<'a> { - type Output = usize; - - aio_methods!(aio_read); -} - -impl<'a> AsMut<libc::aiocb> for AioRead<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -impl<'a> AsRef<libc::aiocb> for AioRead<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously reads from a file descriptor into a scatter/gather list of buffers. -/// -/// # References -/// -/// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv) -/// -/// # Examples -/// -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::{IoSliceMut, Write}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"abcdef123456"; -/// let mut rbuf0 = vec![0; 4]; -/// let mut rbuf1 = vec![0; 2]; -/// let expected_len = rbuf0.len() + rbuf1.len(); -/// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// { -/// let mut aior = Box::pin( -/// AioReadv::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &mut rbufs, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aior.as_mut().submit().unwrap(); -/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len); -/// } -/// assert_eq!(rbuf0, b"cdef"); -/// assert_eq!(rbuf1, b"12"); -/// ``` -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -#[repr(transparent)] -pub struct AioReadv<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, -} - -#[cfg(target_os = "freebsd")] -impl<'a> AioReadv<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the number of buffers the operation will read into. - pub fn iovlen(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Create a new `AioReadv`, placing the data in a list of mutable slices. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to read from - /// * `offs`: File offset - /// * `bufs`: A scatter/gather list of memory buffers. They must - /// outlive the `AioReadv`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - bufs: &mut [IoSliceMut<'a>], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // In vectored mode, aio_nbytes stores the length of the iovec array, - // not the byte count. - aiocb.aiocb.0.aio_nbytes = bufs.len(); - aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; - aiocb.aiocb.0.aio_offset = offs; - AioReadv { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Aio for AioReadv<'a> { - type Output = usize; - - aio_methods!(aio_readv); -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsMut<libc::aiocb> for AioReadv<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsRef<libc::aiocb> for AioReadv<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously writes from a buffer to a file descriptor -/// -/// # References -/// -/// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) -/// -/// # Examples -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin( -/// AioWrite::new( -/// f.as_raw_fd(), -/// 2, //offset -/// WBUF, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aiow.as_mut().submit().unwrap(); -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioWrite<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, -} - -impl<'a> AioWrite<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the requested length of the aio operation in bytes - /// - /// This method returns the *requested* length of the operation. To get the - /// number of bytes actually read or written by a completed operation, use - /// `aio_return` instead. - pub fn nbytes(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Construct a new `AioWrite`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to write to - /// * `offs`: File offset - /// * `buf`: A memory buffer. It must outlive the `AioWrite`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - buf: &'a [u8], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - aiocb.aiocb.0.aio_nbytes = buf.len(); - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. Type Safety guarantees that we'll never pass aiocb to - // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; - aiocb.aiocb.0.aio_offset = offs; - AioWrite { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -impl<'a> Aio for AioWrite<'a> { - type Output = usize; - - aio_methods!(aio_write); -} - -impl<'a> AsMut<libc::aiocb> for AioWrite<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -impl<'a> AsRef<libc::aiocb> for AioWrite<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously writes from a scatter/gather list of buffers to a file descriptor. -/// -/// # References -/// -/// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev) -/// -/// # Examples -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::IoSlice; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const wbuf0: &[u8] = b"abcdef"; -/// const wbuf1: &[u8] = b"123456"; -/// let len = wbuf0.len() + wbuf1.len(); -/// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin( -/// AioWritev::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &wbufs, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aiow.as_mut().submit().unwrap(); -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), len); -/// ``` -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -#[repr(transparent)] -pub struct AioWritev<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, -} - -#[cfg(target_os = "freebsd")] -impl<'a> AioWritev<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the number of buffers the operation will read into. - pub fn iovlen(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Construct a new `AioWritev`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to write to - /// * `offs`: File offset - /// * `bufs`: A scatter/gather list of memory buffers. They must - /// outlive the `AioWritev`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - bufs: &[IoSlice<'a>], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // In vectored mode, aio_nbytes stores the length of the iovec array, - // not the byte count. - aiocb.aiocb.0.aio_nbytes = bufs.len(); - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. Type Safety guarantees that we'll never pass aiocb to - // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; - aiocb.aiocb.0.aio_offset = offs; - AioWritev { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Aio for AioWritev<'a> { - type Output = usize; - - aio_methods!(aio_writev); -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsMut<libc::aiocb> for AioWritev<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsRef<libc::aiocb> for AioWritev<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Cancels outstanding AIO requests for a given file descriptor. -/// -/// # Examples -/// -/// Issue an aio operation, then cancel all outstanding operations on that file -/// descriptor. -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::Write; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// let wbuf = b"CDEF"; -/// let mut f = tempfile().unwrap(); -/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), -/// 2, //offset -/// &wbuf[..], -/// 0, //priority -/// SigevNotify::SigevNone)); -/// aiocb.as_mut().submit().unwrap(); -/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); -/// if cs == AioCancelStat::AioNotCanceled { -/// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// } -/// // Must call `aio_return`, but ignore the result -/// let _ = aiocb.as_mut().aio_return(); -/// ``` -/// -/// # References -/// -/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) -pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { - match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value"), - } -} - -/// Suspends the calling process until at least one of the specified operations -/// have completed, a signal is delivered, or the timeout has passed. -/// -/// If `timeout` is `None`, `aio_suspend` will block indefinitely. -/// -/// # Examples -/// -/// Use `aio_suspend` to block until an aio operation completes. -/// -/// ``` -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), -/// 2, //offset -/// WBUF, -/// 0, //priority -/// SigevNotify::SigevNone)); -/// aiocb.as_mut().submit().unwrap(); -/// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed"); -/// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len()); -/// ``` -/// # References -/// -/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) -pub fn aio_suspend( - list: &[&dyn AsRef<libc::aiocb>], - timeout: Option<TimeSpec>, -) -> Result<()> { - let p = list as *const [&dyn AsRef<libc::aiocb>] - as *const [*const libc::aiocb] as *const *const libc::aiocb; - let timep = match timeout { - None => ptr::null::<libc::timespec>(), - Some(x) => x.as_ref() as *const libc::timespec, - }; - Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) }) - .map(drop) -} - -/// Submits multiple asynchronous I/O requests with a single system call. -/// -/// They are not guaranteed to complete atomically, and the order in which the -/// requests are carried out is not specified. Reads, and writes may be freely -/// mixed. -/// -/// # Examples -/// -/// Use `lio_listio` to submit an aio operation and wait for its completion. In -/// this case, there is no need to use aio_suspend to wait or `error` to poll. -/// This mode is useful for otherwise-synchronous programs that want to execute -/// a handful of I/O operations in parallel. -/// ``` -/// # use std::os::unix::io::AsRawFd; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) -/// .unwrap(); -/// // At this point, we are guaranteed that aiow is complete. -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -/// -/// Use `lio_listio` to submit multiple asynchronous operations with a single -/// syscall, but receive notification individually. This is an efficient -/// technique for reducing overall context-switch overhead, especially when -/// combined with kqueue. -/// ``` -/// # use std::os::unix::io::AsRawFd; -/// # use std::thread; -/// # use std::time; -/// # use nix::errno::Errno; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) -/// .unwrap(); -/// // We must wait for the completion of each individual operation -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -/// -/// Use `lio_listio` to submit multiple operations, and receive notification -/// only when all of them are complete. This can be useful when there is some -/// logical relationship between the operations. But beware! Errors or system -/// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or -/// `EINTR`, in which case some but not all operations may have been submitted. -/// In that case, you must check the status of each individual operation, and -/// possibly resubmit some. -/// ``` -/// # use libc::c_int; -/// # use std::os::unix::io::AsRawFd; -/// # use std::sync::atomic::{AtomicBool, Ordering}; -/// # use std::thread; -/// # use std::time; -/// # use lazy_static::lazy_static; -/// # use nix::errno::Errno; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::*; -/// # use tempfile::tempfile; -/// lazy_static! { -/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); -/// } -/// -/// extern fn sigfunc(_: c_int) { -/// SIGNALED.store(true, Ordering::Relaxed); -/// } -/// let sa = SigAction::new(SigHandler::Handler(sigfunc), -/// SaFlags::SA_RESETHAND, -/// SigSet::empty()); -/// SIGNALED.store(false, Ordering::Relaxed); -/// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); -/// -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; -/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); -/// while !SIGNALED.load(Ordering::Relaxed) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// // At this point, since `lio_listio` returned success and delivered its -/// // notification, we know that all operations are complete. -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -pub fn lio_listio( - mode: LioMode, - list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>], - sigev_notify: SigevNotify, -) -> Result<()> { - let p = list as *mut [Pin<&mut dyn AsMut<libc::aiocb>>] - as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb; - let sigev = SigEvent::new(sigev_notify); - let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; - Errno::result(unsafe { - libc::lio_listio(mode as i32, p, list.len() as i32, sigevp) - }) - .map(drop) -} - -#[cfg(test)] -mod t { - use super::*; - - /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb - /// pointers. This test ensures that such casts are valid. - #[test] - fn casting() { - let sev = SigevNotify::SigevNone; - let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); - assert_eq!( - aiof.as_ref() as *const libc::aiocb, - &aiof as *const AioFsync as *const libc::aiocb - ); - - let mut rbuf = []; - let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); - assert_eq!( - aior.as_ref() as *const libc::aiocb, - &aior as *const AioRead as *const libc::aiocb - ); - - let wbuf = []; - let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); - assert_eq!( - aiow.as_ref() as *const libc::aiocb, - &aiow as *const AioWrite as *const libc::aiocb - ); - } - - #[cfg(target_os = "freebsd")] - #[test] - fn casting_vectored() { - let sev = SigevNotify::SigevNone; - - let mut rbuf = []; - let mut rbufs = [IoSliceMut::new(&mut rbuf)]; - let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); - assert_eq!( - aiorv.as_ref() as *const libc::aiocb, - &aiorv as *const AioReadv as *const libc::aiocb - ); - - let wbuf = []; - let wbufs = [IoSlice::new(&wbuf)]; - let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); - assert_eq!( - aiowv.as_ref() as *const libc::aiocb, - &aiowv as *const AioWritev as *const libc::aiocb - ); - } -} diff --git a/vendor/nix/src/sys/epoll.rs b/vendor/nix/src/sys/epoll.rs deleted file mode 100644 index 58def2e78..000000000 --- a/vendor/nix/src/sys/epoll.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::errno::Errno; -use crate::Result; -use libc::{self, c_int}; -use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; - -libc_bitflags!( - pub struct EpollFlags: c_int { - EPOLLIN; - EPOLLPRI; - EPOLLOUT; - EPOLLRDNORM; - EPOLLRDBAND; - EPOLLWRNORM; - EPOLLWRBAND; - EPOLLMSG; - EPOLLERR; - EPOLLHUP; - EPOLLRDHUP; - EPOLLEXCLUSIVE; - #[cfg(not(target_arch = "mips"))] - EPOLLWAKEUP; - EPOLLONESHOT; - EPOLLET; - } -); - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -#[non_exhaustive] -pub enum EpollOp { - EpollCtlAdd = libc::EPOLL_CTL_ADD, - EpollCtlDel = libc::EPOLL_CTL_DEL, - EpollCtlMod = libc::EPOLL_CTL_MOD, -} - -libc_bitflags! { - pub struct EpollCreateFlags: c_int { - EPOLL_CLOEXEC; - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct EpollEvent { - event: libc::epoll_event, -} - -impl EpollEvent { - pub fn new(events: EpollFlags, data: u64) -> Self { - EpollEvent { - event: libc::epoll_event { - events: events.bits() as u32, - u64: data, - }, - } - } - - pub fn empty() -> Self { - unsafe { mem::zeroed::<EpollEvent>() } - } - - pub fn events(&self) -> EpollFlags { - EpollFlags::from_bits(self.event.events as c_int).unwrap() - } - - pub fn data(&self) -> u64 { - self.event.u64 - } -} - -#[inline] -pub fn epoll_create() -> Result<RawFd> { - let res = unsafe { libc::epoll_create(1024) }; - - Errno::result(res) -} - -#[inline] -pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> { - let res = unsafe { libc::epoll_create1(flags.bits()) }; - - Errno::result(res) -} - -#[inline] -pub fn epoll_ctl<'a, T>( - epfd: RawFd, - op: EpollOp, - fd: RawFd, - event: T, -) -> Result<()> -where - T: Into<Option<&'a mut EpollEvent>>, -{ - let mut event: Option<&mut EpollEvent> = event.into(); - if event.is_none() && op != EpollOp::EpollCtlDel { - Err(Errno::EINVAL) - } else { - let res = unsafe { - if let Some(ref mut event) = event { - libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) - } else { - libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut()) - } - }; - Errno::result(res).map(drop) - } -} - -#[inline] -pub fn epoll_wait( - epfd: RawFd, - events: &mut [EpollEvent], - timeout_ms: isize, -) -> Result<usize> { - let res = unsafe { - libc::epoll_wait( - epfd, - events.as_mut_ptr() as *mut libc::epoll_event, - events.len() as c_int, - timeout_ms as c_int, - ) - }; - - Errno::result(res).map(|r| r as usize) -} diff --git a/vendor/nix/src/sys/event.rs b/vendor/nix/src/sys/event.rs deleted file mode 100644 index d8ad628ea..000000000 --- a/vendor/nix/src/sys/event.rs +++ /dev/null @@ -1,374 +0,0 @@ -/* TOOD: Implement for other kqueue based systems - */ - -use crate::{Errno, Result}; -#[cfg(not(target_os = "netbsd"))] -use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; -#[cfg(target_os = "netbsd")] -use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; -use std::convert::TryInto; -use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; - -// Redefine kevent in terms of programmer-friendly enums and bitfields. -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct KEvent { - kevent: libc::kevent, -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -type type_of_udata = *mut libc::c_void; -#[cfg(any(target_os = "netbsd"))] -type type_of_udata = intptr_t; - -#[cfg(target_os = "netbsd")] -type type_of_event_filter = u32; -#[cfg(not(target_os = "netbsd"))] -type type_of_event_filter = i16; -libc_enum! { - #[cfg_attr(target_os = "netbsd", repr(u32))] - #[cfg_attr(not(target_os = "netbsd"), repr(i16))] - #[non_exhaustive] - pub enum EventFilter { - EVFILT_AIO, - /// Returns whenever there is no remaining data in the write buffer - #[cfg(target_os = "freebsd")] - EVFILT_EMPTY, - #[cfg(target_os = "dragonfly")] - EVFILT_EXCEPT, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] - EVFILT_FS, - #[cfg(target_os = "freebsd")] - EVFILT_LIO, - #[cfg(any(target_os = "ios", target_os = "macos"))] - EVFILT_MACHPORT, - EVFILT_PROC, - /// Returns events associated with the process referenced by a given - /// process descriptor, created by `pdfork()`. The events to monitor are: - /// - /// - NOTE_EXIT: the process has exited. The exit status will be stored in data. - #[cfg(target_os = "freebsd")] - EVFILT_PROCDESC, - EVFILT_READ, - /// Returns whenever an asynchronous `sendfile()` call completes. - #[cfg(target_os = "freebsd")] - EVFILT_SENDFILE, - EVFILT_SIGNAL, - EVFILT_TIMER, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] - EVFILT_USER, - #[cfg(any(target_os = "ios", target_os = "macos"))] - EVFILT_VM, - EVFILT_VNODE, - EVFILT_WRITE, - } - impl TryFrom<type_of_event_filter> -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub type type_of_event_flag = u16; -#[cfg(any(target_os = "netbsd"))] -pub type type_of_event_flag = u32; -libc_bitflags! { - pub struct EventFlag: type_of_event_flag { - EV_ADD; - EV_CLEAR; - EV_DELETE; - EV_DISABLE; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - EV_DISPATCH; - #[cfg(target_os = "freebsd")] - EV_DROP; - EV_ENABLE; - EV_EOF; - EV_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_FLAG0; - EV_FLAG1; - #[cfg(target_os = "dragonfly")] - EV_NODATA; - EV_ONESHOT; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_OOBAND; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_POLL; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - EV_RECEIPT; - } -} - -libc_bitflags!( - pub struct FilterFlag: u32 { - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_ABSOLUTE; - NOTE_ATTRIB; - NOTE_CHILD; - NOTE_DELETE; - #[cfg(target_os = "openbsd")] - NOTE_EOF; - NOTE_EXEC; - NOTE_EXIT; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_EXITSTATUS; - NOTE_EXTEND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFAND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFCOPY; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFCTRLMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFLAGSMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFNOP; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFOR; - NOTE_FORK; - NOTE_LINK; - NOTE_LOWAT; - #[cfg(target_os = "freebsd")] - NOTE_MSECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_NONE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_NSECONDS; - #[cfg(target_os = "dragonfly")] - NOTE_OOB; - NOTE_PCTRLMASK; - NOTE_PDATAMASK; - NOTE_RENAME; - NOTE_REVOKE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_SECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_SIGNAL; - NOTE_TRACK; - NOTE_TRACKERR; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_TRIGGER; - #[cfg(target_os = "openbsd")] - NOTE_TRUNCATE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_USECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE_SUDDEN_TERMINATE; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE_TERMINATE; - NOTE_WRITE; - } -); - -pub fn kqueue() -> Result<RawFd> { - let res = unsafe { libc::kqueue() }; - - Errno::result(res) -} - -// KEvent can't derive Send because on some operating systems, udata is defined -// as a void*. However, KEvent's public API always treats udata as an intptr_t, -// which is safe to Send. -unsafe impl Send for KEvent {} - -impl KEvent { - #[allow(clippy::needless_update)] // Not needless on all platforms. - pub fn new( - ident: uintptr_t, - filter: EventFilter, - flags: EventFlag, - fflags: FilterFlag, - data: intptr_t, - udata: intptr_t, - ) -> KEvent { - KEvent { - kevent: libc::kevent { - ident, - filter: filter as type_of_event_filter, - flags: flags.bits(), - fflags: fflags.bits(), - // data can be either i64 or intptr_t, depending on platform - data: data as _, - udata: udata as type_of_udata, - ..unsafe { mem::zeroed() } - }, - } - } - - pub fn ident(&self) -> uintptr_t { - self.kevent.ident - } - - pub fn filter(&self) -> Result<EventFilter> { - self.kevent.filter.try_into() - } - - pub fn flags(&self) -> EventFlag { - EventFlag::from_bits(self.kevent.flags).unwrap() - } - - pub fn fflags(&self) -> FilterFlag { - FilterFlag::from_bits(self.kevent.fflags).unwrap() - } - - pub fn data(&self) -> intptr_t { - self.kevent.data as intptr_t - } - - pub fn udata(&self) -> intptr_t { - self.kevent.udata as intptr_t - } -} - -pub fn kevent( - kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_ms: usize, -) -> Result<usize> { - // Convert ms to timespec - let timeout = timespec { - tv_sec: (timeout_ms / 1000) as time_t, - tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long, - }; - - kevent_ts(kq, changelist, eventlist, Some(timeout)) -} - -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -))] -type type_of_nchanges = c_int; -#[cfg(target_os = "netbsd")] -type type_of_nchanges = size_t; - -pub fn kevent_ts( - kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_opt: Option<timespec>, -) -> Result<usize> { - let res = unsafe { - libc::kevent( - kq, - changelist.as_ptr() as *const libc::kevent, - changelist.len() as type_of_nchanges, - eventlist.as_mut_ptr() as *mut libc::kevent, - eventlist.len() as type_of_nchanges, - if let Some(ref timeout) = timeout_opt { - timeout as *const timespec - } else { - ptr::null() - }, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -#[inline] -pub fn ev_set( - ev: &mut KEvent, - ident: usize, - filter: EventFilter, - flags: EventFlag, - fflags: FilterFlag, - udata: intptr_t, -) { - ev.kevent.ident = ident as uintptr_t; - ev.kevent.filter = filter as type_of_event_filter; - ev.kevent.flags = flags.bits(); - ev.kevent.fflags = fflags.bits(); - ev.kevent.data = 0; - ev.kevent.udata = udata as type_of_udata; -} - -#[test] -fn test_struct_kevent() { - use std::mem; - - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(0xdead_beef, actual.ident()); - let filter = actual.kevent.filter; - assert_eq!(libc::EVFILT_READ, filter); - assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); - assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); - assert_eq!(0x1337, actual.data()); - assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); - assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>()); -} - -#[test] -fn test_kevent_filter() { - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); -} diff --git a/vendor/nix/src/sys/eventfd.rs b/vendor/nix/src/sys/eventfd.rs deleted file mode 100644 index cd906720c..000000000 --- a/vendor/nix/src/sys/eventfd.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::errno::Errno; -use crate::Result; -use std::os::unix::io::RawFd; - -libc_bitflags! { - pub struct EfdFlags: libc::c_int { - EFD_CLOEXEC; // Since Linux 2.6.27 - EFD_NONBLOCK; // Since Linux 2.6.27 - EFD_SEMAPHORE; // Since Linux 2.6.30 - } -} - -pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> { - let res = unsafe { libc::eventfd(initval, flags.bits()) }; - - Errno::result(res).map(|r| r as RawFd) -} diff --git a/vendor/nix/src/sys/inotify.rs b/vendor/nix/src/sys/inotify.rs deleted file mode 100644 index 84356ec70..000000000 --- a/vendor/nix/src/sys/inotify.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Monitoring API for filesystem events. -//! -//! Inotify is a Linux-only API to monitor filesystems events. -//! -//! For more documentation, please read [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). -//! -//! # Examples -//! -//! Monitor all events happening in directory "test": -//! ```no_run -//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; -//! # -//! // We create a new inotify instance. -//! let instance = Inotify::init(InitFlags::empty()).unwrap(); -//! -//! // We add a new watch on directory "test" for all events. -//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap(); -//! -//! loop { -//! // We read from our inotify instance for events. -//! let events = instance.read_events().unwrap(); -//! println!("Events: {:?}", events); -//! } -//! ``` - -use crate::errno::Errno; -use crate::unistd::read; -use crate::NixPath; -use crate::Result; -use cfg_if::cfg_if; -use libc::{c_char, c_int}; -use std::ffi::{CStr, OsStr, OsString}; -use std::mem::{size_of, MaybeUninit}; -use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::ptr; - -libc_bitflags! { - /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). - pub struct AddWatchFlags: u32 { - /// File was accessed. - IN_ACCESS; - /// File was modified. - IN_MODIFY; - /// Metadata changed. - IN_ATTRIB; - /// Writable file was closed. - IN_CLOSE_WRITE; - /// Nonwritable file was closed. - IN_CLOSE_NOWRITE; - /// File was opened. - IN_OPEN; - /// File was moved from X. - IN_MOVED_FROM; - /// File was moved to Y. - IN_MOVED_TO; - /// Subfile was created. - IN_CREATE; - /// Subfile was deleted. - IN_DELETE; - /// Self was deleted. - IN_DELETE_SELF; - /// Self was moved. - IN_MOVE_SELF; - - /// Backing filesystem was unmounted. - IN_UNMOUNT; - /// Event queue overflowed. - IN_Q_OVERFLOW; - /// File was ignored. - IN_IGNORED; - - /// Combination of `IN_CLOSE_WRITE` and `IN_CLOSE_NOWRITE`. - IN_CLOSE; - /// Combination of `IN_MOVED_FROM` and `IN_MOVED_TO`. - IN_MOVE; - - /// Only watch the path if it is a directory. - IN_ONLYDIR; - /// Don't follow symlinks. - IN_DONT_FOLLOW; - - /// Event occurred against directory. - IN_ISDIR; - /// Only send event once. - IN_ONESHOT; - /// All of the events. - IN_ALL_EVENTS; - } -} - -libc_bitflags! { - /// Configuration options for [`inotify_init1`](fn.inotify_init1.html). - pub struct InitFlags: c_int { - /// Set the `FD_CLOEXEC` flag on the file descriptor. - IN_CLOEXEC; - /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. - IN_NONBLOCK; - } -} - -/// An inotify instance. This is also a file descriptor, you can feed it to -/// other interfaces consuming file descriptors, epoll for example. -#[derive(Debug, Clone, Copy)] -pub struct Inotify { - fd: RawFd, -} - -/// This object is returned when you create a new watch on an inotify instance. -/// It is then returned as part of an event once triggered. It allows you to -/// know which watch triggered which event. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] -pub struct WatchDescriptor { - wd: i32, -} - -/// A single inotify event. -/// -/// For more documentation see, [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). -#[derive(Debug)] -pub struct InotifyEvent { - /// Watch descriptor. This field corresponds to the watch descriptor you - /// were issued when calling add_watch. It allows you to know which watch - /// this event comes from. - pub wd: WatchDescriptor, - /// Event mask. This field is a bitfield describing the exact event that - /// occured. - pub mask: AddWatchFlags, - /// This cookie is a number that allows you to connect related events. For - /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. - pub cookie: u32, - /// Filename. This field exists only if the event was triggered for a file - /// inside the watched directory. - pub name: Option<OsString>, -} - -impl Inotify { - /// Initialize a new inotify instance. - /// - /// Returns a Result containing an inotify instance. - /// - /// For more information see, [inotify_init(2)](https://man7.org/linux/man-pages/man2/inotify_init.2.html). - pub fn init(flags: InitFlags) -> Result<Inotify> { - let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - - res.map(|fd| Inotify { fd }) - } - - /// Adds a new watch on the target file or directory. - /// - /// Returns a watch descriptor. This is not a File Descriptor! - /// - /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). - pub fn add_watch<P: ?Sized + NixPath>( - self, - path: &P, - mask: AddWatchFlags, - ) -> Result<WatchDescriptor> { - let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) - })?; - - Errno::result(res).map(|wd| WatchDescriptor { wd }) - } - - /// Removes an existing watch using the watch descriptor returned by - /// inotify_add_watch. - /// - /// Returns an EINVAL error if the watch descriptor is invalid. - /// - /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). - pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { - cfg_if! { - if #[cfg(target_os = "linux")] { - let arg = wd.wd; - } else if #[cfg(target_os = "android")] { - let arg = wd.wd as u32; - } - } - let res = unsafe { libc::inotify_rm_watch(self.fd, arg) }; - - Errno::result(res).map(drop) - } - - /// Reads a collection of events from the inotify file descriptor. This call - /// can either be blocking or non blocking depending on whether IN_NONBLOCK - /// was set at initialization. - /// - /// Returns as many events as available. If the call was non blocking and no - /// events could be read then the EAGAIN error is returned. - pub fn read_events(self) -> Result<Vec<InotifyEvent>> { - let header_size = size_of::<libc::inotify_event>(); - const BUFSIZ: usize = 4096; - let mut buffer = [0u8; BUFSIZ]; - let mut events = Vec::new(); - let mut offset = 0; - - let nread = read(self.fd, &mut buffer)?; - - while (nread - offset) >= header_size { - let event = unsafe { - let mut event = MaybeUninit::<libc::inotify_event>::uninit(); - ptr::copy_nonoverlapping( - buffer.as_ptr().add(offset), - event.as_mut_ptr() as *mut u8, - (BUFSIZ - offset).min(header_size), - ); - event.assume_init() - }; - - let name = match event.len { - 0 => None, - _ => { - let ptr = unsafe { - buffer.as_ptr().add(offset + header_size) - as *const c_char - }; - let cstr = unsafe { CStr::from_ptr(ptr) }; - - Some(OsStr::from_bytes(cstr.to_bytes()).to_owned()) - } - }; - - events.push(InotifyEvent { - wd: WatchDescriptor { wd: event.wd }, - mask: AddWatchFlags::from_bits_truncate(event.mask), - cookie: event.cookie, - name, - }); - - offset += header_size + event.len as usize; - } - - Ok(events) - } -} - -impl AsRawFd for Inotify { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl FromRawFd for Inotify { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd } - } -} diff --git a/vendor/nix/src/sys/ioctl/bsd.rs b/vendor/nix/src/sys/ioctl/bsd.rs deleted file mode 100644 index 307994cb9..000000000 --- a/vendor/nix/src/sys/ioctl/bsd.rs +++ /dev/null @@ -1,129 +0,0 @@ -/// The datatype used for the ioctl number -#[doc(hidden)] -#[cfg(not(target_os = "illumos"))] -pub type ioctl_num_type = ::libc::c_ulong; - -#[doc(hidden)] -#[cfg(target_os = "illumos")] -pub type ioctl_num_type = ::libc::c_int; - -/// The datatype used for the 3rd argument -#[doc(hidden)] -pub type ioctl_param_type = ::libc::c_int; - -mod consts { - use crate::sys::ioctl::ioctl_num_type; - #[doc(hidden)] - pub const VOID: ioctl_num_type = 0x2000_0000; - #[doc(hidden)] - pub const OUT: ioctl_num_type = 0x4000_0000; - #[doc(hidden)] - #[allow(overflowing_literals)] - pub const IN: ioctl_num_type = 0x8000_0000; - #[doc(hidden)] - pub const INOUT: ioctl_num_type = IN | OUT; - #[doc(hidden)] - pub const IOCPARM_MASK: ioctl_num_type = 0x1fff; -} - -pub use self::consts::*; - -#[macro_export] -#[doc(hidden)] -macro_rules! ioc { - ($inout:expr, $group:expr, $num:expr, $len:expr) => { - $inout - | (($len as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::IOCPARM_MASK) - << 16) - | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) - | ($num as $crate::sys::ioctl::ioctl_num_type) - }; -} - -/// Generate an ioctl request code for a command that passes no data. -/// -/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_none!()` directly. -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! request_code_none { - ($g:expr, $n:expr) => { - ioc!($crate::sys::ioctl::VOID, $g, $n, 0) - }; -} - -/// Generate an ioctl request code for a command that passes an integer -/// -/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write_int!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write_int { - ($g:expr, $n:expr) => { - ioc!( - $crate::sys::ioctl::VOID, - $g, - $n, - ::std::mem::size_of::<$crate::libc::c_int>() - ) - }; -} - -/// Generate an ioctl request code for a command that reads. -/// -/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_read!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is reading and the kernel is -/// writing. -#[macro_export(local_inner_macros)] -macro_rules! request_code_read { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::OUT, $g, $n, $len) - }; -} - -/// Generate an ioctl request code for a command that writes. -/// -/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is writing and the kernel is -/// reading. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::IN, $g, $n, $len) - }; -} - -/// Generate an ioctl request code for a command that reads and writes. -/// -/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_readwrite { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::INOUT, $g, $n, $len) - }; -} diff --git a/vendor/nix/src/sys/ioctl/linux.rs b/vendor/nix/src/sys/ioctl/linux.rs deleted file mode 100644 index 0c0a20905..000000000 --- a/vendor/nix/src/sys/ioctl/linux.rs +++ /dev/null @@ -1,172 +0,0 @@ -/// The datatype used for the ioctl number -#[cfg(any(target_os = "android", target_env = "musl"))] -#[doc(hidden)] -pub type ioctl_num_type = ::libc::c_int; -#[cfg(not(any(target_os = "android", target_env = "musl")))] -#[doc(hidden)] -pub type ioctl_num_type = ::libc::c_ulong; -/// The datatype used for the 3rd argument -#[doc(hidden)] -pub type ioctl_param_type = ::libc::c_ulong; - -#[doc(hidden)] -pub const NRBITS: ioctl_num_type = 8; -#[doc(hidden)] -pub const TYPEBITS: ioctl_num_type = 8; - -#[cfg(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "sparc64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 1; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 4; - #[doc(hidden)] - pub const SIZEBITS: u8 = 13; - #[doc(hidden)] - pub const DIRBITS: u8 = 3; -} - -// "Generic" ioctl protocol -#[cfg(any( - target_arch = "x86", - target_arch = "arm", - target_arch = "s390x", - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "riscv32", - target_arch = "riscv64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 0; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 1; - #[doc(hidden)] - pub const SIZEBITS: u8 = 14; - #[doc(hidden)] - pub const DIRBITS: u8 = 2; -} - -pub use self::consts::*; - -#[doc(hidden)] -pub const NRSHIFT: ioctl_num_type = 0; -#[doc(hidden)] -pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type; -#[doc(hidden)] -pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type; -#[doc(hidden)] -pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type; - -#[doc(hidden)] -pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1; -#[doc(hidden)] -pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1; -#[doc(hidden)] -pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1; -#[doc(hidden)] -pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1; - -/// Encode an ioctl command. -#[macro_export] -#[doc(hidden)] -macro_rules! ioc { - ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => { - (($dir as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::DIRMASK) - << $crate::sys::ioctl::DIRSHIFT) - | (($ty as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::TYPEMASK) - << $crate::sys::ioctl::TYPESHIFT) - | (($nr as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::NRMASK) - << $crate::sys::ioctl::NRSHIFT) - | (($sz as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::SIZEMASK) - << $crate::sys::ioctl::SIZESHIFT) - }; -} - -/// Generate an ioctl request code for a command that passes no data. -/// -/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_none!()` directly. -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! request_code_none { - ($ty:expr, $nr:expr) => { - ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0) - }; -} - -/// Generate an ioctl request code for a command that reads. -/// -/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_read!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is reading and the kernel is -/// writing. -#[macro_export(local_inner_macros)] -macro_rules! request_code_read { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz) - }; -} - -/// Generate an ioctl request code for a command that writes. -/// -/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is writing and the kernel is -/// reading. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz) - }; -} - -/// Generate an ioctl request code for a command that reads and writes. -/// -/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_readwrite { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!( - $crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, - $ty, - $nr, - $sz - ) - }; -} diff --git a/vendor/nix/src/sys/ioctl/mod.rs b/vendor/nix/src/sys/ioctl/mod.rs deleted file mode 100644 index 98d6b5c99..000000000 --- a/vendor/nix/src/sys/ioctl/mod.rs +++ /dev/null @@ -1,786 +0,0 @@ -//! Provide helpers for making ioctl system calls. -//! -//! This library is pretty low-level and messy. `ioctl` is not fun. -//! -//! What is an `ioctl`? -//! =================== -//! -//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new -//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be -//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file -//! descriptor. -//! -//! It is common to see `ioctl`s used for the following purposes: -//! -//! * Provide read/write access to out-of-band data related to a device such as configuration -//! (for instance, setting serial port options) -//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI -//! devices). -//! * Provide access to control functions on a device (for example, on Linux you can send -//! commands like pause, resume, and eject to the CDROM device. -//! * Do whatever else the device driver creator thought made most sense. -//! -//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard. -//! They operate on file descriptors and have an identifier that specifies what the ioctl is. -//! Additionally they may read or write data and therefore need to pass along a data pointer. -//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also -//! be difficult. -//! -//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some -//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into -//! subcomponents (For linux this is documented in -//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)): -//! -//! * Number: The actual ioctl ID -//! * Type: A grouping of ioctls for a common purpose or driver -//! * Size: The size in bytes of the data that will be transferred -//! * Direction: Whether there is any data and if it's read, write, or both -//! -//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead -//! preferring to use the 4 components above to generate the final ioctl identifier. Because of -//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are -//! commonly referred to as "bad" in `ioctl` documentation. -//! -//! Defining `ioctl`s -//! ================= -//! -//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public -//! unsafe functions that can then be used for calling the ioctl. This macro has a few different -//! ways it can be used depending on the specific ioctl you're working with. -//! -//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This -//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in -//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR` -//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! const SPI_IOC_TYPE_MODE: u8 = 1; -//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); -//! # fn main() {} -//! ``` -//! -//! This generates the function: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use std::mem; -//! # use nix::{libc, Result}; -//! # use nix::errno::Errno; -//! # use nix::libc::c_int as c_int; -//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! # const SPI_IOC_TYPE_MODE: u8 = 1; -//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> { -//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data); -//! Errno::result(res) -//! } -//! # fn main() {} -//! ``` -//! -//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s. -//! These are generated by assuming the return value of the ioctl is `-1` on error and everything -//! else is a valid return value. If this is not the case, `Result::map` can be used to map some -//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function. -//! -//! Writing `ioctl`s generally use pointers as their data source and these should use the -//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the -//! `ioctl_write_int!` macro. This variant does not take a type as the last argument: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const HCI_IOC_MAGIC: u8 = b'k'; -//! const HCI_IOC_HCIDEVUP: u8 = 1; -//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); -//! # fn main() {} -//! ``` -//! -//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro -//! doesn't take a type and so it is declared similar to the `write_int` variant shown above. -//! -//! The mode for a given `ioctl` should be clear from the documentation if it has good -//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl` -//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite" -//! respectively. To determine the specific `write_` variant to use you'll need to find -//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used, -//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the -//! [`ioctl_list` man page](https://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a -//! large number of `ioctl`s and describes their argument data type. -//! -//! Using "bad" `ioctl`s -//! -------------------- -//! -//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of -//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the -//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these -//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates -//! the ioctl number and instead use the defined value directly. -//! -//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor. -//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! # use nix::libc::TCGETS as TCGETS; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! # use nix::libc::termios as termios; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! ioctl_read_bad!(tcgets, TCGETS, termios); -//! # fn main() {} -//! ``` -//! -//! The generated function has the same form as that generated by `ioctl_read!`: -//! -//! ```text -//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>; -//! ``` -//! -//! Working with Arrays -//! ------------------- -//! -//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf` -//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that -//! there are no "bad" versions for working with buffers. The generated functions include a `len` -//! argument to specify the number of elements (where the type of each element is specified in the -//! macro). -//! -//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl` -//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs. -//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like: -//! -//! ```C -//! #define SPI_IOC_MAGIC 'k' -//! #define SPI_MSGSIZE(N) ... -//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) -//! ``` -//! -//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's -//! needed to define this `ioctl` is: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! const SPI_IOC_TYPE_MESSAGE: u8 = 0; -//! # pub struct spi_ioc_transfer(u64); -//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); -//! # fn main() {} -//! ``` -//! -//! This generates a function like: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use std::mem; -//! # use nix::{libc, Result}; -//! # use nix::errno::Errno; -//! # use nix::libc::c_int as c_int; -//! # const SPI_IOC_MAGIC: u8 = b'k'; -//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0; -//! # pub struct spi_ioc_transfer(u64); -//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> { -//! let res = libc::ioctl(fd, -//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()), -//! data); -//! Errno::result(res) -//! } -//! # fn main() {} -//! ``` -//! -//! Finding `ioctl` Documentation -//! ----------------------------- -//! -//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot -//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are -//! documented directly in the headers defining their constants, but others have more extensive -//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`). -//! -//! Documenting the Generated Functions -//! =================================== -//! -//! In many cases, users will wish for the functions generated by the `ioctl` -//! macro to be public and documented. For this reason, the generated functions -//! are public by default. If you wish to hide the ioctl, you will need to put -//! them in a private module. -//! -//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an -//! example : -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use nix::libc::c_int; -//! ioctl_read! { -//! /// Make the given terminal the controlling terminal of the calling process. The calling -//! /// process must be a session leader and not have a controlling terminal already. If the -//! /// terminal is already the controlling terminal of a different session group then the -//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the -//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen -//! /// and all processes that had it as controlling terminal lose it. -//! tiocsctty, b't', 19, c_int -//! } -//! -//! # fn main() {} -//! ``` -use cfg_if::cfg_if; - -#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] -#[macro_use] -mod linux; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "redox" -))] -pub use self::linux::*; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -#[macro_use] -mod bsd; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -pub use self::bsd::*; - -/// Convert raw ioctl return value to a Nix result -#[macro_export] -#[doc(hidden)] -macro_rules! convert_ioctl_res { - ($w:expr) => {{ - $crate::errno::Errno::result($w) - }}; -} - -/// Generates a wrapper function for an ioctl that passes no data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as: -/// -/// ```C -/// #define VIDIOC_LOG_STATUS _IO('V', 70) -/// ``` -/// -/// This can be implemented in Rust like: -/// -/// ```no_run -/// # #[macro_use] extern crate nix; -/// ioctl_none!(log_status, b'V', 70); -/// fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_none { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ```no_run -/// # #[macro_use] extern crate nix; -/// # use libc::TIOCNXCL; -/// # use std::fs::File; -/// # use std::os::unix::io::AsRawFd; -/// ioctl_none_bad!(tiocnxcl, TIOCNXCL); -/// fn main() { -/// let file = File::open("/dev/ttyUSB0").unwrap(); -/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap(); -/// } -/// ``` -// TODO: add an example using request_code_*!() -#[macro_export(local_inner_macros)] -macro_rules! ioctl_none_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads data from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -/// const SPI_IOC_TYPE_MODE: u8 = 1; -/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # pub struct v4l2_audio {} -/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_ptr { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *const $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_ptr_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *const $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { - /// Generates a wrapper function for a ioctl that writes an integer to the kernel. - /// - /// The arguments to this macro are: - /// - /// * The function name - /// * The ioctl identifier - /// * The ioctl sequence number - /// - /// The generated function has the following signature: - /// - /// ```rust,ignore - /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> - /// ``` - /// - /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: - /// * BSD - `libc::c_int` - /// * Linux - `libc::c_ulong` - /// - /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). - /// - /// # Example - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// ioctl_write_int!(vt_activate, b'v', 4); - /// # fn main() {} - /// ``` - #[macro_export(local_inner_macros)] - macro_rules! ioctl_write_int { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::sys::ioctl::ioctl_param_type) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) - } - } else { - /// Generates a wrapper function for a ioctl that writes an integer to the kernel. - /// - /// The arguments to this macro are: - /// - /// * The function name - /// * The ioctl identifier - /// * The ioctl sequence number - /// - /// The generated function has the following signature: - /// - /// ```rust,ignore - /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> - /// ``` - /// - /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: - /// * BSD - `libc::c_int` - /// * Linux - `libc::c_ulong` - /// - /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). - /// - /// # Example - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// const HCI_IOC_MAGIC: u8 = b'k'; - /// const HCI_IOC_HCIDEVUP: u8 = 1; - /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); - /// # fn main() {} - /// ``` - #[macro_export(local_inner_macros)] - macro_rules! ioctl_write_int { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::sys::ioctl::ioctl_param_type) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) - } - } -} - -/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); -/// # fn main() {} -/// ``` -/// -/// ```rust -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_int_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads and writes data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # pub struct v4l2_audio {} -/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for ioctl_readwrite_bad -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for ioctl_read_buf -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &mut [$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -/// const SPI_IOC_TYPE_MESSAGE: u8 = 0; -/// # pub struct spi_ioc_transfer(u64); -/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &[$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for readwrite_buf -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &mut [$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} diff --git a/vendor/nix/src/sys/memfd.rs b/vendor/nix/src/sys/memfd.rs deleted file mode 100644 index ad9345e89..000000000 --- a/vendor/nix/src/sys/memfd.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Interfaces for managing memory-backed files. - -use cfg_if::cfg_if; -use std::os::unix::io::RawFd; - -use crate::errno::Errno; -use crate::Result; -use std::ffi::CStr; - -libc_bitflags!( - /// Options that change the behavior of [`memfd_create`]. - pub struct MemFdCreateFlag: libc::c_uint { - /// Set the close-on-exec ([`FD_CLOEXEC`]) flag on the new file descriptor. - /// - /// By default, the new file descriptor is set to remain open across an [`execve`] - /// (the `FD_CLOEXEC` flag is initially disabled). This flag can be used to change - /// this default. The file offset is set to the beginning of the file (see [`lseek`]). - /// - /// See also the description of the `O_CLOEXEC` flag in [`open(2)`]. - /// - /// [`execve`]: crate::unistd::execve - /// [`lseek`]: crate::unistd::lseek - /// [`FD_CLOEXEC`]: crate::fcntl::FdFlag::FD_CLOEXEC - /// [`open(2)`]: https://man7.org/linux/man-pages/man2/open.2.html - MFD_CLOEXEC; - /// Allow sealing operations on this file. - /// - /// See also the file sealing notes given in [`memfd_create(2)`]. - /// - /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html - MFD_ALLOW_SEALING; - } -); - -/// Creates an anonymous file that lives in memory, and return a file-descriptor to it. -/// -/// The file behaves like a regular file, and so can be modified, truncated, memory-mapped, and so on. -/// However, unlike a regular file, it lives in RAM and has a volatile backing storage. -/// -/// For more information, see [`memfd_create(2)`]. -/// -/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html -pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> { - let res = unsafe { - cfg_if! { - if #[cfg(all( - // Android does not have a memfd_create symbol - not(target_os = "android"), - any( - target_os = "freebsd", - // If the OS is Linux, gnu and musl expose a memfd_create symbol but not uclibc - target_env = "gnu", - target_env = "musl", - )))] - { - libc::memfd_create(name.as_ptr(), flags.bits()) - } else { - libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) - } - } - }; - - Errno::result(res).map(|r| r as RawFd) -} diff --git a/vendor/nix/src/sys/mman.rs b/vendor/nix/src/sys/mman.rs deleted file mode 100644 index 2bee09161..000000000 --- a/vendor/nix/src/sys/mman.rs +++ /dev/null @@ -1,599 +0,0 @@ -//! Memory management declarations. - -use crate::errno::Errno; -#[cfg(not(target_os = "android"))] -use crate::NixPath; -use crate::Result; -#[cfg(not(target_os = "android"))] -#[cfg(feature = "fs")] -use crate::{fcntl::OFlag, sys::stat::Mode}; -use libc::{self, c_int, c_void, off_t, size_t}; -use std::{os::unix::io::RawFd, num::NonZeroUsize}; - -libc_bitflags! { - /// Desired memory protection of a memory mapping. - pub struct ProtFlags: c_int { - /// Pages cannot be accessed. - PROT_NONE; - /// Pages can be read. - PROT_READ; - /// Pages can be written. - PROT_WRITE; - /// Pages can be executed - PROT_EXEC; - /// Apply protection up to the end of a mapping that grows upwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PROT_GROWSDOWN; - /// Apply protection down to the beginning of a mapping that grows downwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PROT_GROWSUP; - } -} - -libc_bitflags! { - /// Additional parameters for [`mmap`]. - pub struct MapFlags: c_int { - /// Compatibility flag. Ignored. - MAP_FILE; - /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`. - MAP_SHARED; - /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`. - MAP_PRIVATE; - /// Place the mapping at exactly the address specified in `addr`. - MAP_FIXED; - /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_FIXED_NOREPLACE; - /// To be used with `MAP_FIXED`, to forbid the system - /// to select a different address than the one specified. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_EXCL; - /// Synonym for `MAP_ANONYMOUS`. - MAP_ANON; - /// The mapping is not backed by any file. - MAP_ANONYMOUS; - /// Put the mapping into the first 2GB of the process address space. - #[cfg(any(all(any(target_os = "android", target_os = "linux"), - any(target_arch = "x86", target_arch = "x86_64")), - all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), - all(target_os = "freebsd", target_pointer_width = "64")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_32BIT; - /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_GROWSDOWN; - /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_DENYWRITE; - /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_EXECUTABLE; - /// Mark the mmaped region to be locked in the same way as `mlock(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_LOCKED; - /// Do not reserve swap space for this mapping. - /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NORESERVE; - /// Populate page tables for a mapping. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_POPULATE; - /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NONBLOCK; - /// Allocate the mapping using "huge pages." - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGETLB; - /// Make use of 64KB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_64KB; - /// Make use of 512KB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_512KB; - /// Make use of 1MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_1MB; - /// Make use of 2MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_2MB; - /// Make use of 8MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_8MB; - /// Make use of 16MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_16MB; - /// Make use of 32MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_32MB; - /// Make use of 256MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_256MB; - /// Make use of 512MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_512MB; - /// Make use of 1GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_1GB; - /// Make use of 2GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_2GB; - /// Make use of 16GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_16GB; - - /// Lock the mapped region into memory as with `mlock(2)`. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_WIRED; - /// Causes dirtied data in the specified range to be flushed to disk only when necessary. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NOSYNC; - /// Rename private pages to a file. - /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_RENAME; - /// Region may contain semaphores. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HASSEMAPHORE; - /// Region grows down, like a stack. - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_STACK; - /// Pages in this mapping are not retained in the kernel's memory cache. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NOCACHE; - /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_JIT; - /// Allows to use large pages, underlying alignment based on size. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_ALIGNED_SUPER; - /// Pages will be discarded in the core dumps. - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_CONCEAL; - } -} - -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -libc_bitflags! { - /// Options for [`mremap`]. - pub struct MRemapFlags: c_int { - /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MREMAP_MAYMOVE; - /// Place the mapping at exactly the address specified in `new_address`. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MREMAP_FIXED; - /// Place the mapping at exactly the address specified in `new_address`. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_FIXED; - /// Allows to duplicate the mapping to be able to apply different flags on the copy. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_REMAPDUP; - } -} - -libc_enum! { - /// Usage information for a range of memory to allow for performance optimizations by the kernel. - /// - /// Used by [`madvise`]. - #[repr(i32)] - #[non_exhaustive] - pub enum MmapAdvise { - /// No further special treatment. This is the default. - MADV_NORMAL, - /// Expect random page references. - MADV_RANDOM, - /// Expect sequential page references. - MADV_SEQUENTIAL, - /// Expect access in the near future. - MADV_WILLNEED, - /// Do not expect access in the near future. - MADV_DONTNEED, - /// Free up a given range of pages and its associated backing store. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_REMOVE, - /// Do not make pages in this range available to the child after a `fork(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DONTFORK, - /// Undo the effect of `MADV_DONTFORK`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DOFORK, - /// Poison the given pages. - /// - /// Subsequent references to those pages are treated like hardware memory corruption. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_HWPOISON, - /// Enable Kernel Samepage Merging (KSM) for the given pages. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_MERGEABLE, - /// Undo the effect of `MADV_MERGEABLE` - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_UNMERGEABLE, - /// Preserve the memory of each page but offline the original page. - #[cfg(any(target_os = "android", - all(target_os = "linux", any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "x86", - target_arch = "x86_64", - target_arch = "sparc64"))))] - MADV_SOFT_OFFLINE, - /// Enable Transparent Huge Pages (THP) for pages in the given range. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_HUGEPAGE, - /// Undo the effect of `MADV_HUGEPAGE`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOHUGEPAGE, - /// Exclude the given range from a core dump. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DONTDUMP, - /// Undo the effect of an earlier `MADV_DONTDUMP`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DODUMP, - /// Specify that the application no longer needs the pages in the given range. - MADV_FREE, - /// Request that the system not flush the current range to disk unless it needs to. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOSYNC, - /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_AUTOSYNC, - /// Region is not included in a core file. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOCORE, - /// Include region in a core file - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_CORE, - /// This process should not be killed when swap space is exhausted. - #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_PROTECT, - /// Invalidate the hardware page table for the given region. - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_INVAL, - /// Set the offset of the page directory page to `value` for the virtual page table. - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_SETMAP, - /// Indicates that the application will not need the data in the given range. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_ZERO_WIRED_PAGES, - /// Pages can be reused (by anyone). - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_FREE_REUSABLE, - /// Caller wants to reuse those pages. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_FREE_REUSE, - // Darwin doesn't document this flag's behavior. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(missing_docs)] - MADV_CAN_REUSE, - } -} - -libc_bitflags! { - /// Configuration flags for [`msync`]. - pub struct MsFlags: c_int { - /// Schedule an update but return immediately. - MS_ASYNC; - /// Invalidate all cached data. - MS_INVALIDATE; - /// Invalidate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MS_KILLPAGES; - /// Deactivate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MS_DEACTIVATE; - /// Perform an update and wait for it to complete. - MS_SYNC; - } -} - -#[cfg(not(target_os = "haiku"))] -libc_bitflags! { - /// Flags for [`mlockall`]. - pub struct MlockAllFlags: c_int { - /// Lock pages that are currently mapped into the address space of the process. - MCL_CURRENT; - /// Lock pages which will become mapped into the address space of the process in the future. - MCL_FUTURE; - } -} - -/// Locks all memory pages that contain part of the address range with `length` -/// bytes starting at `addr`. -/// -/// Locked pages never move to the swap area. -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`mlock(2)`] man page. -/// -/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html -pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::mlock(addr, length)).map(drop) -} - -/// Unlocks all memory pages that contain part of the address range with -/// `length` bytes starting at `addr`. -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`munlock(2)`] man -/// page. -/// -/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html -pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::munlock(addr, length)).map(drop) -} - -/// Locks all memory pages mapped into this process' address space. -/// -/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. -/// -/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html -#[cfg(not(target_os = "haiku"))] -pub fn mlockall(flags: MlockAllFlags) -> Result<()> { - unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) -} - -/// Unlocks all memory pages mapped into this process' address space. -/// -/// For more information, see [`munlockall(2)`]. -/// -/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html -#[cfg(not(target_os = "haiku"))] -pub fn munlockall() -> Result<()> { - unsafe { Errno::result(libc::munlockall()) }.map(drop) -} - -/// allocate memory, or map files or devices into memory -/// -/// # Safety -/// -/// See the [`mmap(2)`] man page for detailed requirements. -/// -/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html -pub unsafe fn mmap( - addr: Option<NonZeroUsize>, - length: NonZeroUsize, - prot: ProtFlags, - flags: MapFlags, - fd: RawFd, - offset: off_t, -) -> Result<*mut c_void> { - let ptr = addr.map_or( - std::ptr::null_mut(), - |a| usize::from(a) as *mut c_void - ); - - let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); - - if ret == libc::MAP_FAILED { - Err(Errno::last()) - } else { - Ok(ret) - } -} - -/// Expands (or shrinks) an existing memory mapping, potentially moving it at -/// the same time. -/// -/// # Safety -/// -/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for -/// detailed requirements. -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -pub unsafe fn mremap( - addr: *mut c_void, - old_size: size_t, - new_size: size_t, - flags: MRemapFlags, - new_address: Option<*mut c_void>, -) -> Result<*mut c_void> { - #[cfg(target_os = "linux")] - let ret = libc::mremap( - addr, - old_size, - new_size, - flags.bits(), - new_address.unwrap_or(std::ptr::null_mut()), - ); - #[cfg(target_os = "netbsd")] - let ret = libc::mremap( - addr, - old_size, - new_address.unwrap_or(std::ptr::null_mut()), - new_size, - flags.bits(), - ); - - if ret == libc::MAP_FAILED { - Err(Errno::last()) - } else { - Ok(ret) - } -} - -/// remove a mapping -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`munmap(2)`] man -/// page. -/// -/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html -pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { - Errno::result(libc::munmap(addr, len)).map(drop) -} - -/// give advice about use of memory -/// -/// # Safety -/// -/// See the [`madvise(2)`] man page. Take special care when using -/// [`MmapAdvise::MADV_FREE`]. -/// -/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html -pub unsafe fn madvise( - addr: *mut c_void, - length: size_t, - advise: MmapAdvise, -) -> Result<()> { - Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) -} - -/// Set protection of memory mapping. -/// -/// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for -/// details. -/// -/// # Safety -/// -/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to -/// SIGSEGVs. -/// -/// ``` -/// # use nix::libc::size_t; -/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; -/// # use std::ptr; -/// const ONE_K: size_t = 1024; -/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); -/// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, -/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); -/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); -/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) -/// }; -/// assert_eq!(slice[0], 0x00); -/// slice[0] = 0xFF; -/// assert_eq!(slice[0], 0xFF); -/// ``` -pub unsafe fn mprotect( - addr: *mut c_void, - length: size_t, - prot: ProtFlags, -) -> Result<()> { - Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) -} - -/// synchronize a mapped region -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`msync(2)`] man -/// page. -/// -/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html -pub unsafe fn msync( - addr: *mut c_void, - length: size_t, - flags: MsFlags, -) -> Result<()> { - Errno::result(libc::msync(addr, length, flags.bits())).map(drop) -} - -#[cfg(not(target_os = "android"))] -feature! { -#![feature = "fs"] -/// Creates and opens a new, or opens an existing, POSIX shared memory object. -/// -/// For more information, see [`shm_open(3)`]. -/// -/// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html -pub fn shm_open<P>( - name: &P, - flag: OFlag, - mode: Mode - ) -> Result<RawFd> - where P: ?Sized + NixPath -{ - let ret = name.with_nix_path(|cstr| { - #[cfg(any(target_os = "macos", target_os = "ios"))] - unsafe { - libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) - } - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - unsafe { - libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) - } - })?; - - Errno::result(ret) -} -} - -/// Performs the converse of [`shm_open`], removing an object previously created. -/// -/// For more information, see [`shm_unlink(3)`]. -/// -/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html -#[cfg(not(target_os = "android"))] -pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> { - let ret = - name.with_nix_path(|cstr| unsafe { libc::shm_unlink(cstr.as_ptr()) })?; - - Errno::result(ret).map(drop) -} diff --git a/vendor/nix/src/sys/mod.rs b/vendor/nix/src/sys/mod.rs deleted file mode 100644 index 2065059de..000000000 --- a/vendor/nix/src/sys/mod.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! Mostly platform-specific functionality -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", - target_os = "netbsd" -))] -feature! { - #![feature = "aio"] - pub mod aio; -} - -feature! { - #![feature = "event"] - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[allow(missing_docs)] - pub mod epoll; - - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[allow(missing_docs)] - pub mod event; - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[allow(missing_docs)] - pub mod eventfd; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" -))] -#[cfg(feature = "ioctl")] -#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] -#[macro_use] -pub mod ioctl; - -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -feature! { - #![feature = "fs"] - pub mod memfd; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "mman"] - pub mod mman; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "personality"] - pub mod personality; -} - -feature! { - #![feature = "pthread"] - pub mod pthread; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -feature! { - #![feature = "ptrace"] - #[allow(missing_docs)] - pub mod ptrace; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "quota"] - pub mod quota; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "reboot"] - pub mod reboot; -} - -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -feature! { - #![feature = "resource"] - pub mod resource; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "poll"] - pub mod select; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] -feature! { - #![feature = "zerocopy"] - pub mod sendfile; -} - -pub mod signal; - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "signal"] - #[allow(missing_docs)] - pub mod signalfd; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "socket"] - #[allow(missing_docs)] - pub mod socket; -} - -feature! { - #![feature = "fs"] - #[allow(missing_docs)] - pub mod stat; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd" -))] -feature! { - #![feature = "fs"] - pub mod statfs; -} - -feature! { - #![feature = "fs"] - pub mod statvfs; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[allow(missing_docs)] -pub mod sysinfo; - -feature! { - #![feature = "term"] - #[allow(missing_docs)] - pub mod termios; -} - -#[allow(missing_docs)] -pub mod time; - -feature! { - #![feature = "uio"] - pub mod uio; -} - -feature! { - #![feature = "feature"] - pub mod utsname; -} - -feature! { - #![feature = "process"] - pub mod wait; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "inotify"] - pub mod inotify; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "time"] - pub mod timerfd; -} - -#[cfg(all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" -))] -feature! { - #![feature = "time"] - pub mod timer; -} diff --git a/vendor/nix/src/sys/personality.rs b/vendor/nix/src/sys/personality.rs deleted file mode 100644 index f295a05fa..000000000 --- a/vendor/nix/src/sys/personality.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Process execution domains -use crate::errno::Errno; -use crate::Result; - -use libc::{self, c_int, c_ulong}; - -libc_bitflags! { - /// Flags used and returned by [`get()`](fn.get.html) and - /// [`set()`](fn.set.html). - pub struct Persona: c_int { - /// Provide the legacy virtual address space layout. - ADDR_COMPAT_LAYOUT; - /// Disable address-space-layout randomization. - ADDR_NO_RANDOMIZE; - /// Limit the address space to 32 bits. - ADDR_LIMIT_32BIT; - /// Use `0xc0000000` as the offset at which to search a virtual memory - /// chunk on [`mmap(2)`], otherwise use `0xffffe000`. - /// - /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html - ADDR_LIMIT_3GB; - /// User-space function pointers to signal handlers point to descriptors. - #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FDPIC_FUNCPTRS; - /// Map page 0 as read-only. - MMAP_PAGE_ZERO; - /// `PROT_READ` implies `PROT_EXEC` for [`mmap(2)`]. - /// - /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html - READ_IMPLIES_EXEC; - /// No effects. - SHORT_INODE; - /// [`select(2)`], [`pselect(2)`], and [`ppoll(2)`] do not modify the - /// returned timeout argument when interrupted by a signal handler. - /// - /// [`select(2)`]: https://man7.org/linux/man-pages/man2/select.2.html - /// [`pselect(2)`]: https://man7.org/linux/man-pages/man2/pselect.2.html - /// [`ppoll(2)`]: https://man7.org/linux/man-pages/man2/ppoll.2.html - STICKY_TIMEOUTS; - /// Have [`uname(2)`] report a 2.6.40+ version number rather than a 3.x - /// version number. - /// - /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html - #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - UNAME26; - /// No effects. - WHOLE_SECONDS; - } -} - -/// Retrieve the current process personality. -/// -/// Returns a Result containing a Persona instance. -/// -/// Example: -/// -/// ``` -/// # use nix::sys::personality::{self, Persona}; -/// let pers = personality::get().unwrap(); -/// assert!(!pers.contains(Persona::WHOLE_SECONDS)); -/// ``` -pub fn get() -> Result<Persona> { - let res = unsafe { libc::personality(0xFFFFFFFF) }; - - Errno::result(res).map(Persona::from_bits_truncate) -} - -/// Set the current process personality. -/// -/// Returns a Result containing the *previous* personality for the -/// process, as a Persona. -/// -/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html) -/// -/// **NOTE**: This call **replaces** the current personality entirely. -/// To **update** the personality, first call `get()` and then `set()` -/// with the modified persona. -/// -/// Example: -/// -/// ``` -/// # use nix::sys::personality::{self, Persona}; -/// let mut pers = personality::get().unwrap(); -/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); -/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); -/// ``` -pub fn set(persona: Persona) -> Result<Persona> { - let res = unsafe { libc::personality(persona.bits() as c_ulong) }; - - Errno::result(res).map(Persona::from_bits_truncate) -} diff --git a/vendor/nix/src/sys/pthread.rs b/vendor/nix/src/sys/pthread.rs deleted file mode 100644 index 6bad03a4d..000000000 --- a/vendor/nix/src/sys/pthread.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Low level threading primitives - -#[cfg(not(target_os = "redox"))] -use crate::errno::Errno; -#[cfg(not(target_os = "redox"))] -use crate::Result; -use libc::{self, pthread_t}; - -/// Identifies an individual thread. -pub type Pthread = pthread_t; - -/// Obtain ID of the calling thread (see -/// [`pthread_self(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html) -/// -/// The thread ID returned by `pthread_self()` is not the same thing as -/// the kernel thread ID returned by a call to `gettid(2)`. -#[inline] -pub fn pthread_self() -> Pthread { - unsafe { libc::pthread_self() } -} - -feature! { -#![feature = "signal"] - -/// Send a signal to a thread (see [`pthread_kill(3)`]). -/// -/// If `signal` is `None`, `pthread_kill` will only preform error checking and -/// won't send any signal. -/// -/// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html -#[allow(clippy::not_unsafe_ptr_arg_deref)] -#[cfg(not(target_os = "redox"))] -pub fn pthread_kill<T>(thread: Pthread, signal: T) -> Result<()> - where T: Into<Option<crate::sys::signal::Signal>> -{ - let sig = match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }; - let res = unsafe { libc::pthread_kill(thread, sig) }; - Errno::result(res).map(drop) -} -} diff --git a/vendor/nix/src/sys/ptrace/bsd.rs b/vendor/nix/src/sys/ptrace/bsd.rs deleted file mode 100644 index ba267c657..000000000 --- a/vendor/nix/src/sys/ptrace/bsd.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int}; -use std::ptr; - -pub type RequestType = c_int; - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "openbsd"))] { - #[doc(hidden)] - pub type AddressType = *mut ::libc::c_char; - } else { - #[doc(hidden)] - pub type AddressType = *mut ::libc::c_void; - } -} - -libc_enum! { - #[repr(i32)] - /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] - pub enum Request { - PT_TRACE_ME, - PT_READ_I, - PT_READ_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_READ_U, - PT_WRITE_I, - PT_WRITE_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_WRITE_U, - PT_CONTINUE, - PT_KILL, - #[cfg(any(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos"), - all(target_os = "openbsd", target_arch = "x86_64"), - all(target_os = "netbsd", any(target_arch = "x86_64", - target_arch = "powerpc"))))] - PT_STEP, - PT_ATTACH, - PT_DETACH, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_SIGEXC, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_THUPDATE, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_ATTACHEXC - } -} - -unsafe fn ptrace_other( - request: Request, - pid: Pid, - addr: AddressType, - data: c_int, -) -> Result<c_int> { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) -} - -/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` -/// -/// Indicates that this process is to be traced by its parent. -/// This is the only ptrace request to be issued by the tracee. -pub fn traceme() -> Result<()> { - unsafe { - ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0) - .map(drop) - } -} - -/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` -/// -/// Attaches to the process specified by `pid`, making it a tracee of the calling process. -pub fn attach(pid: Pid) -> Result<()> { - unsafe { - ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) - } -} - -/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` -/// -/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a -/// signal specified by `sig`. -pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop) - } -} - -/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` -/// -/// Continues the execution of the process with PID `pid`, optionally -/// delivering a signal specified by `sig`. -pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - // Ignore the useless return value - ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data) - .map(drop) - } -} - -/// Issues a kill request as with `ptrace(PT_KILL, ...)` -/// -/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` -pub fn kill(pid: Pid) -> Result<()> { - unsafe { - ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) - } -} - -/// Move the stopped tracee process forward by a single step as with -/// `ptrace(PT_STEP, ...)` -/// -/// Advances the execution of the process with PID `pid` by a single step optionally delivering a -/// signal specified by `sig`. -/// -/// # Example -/// ```rust -/// use nix::sys::ptrace::step; -/// use nix::unistd::Pid; -/// use nix::sys::signal::Signal; -/// use nix::sys::wait::*; -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); -/// } -/// _ => {}, -/// } -/// ``` -#[cfg(any( - any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), - all(target_os = "openbsd", target_arch = "x86_64"), - all( - target_os = "netbsd", - any(target_arch = "x86_64", target_arch = "powerpc") - ) -))] -pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) - } -} - -/// Reads a word from a processes memory at the given address -// Technically, ptrace doesn't dereference the pointer. It passes it directly -// to the kernel. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { - unsafe { - // Traditionally there was a difference between reading data or - // instruction memory but not in modern systems. - ptrace_other(Request::PT_READ_D, pid, addr, 0) - } -} - -/// Writes a word into the processes memory at the given address -// Technically, ptrace doesn't dereference the pointer. It passes it directly -// to the kernel. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { - unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } -} diff --git a/vendor/nix/src/sys/ptrace/linux.rs b/vendor/nix/src/sys/ptrace/linux.rs deleted file mode 100644 index 9687e05d4..000000000 --- a/vendor/nix/src/sys/ptrace/linux.rs +++ /dev/null @@ -1,558 +0,0 @@ -//! For detailed description of the ptrace requests, consult `man ptrace`. - -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_long, c_void, siginfo_t}; -use std::{mem, ptr}; - -pub type AddressType = *mut ::libc::c_void; - -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -use libc::user_regs_struct; - -cfg_if! { - if #[cfg(any(all(target_os = "linux", target_arch = "s390x"), - all(target_os = "linux", target_env = "gnu"), - target_env = "uclibc"))] { - #[doc(hidden)] - pub type RequestType = ::libc::c_uint; - } else { - #[doc(hidden)] - pub type RequestType = ::libc::c_int; - } -} - -libc_enum! { - #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))] - #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))] - /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] - pub enum Request { - PTRACE_TRACEME, - PTRACE_PEEKTEXT, - PTRACE_PEEKDATA, - PTRACE_PEEKUSER, - PTRACE_POKETEXT, - PTRACE_POKEDATA, - PTRACE_POKEUSER, - PTRACE_CONT, - PTRACE_KILL, - PTRACE_SINGLESTEP, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_GETREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_SETREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_GETFPREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_SETFPREGS, - PTRACE_ATTACH, - PTRACE_DETACH, - #[cfg(all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86", - target_arch = "x86_64")))] - PTRACE_GETFPXREGS, - #[cfg(all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86", - target_arch = "x86_64")))] - PTRACE_SETFPXREGS, - PTRACE_SYSCALL, - PTRACE_SETOPTIONS, - PTRACE_GETEVENTMSG, - PTRACE_GETSIGINFO, - PTRACE_SETSIGINFO, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_GETREGSET, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_SETREGSET, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTRACE_SEIZE, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTRACE_INTERRUPT, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_LISTEN, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_PEEKSIGINFO, - #[cfg(all(target_os = "linux", target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64")))] - PTRACE_SYSEMU, - #[cfg(all(target_os = "linux", target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64")))] - PTRACE_SYSEMU_SINGLESTEP, - } -} - -libc_enum! { - #[repr(i32)] - /// Using the ptrace options the tracer can configure the tracee to stop - /// at certain events. This enum is used to define those events as defined - /// in `man ptrace`. - #[non_exhaustive] - pub enum Event { - /// Event that stops before a return from fork or clone. - PTRACE_EVENT_FORK, - /// Event that stops before a return from vfork or clone. - PTRACE_EVENT_VFORK, - /// Event that stops before a return from clone. - PTRACE_EVENT_CLONE, - /// Event that stops before a return from execve. - PTRACE_EVENT_EXEC, - /// Event for a return from vfork. - PTRACE_EVENT_VFORK_DONE, - /// Event for a stop before an exit. Unlike the waitpid Exit status program. - /// registers can still be examined - PTRACE_EVENT_EXIT, - /// Stop triggered by a seccomp rule on a tracee. - PTRACE_EVENT_SECCOMP, - /// Stop triggered by the `INTERRUPT` syscall, or a group stop, - /// or when a new child is attached. - PTRACE_EVENT_STOP, - } -} - -libc_bitflags! { - /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. - /// See `man ptrace` for more details. - pub struct Options: libc::c_int { - /// When delivering system call traps set a bit to allow tracer to - /// distinguish between normal stops or syscall stops. May not work on - /// all systems. - PTRACE_O_TRACESYSGOOD; - /// Stop tracee at next fork and start tracing the forked process. - PTRACE_O_TRACEFORK; - /// Stop tracee at next vfork call and trace the vforked process. - PTRACE_O_TRACEVFORK; - /// Stop tracee at next clone call and trace the cloned process. - PTRACE_O_TRACECLONE; - /// Stop tracee at next execve call. - PTRACE_O_TRACEEXEC; - /// Stop tracee at vfork completion. - PTRACE_O_TRACEVFORKDONE; - /// Stop tracee at next exit call. Stops before exit commences allowing - /// tracer to see location of exit and register states. - PTRACE_O_TRACEEXIT; - /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more - /// details. - PTRACE_O_TRACESECCOMP; - /// Send a SIGKILL to the tracee if the tracer exits. This is useful - /// for ptrace jailers to prevent tracees from escaping their control. - PTRACE_O_EXITKILL; - } -} - -fn ptrace_peek( - request: Request, - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<c_long> { - let ret = unsafe { - Errno::clear(); - libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) - }; - match Errno::result(ret) { - Ok(..) | Err(Errno::UnknownErrno) => Ok(ret), - err @ Err(..) => err, - } -} - -/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -pub fn getregs(pid: Pid) -> Result<user_regs_struct> { - ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid) -} - -/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { - let res = unsafe { - libc::ptrace( - Request::PTRACE_SETREGS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - ®s as *const _ as *const c_void, - ) - }; - Errno::result(res).map(drop) -} - -/// Function for ptrace requests that return values from the data field. -/// Some ptrace get requests populate structs or larger elements than `c_long` -/// and therefore use the data field to return values. This function handles these -/// requests. -fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { - let mut data = mem::MaybeUninit::uninit(); - let res = unsafe { - libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<T>(), - data.as_mut_ptr() as *const _ as *const c_void, - ) - }; - Errno::result(res)?; - Ok(unsafe { data.assume_init() }) -} - -unsafe fn ptrace_other( - request: Request, - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<c_long> { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) -} - -/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. -pub fn setoptions(pid: Pid, options: Options) -> Result<()> { - let res = unsafe { - libc::ptrace( - Request::PTRACE_SETOPTIONS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - options.bits() as *mut c_void, - ) - }; - Errno::result(res).map(drop) -} - -/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` -pub fn getevent(pid: Pid) -> Result<c_long> { - ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid) -} - -/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` -pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { - ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid) -} - -/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` -pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { - let ret = unsafe { - Errno::clear(); - libc::ptrace( - Request::PTRACE_SETSIGINFO as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - sig as *const _ as *const c_void, - ) - }; - match Errno::result(ret) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } -} - -/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` -/// -/// Indicates that this process is to be traced by its parent. -/// This is the only ptrace request to be issued by the tracee. -pub fn traceme() -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_TRACEME, - Pid::from_raw(0), - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) // ignore the useless return value - } -} - -/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` -/// -/// Arranges for the tracee to be stopped at the next entry to or exit from a system call, -/// optionally delivering a signal specified by `sig`. -pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data) - .map(drop) // ignore the useless return value - } -} - -/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` -/// -/// In contrast to the `syscall` function, the syscall stopped at will not be executed. -/// Thus the the tracee will only be stopped once per syscall, -/// optionally delivering a signal specified by `sig`. -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64") -))] -pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data) - .map(drop) - // ignore the useless return value - } -} - -/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` -/// -/// Attaches to the process specified by `pid`, making it a tracee of the calling process. -pub fn attach(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_ATTACH, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) // ignore the useless return value - } -} - -/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` -/// -/// Attaches to the process specified in pid, making it a tracee of the calling process. -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn seize(pid: Pid, options: Options) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_SEIZE, - pid, - ptr::null_mut(), - options.bits() as *mut c_void, - ) - .map(drop) // ignore the useless return value - } -} - -/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` -/// -/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a -/// signal specified by `sig`. -pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data) - .map(drop) - } -} - -/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` -/// -/// Continues the execution of the process with PID `pid`, optionally -/// delivering a signal specified by `sig`. -pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) - // ignore the useless return value - } -} - -/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` -/// -/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn interrupt(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_INTERRUPT, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) - } -} - -/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` -/// -/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` -pub fn kill(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_KILL, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) - } -} - -/// Move the stopped tracee process forward by a single step as with -/// `ptrace(PTRACE_SINGLESTEP, ...)` -/// -/// Advances the execution of the process with PID `pid` by a single step optionally delivering a -/// signal specified by `sig`. -/// -/// # Example -/// ```rust -/// use nix::sys::ptrace::step; -/// use nix::unistd::Pid; -/// use nix::sys::signal::Signal; -/// use nix::sys::wait::*; -/// -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); -/// } -/// _ => {}, -/// } -/// ``` -pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data) - .map(drop) - } -} - -/// Move the stopped tracee process forward by a single step or stop at the next syscall -/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` -/// -/// Advances the execution by a single step or until the next syscall. -/// In case the tracee is stopped at a syscall, the syscall will not be executed. -/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64") -))] -pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other( - Request::PTRACE_SYSEMU_SINGLESTEP, - pid, - ptr::null_mut(), - data, - ) - .map(drop) // ignore the useless return value - } -} - -/// Reads a word from a processes memory at the given address -pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> { - ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) -} - -/// Writes a word into the processes memory at the given address -/// -/// # Safety -/// -/// The `data` argument is passed directly to `ptrace(2)`. Read that man page -/// for guidance. -pub unsafe fn write( - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<()> { - ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) -} - -/// Reads a word from a user area at `offset`. -/// The user struct definition can be found in `/usr/include/sys/user.h`. -pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> { - ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) -} - -/// Writes a word to a user area at `offset`. -/// The user struct definition can be found in `/usr/include/sys/user.h`. -/// -/// # Safety -/// -/// The `data` argument is passed directly to `ptrace(2)`. Read that man page -/// for guidance. -pub unsafe fn write_user( - pid: Pid, - offset: AddressType, - data: *mut c_void, -) -> Result<()> { - ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) -} diff --git a/vendor/nix/src/sys/ptrace/mod.rs b/vendor/nix/src/sys/ptrace/mod.rs deleted file mode 100644 index 2b121c0b4..000000000 --- a/vendor/nix/src/sys/ptrace/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -///! Provides helpers for making ptrace system calls - -#[cfg(any(target_os = "android", target_os = "linux"))] -mod linux; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::linux::*; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -mod bsd; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -pub use self::bsd::*; diff --git a/vendor/nix/src/sys/quota.rs b/vendor/nix/src/sys/quota.rs deleted file mode 100644 index b3c44ca70..000000000 --- a/vendor/nix/src/sys/quota.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! Set and configure disk quotas for users, groups, or projects. -//! -//! # Examples -//! -//! Enabling and setting a quota: -//! -//! ```rust,no_run -//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags}; -//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user").unwrap(); -//! let mut dqblk: Dqblk = Default::default(); -//! dqblk.set_blocks_hard_limit(10000); -//! dqblk.set_blocks_soft_limit(8000); -//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS).unwrap(); -//! ``` -use crate::errno::Errno; -use crate::{NixPath, Result}; -use libc::{self, c_char, c_int}; -use std::default::Default; -use std::{mem, ptr}; - -struct QuotaCmd(QuotaSubCmd, QuotaType); - -impl QuotaCmd { - #[allow(unused_unsafe)] - fn as_int(&self) -> c_int { - unsafe { libc::QCMD(self.0 as i32, self.1 as i32) } - } -} - -// linux quota version >= 2 -libc_enum! { - #[repr(i32)] - enum QuotaSubCmd { - Q_SYNC, - Q_QUOTAON, - Q_QUOTAOFF, - Q_GETQUOTA, - Q_SETQUOTA, - } -} - -libc_enum! { - /// The scope of the quota. - #[repr(i32)] - #[non_exhaustive] - pub enum QuotaType { - /// Specify a user quota - USRQUOTA, - /// Specify a group quota - GRPQUOTA, - } -} - -libc_enum! { - /// The type of quota format to use. - #[repr(i32)] - #[non_exhaustive] - pub enum QuotaFmt { - /// Use the original quota format. - QFMT_VFS_OLD, - /// Use the standard VFS v0 quota format. - /// - /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes. - QFMT_VFS_V0, - /// Use the VFS v1 quota format. - /// - /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes. - QFMT_VFS_V1, - } -} - -libc_bitflags!( - /// Indicates the quota fields that are valid to read from. - #[derive(Default)] - pub struct QuotaValidFlags: u32 { - /// The block hard & soft limit fields. - QIF_BLIMITS; - /// The current space field. - QIF_SPACE; - /// The inode hard & soft limit fields. - QIF_ILIMITS; - /// The current inodes field. - QIF_INODES; - /// The disk use time limit field. - QIF_BTIME; - /// The file quote time limit field. - QIF_ITIME; - /// All block & inode limits. - QIF_LIMITS; - /// The space & inodes usage fields. - QIF_USAGE; - /// The time limit fields. - QIF_TIMES; - /// All fields. - QIF_ALL; - } -); - -/// Wrapper type for `if_dqblk` -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Dqblk(libc::dqblk); - -impl Default for Dqblk { - fn default() -> Dqblk { - Dqblk(libc::dqblk { - dqb_bhardlimit: 0, - dqb_bsoftlimit: 0, - dqb_curspace: 0, - dqb_ihardlimit: 0, - dqb_isoftlimit: 0, - dqb_curinodes: 0, - dqb_btime: 0, - dqb_itime: 0, - dqb_valid: 0, - }) - } -} - -impl Dqblk { - /// The absolute limit on disk quota blocks allocated. - pub fn blocks_hard_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { - Some(self.0.dqb_bhardlimit) - } else { - None - } - } - - /// Set the absolute limit on disk quota blocks allocated. - pub fn set_blocks_hard_limit(&mut self, limit: u64) { - self.0.dqb_bhardlimit = limit; - } - - /// Preferred limit on disk quota blocks - pub fn blocks_soft_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { - Some(self.0.dqb_bsoftlimit) - } else { - None - } - } - - /// Set the preferred limit on disk quota blocks allocated. - pub fn set_blocks_soft_limit(&mut self, limit: u64) { - self.0.dqb_bsoftlimit = limit; - } - - /// Current occupied space (bytes). - pub fn occupied_space(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_SPACE) { - Some(self.0.dqb_curspace) - } else { - None - } - } - - /// Maximum number of allocated inodes. - pub fn inodes_hard_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { - Some(self.0.dqb_ihardlimit) - } else { - None - } - } - - /// Set the maximum number of allocated inodes. - pub fn set_inodes_hard_limit(&mut self, limit: u64) { - self.0.dqb_ihardlimit = limit; - } - - /// Preferred inode limit - pub fn inodes_soft_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { - Some(self.0.dqb_isoftlimit) - } else { - None - } - } - - /// Set the preferred limit of allocated inodes. - pub fn set_inodes_soft_limit(&mut self, limit: u64) { - self.0.dqb_isoftlimit = limit; - } - - /// Current number of allocated inodes. - pub fn allocated_inodes(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_INODES) { - Some(self.0.dqb_curinodes) - } else { - None - } - } - - /// Time limit for excessive disk use. - pub fn block_time_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BTIME) { - Some(self.0.dqb_btime) - } else { - None - } - } - - /// Set the time limit for excessive disk use. - pub fn set_block_time_limit(&mut self, limit: u64) { - self.0.dqb_btime = limit; - } - - /// Time limit for excessive files. - pub fn inode_time_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ITIME) { - Some(self.0.dqb_itime) - } else { - None - } - } - - /// Set the time limit for excessive files. - pub fn set_inode_time_limit(&mut self, limit: u64) { - self.0.dqb_itime = limit; - } -} - -fn quotactl<P: ?Sized + NixPath>( - cmd: QuotaCmd, - special: Option<&P>, - id: c_int, - addr: *mut c_char, -) -> Result<()> { - unsafe { - Errno::clear(); - let res = match special { - Some(dev) => dev.with_nix_path(|path| { - libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr) - }), - None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)), - }?; - - Errno::result(res).map(drop) - } -} - -/// Turn on disk quotas for a block device. -pub fn quotactl_on<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - format: QuotaFmt, - quota_file: &P, -) -> Result<()> { - quota_file.with_nix_path(|path| { - let mut path_copy = path.to_bytes_with_nul().to_owned(); - let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; - quotactl( - QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), - Some(special), - format as c_int, - p, - ) - })? -} - -/// Disable disk quotas for a block device. -pub fn quotactl_off<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, -) -> Result<()> { - quotactl( - QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), - Some(special), - 0, - ptr::null_mut(), - ) -} - -/// Update the on-disk copy of quota usages for a filesystem. -/// -/// If `special` is `None`, then all file systems with active quotas are sync'd. -pub fn quotactl_sync<P: ?Sized + NixPath>( - which: QuotaType, - special: Option<&P>, -) -> Result<()> { - quotactl( - QuotaCmd(QuotaSubCmd::Q_SYNC, which), - special, - 0, - ptr::null_mut(), - ) -} - -/// Get disk quota limits and current usage for the given user/group id. -pub fn quotactl_get<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - id: c_int, -) -> Result<Dqblk> { - let mut dqblk = mem::MaybeUninit::uninit(); - quotactl( - QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), - Some(special), - id, - dqblk.as_mut_ptr() as *mut c_char, - )?; - Ok(unsafe { Dqblk(dqblk.assume_init()) }) -} - -/// Configure quota values for the specified fields for a given user/group id. -pub fn quotactl_set<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - id: c_int, - dqblk: &Dqblk, - fields: QuotaValidFlags, -) -> Result<()> { - let mut dqblk_copy = *dqblk; - dqblk_copy.0.dqb_valid = fields.bits(); - quotactl( - QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), - Some(special), - id, - &mut dqblk_copy as *mut _ as *mut c_char, - ) -} diff --git a/vendor/nix/src/sys/reboot.rs b/vendor/nix/src/sys/reboot.rs deleted file mode 100644 index 02d98162b..000000000 --- a/vendor/nix/src/sys/reboot.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. - -use crate::errno::Errno; -use crate::Result; -use std::convert::Infallible; -use std::mem::drop; - -libc_enum! { - /// How exactly should the system be rebooted. - /// - /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for - /// enabling/disabling Ctrl-Alt-Delete. - #[repr(i32)] - #[non_exhaustive] - pub enum RebootMode { - /// Halt the system. - RB_HALT_SYSTEM, - /// Execute a kernel that has been loaded earlier with - /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). - RB_KEXEC, - /// Stop the system and switch off power, if possible. - RB_POWER_OFF, - /// Restart the system. - RB_AUTOBOOT, - // we do not support Restart2. - /// Suspend the system using software suspend. - RB_SW_SUSPEND, - } -} - -/// Reboots or shuts down the system. -pub fn reboot(how: RebootMode) -> Result<Infallible> { - unsafe { libc::reboot(how as libc::c_int) }; - Err(Errno::last()) -} - -/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). -/// -/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. -pub fn set_cad_enabled(enable: bool) -> Result<()> { - let cmd = if enable { - libc::RB_ENABLE_CAD - } else { - libc::RB_DISABLE_CAD - }; - let res = unsafe { libc::reboot(cmd) }; - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/sys/resource.rs b/vendor/nix/src/sys/resource.rs deleted file mode 100644 index 892773776..000000000 --- a/vendor/nix/src/sys/resource.rs +++ /dev/null @@ -1,443 +0,0 @@ -//! Configure the process resource limits. -use cfg_if::cfg_if; -use libc::{c_int, c_long, rusage}; - -use crate::errno::Errno; -use crate::sys::time::TimeVal; -use crate::Result; -pub use libc::rlim_t; -pub use libc::RLIM_INFINITY; -use std::mem; - -cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - use libc::{__rlimit_resource_t, rlimit}; - } else if #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(target_env = "gnu")) - ))]{ - use libc::rlimit; - } -} - -libc_enum! { - /// Types of process resources. - /// - /// The Resource enum is platform dependent. Check different platform - /// manuals for more details. Some platform links have been provided for - /// easier reference (non-exhaustive). - /// - /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) - /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) - /// * [NetBSD](https://man.netbsd.org/setrlimit.2) - - // linux-gnu uses u_int as resource enum, which is implemented in libc as - // well. - // - // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html - // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs - #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))] - #[cfg_attr(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) - ), repr(i32))] - #[non_exhaustive] - pub enum Resource { - #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum amount (in bytes) of virtual memory the process is - /// allowed to map. - RLIMIT_AS, - /// The largest size (in bytes) core(5) file that may be created. - RLIMIT_CORE, - /// The maximum amount of cpu time (in seconds) to be used by each - /// process. - RLIMIT_CPU, - /// The maximum size (in bytes) of the data segment for a process - RLIMIT_DATA, - /// The largest size (in bytes) file that may be created. - RLIMIT_FSIZE, - /// The maximum number of open files for this process. - RLIMIT_NOFILE, - /// The maximum size (in bytes) of the stack segment for a process. - RLIMIT_STACK, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of kqueues this user id is allowed to create. - RLIMIT_KQUEUES, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the combined number of flock locks and fcntl leases that - /// this process may establish. - RLIMIT_LOCKS, - - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "linux", - target_os = "netbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) which a process may lock into memory - /// using the mlock(2) system call. - RLIMIT_MEMLOCK, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the number of bytes that can be allocated for POSIX - /// message queues for the real user ID of the calling process. - RLIMIT_MSGQUEUE, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A ceiling to which the process's nice value can be raised using - /// setpriority or nice. - RLIMIT_NICE, - - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of simultaneous processes for this user id. - RLIMIT_NPROC, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of pseudo-terminals this user id is allowed to - /// create. - RLIMIT_NPTS, - - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// When there is memory pressure and swap is available, prioritize - /// eviction of a process' resident pages beyond this amount (in bytes). - RLIMIT_RSS, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A ceiling on the real-time priority that may be set for this process - /// using sched_setscheduler and sched_set‐ param. - RLIMIT_RTPRIO, - - #[cfg(any(target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit (in microseconds) on the amount of CPU time that a process - /// scheduled under a real-time scheduling policy may con‐ sume without - /// making a blocking system call. - RLIMIT_RTTIME, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the number of signals that may be queued for the real - /// user ID of the calling process. - RLIMIT_SIGPENDING, - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) of socket buffer usage for this user. - RLIMIT_SBSIZE, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) of the swap space that may be reserved - /// or used by all of this user id's processes. - RLIMIT_SWAP, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// An alias for RLIMIT_AS. - RLIMIT_VMEM, - } -} - -/// Get the current processes resource limits -/// -/// The special value [`RLIM_INFINITY`] indicates that no limit will be -/// enforced. -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to get the limits of. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{getrlimit, Resource}; -/// -/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); -/// println!("current soft_limit: {}", soft_limit); -/// println!("current hard_limit: {}", hard_limit); -/// ``` -/// -/// # References -/// -/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { - let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit(); - - cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; - } else { - let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; - } - } - - Errno::result(res).map(|_| { - let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; - (rlim_cur, rlim_max) - }) -} - -/// Set the current processes resource limits -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to set the limits of. -/// * `soft_limit`: The value that the kernel enforces for the corresponding -/// resource. -/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to -/// the current hard limit for non-root users. -/// -/// The special value [`RLIM_INFINITY`] indicates that no limit will be -/// enforced. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{setrlimit, Resource}; -/// -/// let soft_limit = 512; -/// let hard_limit = 1024; -/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); -/// ``` -/// -/// # References -/// -/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -/// -/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. -pub fn setrlimit( - resource: Resource, - soft_limit: rlim_t, - hard_limit: rlim_t, -) -> Result<()> { - let new_rlim = rlimit { - rlim_cur: soft_limit, - rlim_max: hard_limit, - }; - cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; - }else{ - let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; - } - } - - Errno::result(res).map(drop) -} - -libc_enum! { - /// Whose resource usage should be returned by [`getrusage`]. - #[repr(i32)] - #[non_exhaustive] - pub enum UsageWho { - /// Resource usage for the current process. - RUSAGE_SELF, - - /// Resource usage for all the children that have terminated and been waited for. - RUSAGE_CHILDREN, - - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Resource usage for the calling thread. - RUSAGE_THREAD, - } -} - -/// Output of `getrusage` with information about resource usage. Some of the fields -/// may be unused in some platforms, and will be always zeroed out. See their manuals -/// for details. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Usage(rusage); - -impl AsRef<rusage> for Usage { - fn as_ref(&self) -> &rusage { - &self.0 - } -} - -impl AsMut<rusage> for Usage { - fn as_mut(&mut self) -> &mut rusage { - &mut self.0 - } -} - -impl Usage { - /// Total amount of time spent executing in user mode. - pub fn user_time(&self) -> TimeVal { - TimeVal::from(self.0.ru_utime) - } - - /// Total amount of time spent executing in kernel mode. - pub fn system_time(&self) -> TimeVal { - TimeVal::from(self.0.ru_stime) - } - - /// The resident set size at its peak, in kilobytes. - pub fn max_rss(&self) -> c_long { - self.0.ru_maxrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of text memory shared with other processes. - pub fn shared_integral(&self) -> c_long { - self.0.ru_ixrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of unshared memory used by data. - pub fn unshared_data_integral(&self) -> c_long { - self.0.ru_idrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of unshared memory used for stack space. - pub fn unshared_stack_integral(&self) -> c_long { - self.0.ru_isrss - } - - /// Number of page faults that were served without resorting to I/O, with pages - /// that have been allocated previously by the kernel. - pub fn minor_page_faults(&self) -> c_long { - self.0.ru_minflt - } - - /// Number of page faults that were served through I/O (i.e. swap). - pub fn major_page_faults(&self) -> c_long { - self.0.ru_majflt - } - - /// Number of times all of the memory was fully swapped out. - pub fn full_swaps(&self) -> c_long { - self.0.ru_nswap - } - - /// Number of times a read was done from a block device. - pub fn block_reads(&self) -> c_long { - self.0.ru_inblock - } - - /// Number of times a write was done to a block device. - pub fn block_writes(&self) -> c_long { - self.0.ru_oublock - } - - /// Number of IPC messages sent. - pub fn ipc_sends(&self) -> c_long { - self.0.ru_msgsnd - } - - /// Number of IPC messages received. - pub fn ipc_receives(&self) -> c_long { - self.0.ru_msgrcv - } - - /// Number of signals received. - pub fn signals(&self) -> c_long { - self.0.ru_nsignals - } - - /// Number of times a context switch was voluntarily invoked. - pub fn voluntary_context_switches(&self) -> c_long { - self.0.ru_nvcsw - } - - /// Number of times a context switch was imposed by the kernel (usually due to - /// time slice expiring or preemption by a higher priority process). - pub fn involuntary_context_switches(&self) -> c_long { - self.0.ru_nivcsw - } -} - -/// Get usage information for a process, its children or the current thread -/// -/// Real time information can be obtained for either the current process or (in some -/// systems) thread, but information about children processes is only provided for -/// those that have terminated and been waited for (see [`super::wait::wait`]). -/// -/// Some information may be missing depending on the platform, and the way information -/// is provided for children may also vary. Check the manuals for details. -/// -/// # References -/// -/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html) -/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html) -/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage) -/// * [NetBSD](https://man.netbsd.org/getrusage.2) -/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html) -/// -/// [`UsageWho`]: enum.UsageWho.html -/// -/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`]. -pub fn getrusage(who: UsageWho) -> Result<Usage> { - unsafe { - let mut rusage = mem::MaybeUninit::<rusage>::uninit(); - let res = libc::getrusage(who as c_int, rusage.as_mut_ptr()); - Errno::result(res).map(|_| Usage(rusage.assume_init())) - } -} - -#[cfg(test)] -mod test { - use super::{getrusage, UsageWho}; - - #[test] - pub fn test_self_cpu_time() { - // Make sure some CPU time is used. - let mut numbers: Vec<i32> = (1..1_000_000).collect(); - numbers.iter_mut().for_each(|item| *item *= 2); - - // FIXME: this is here to help ensure the compiler does not optimize the whole - // thing away. Replace the assert with test::black_box once stabilized. - assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100); - - let usage = getrusage(UsageWho::RUSAGE_SELF) - .expect("Failed to call getrusage for SELF"); - let rusage = usage.as_ref(); - - let user = usage.user_time(); - assert!(user.tv_sec() > 0 || user.tv_usec() > 0); - assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); - assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); - } -} diff --git a/vendor/nix/src/sys/select.rs b/vendor/nix/src/sys/select.rs deleted file mode 100644 index 7a94cff87..000000000 --- a/vendor/nix/src/sys/select.rs +++ /dev/null @@ -1,455 +0,0 @@ -//! Portably monitor a group of file descriptors for readiness. -use crate::errno::Errno; -use crate::sys::time::{TimeSpec, TimeVal}; -use crate::Result; -use libc::{self, c_int}; -use std::convert::TryFrom; -use std::iter::FusedIterator; -use std::mem; -use std::ops::Range; -use std::os::unix::io::RawFd; -use std::ptr::{null, null_mut}; - -pub use libc::FD_SETSIZE; - -/// Contains a set of file descriptors used by [`select`] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct FdSet(libc::fd_set); - -fn assert_fd_valid(fd: RawFd) { - assert!( - usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE), - "fd must be in the range 0..FD_SETSIZE", - ); -} - -impl FdSet { - /// Create an empty `FdSet` - pub fn new() -> FdSet { - let mut fdset = mem::MaybeUninit::uninit(); - unsafe { - libc::FD_ZERO(fdset.as_mut_ptr()); - FdSet(fdset.assume_init()) - } - } - - /// Add a file descriptor to an `FdSet` - pub fn insert(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_SET(fd, &mut self.0) }; - } - - /// Remove a file descriptor from an `FdSet` - pub fn remove(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_CLR(fd, &mut self.0) }; - } - - /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains(&self, fd: RawFd) -> bool { - assert_fd_valid(fd); - unsafe { libc::FD_ISSET(fd, &self.0) } - } - - /// Remove all file descriptors from this `FdSet`. - pub fn clear(&mut self) { - unsafe { libc::FD_ZERO(&mut self.0) }; - } - - /// Finds the highest file descriptor in the set. - /// - /// Returns `None` if the set is empty. - /// - /// This can be used to calculate the `nfds` parameter of the [`select`] function. - /// - /// # Example - /// - /// ``` - /// # use nix::sys::select::FdSet; - /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// assert_eq!(set.highest(), Some(9)); - /// ``` - /// - /// [`select`]: fn.select.html - pub fn highest(&self) -> Option<RawFd> { - self.fds(None).next_back() - } - - /// Returns an iterator over the file descriptors in the set. - /// - /// For performance, it takes an optional higher bound: the iterator will - /// not return any elements of the set greater than the given file - /// descriptor. - /// - /// # Examples - /// - /// ``` - /// # use nix::sys::select::FdSet; - /// # use std::os::unix::io::RawFd; - /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// let fds: Vec<RawFd> = set.fds(None).collect(); - /// assert_eq!(fds, vec![4, 9]); - /// ``` - #[inline] - pub fn fds(&self, highest: Option<RawFd>) -> Fds { - Fds { - set: self, - range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE), - } - } -} - -impl Default for FdSet { - fn default() -> Self { - Self::new() - } -} - -/// Iterator over `FdSet`. -#[derive(Debug)] -pub struct Fds<'a> { - set: &'a FdSet, - range: Range<usize>, -} - -impl<'a> Iterator for Fds<'a> { - type Item = RawFd; - - fn next(&mut self) -> Option<RawFd> { - for i in &mut self.range { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (_, upper) = self.range.size_hint(); - (0, upper) - } -} - -impl<'a> DoubleEndedIterator for Fds<'a> { - #[inline] - fn next_back(&mut self) -> Option<RawFd> { - while let Some(i) = self.range.next_back() { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); - } - } - None - } -} - -impl<'a> FusedIterator for Fds<'a> {} - -/// Monitors file descriptors for readiness -/// -/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all -/// file descriptors that are ready for the given operation are set. -/// -/// When this function returns, `timeout` has an implementation-defined value. -/// -/// # Parameters -/// -/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this -/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 -/// to the maximum of that. -/// * `readfds`: File descriptors to check for being ready to read. -/// * `writefds`: File descriptors to check for being ready to write. -/// * `errorfds`: File descriptors to check for pending error conditions. -/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block -/// indefinitely). -/// -/// # References -/// -/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) -/// -/// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn select<'a, N, R, W, E, T>( - nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, -) -> Result<c_int> -where - N: Into<Option<c_int>>, - R: Into<Option<&'a mut FdSet>>, - W: Into<Option<&'a mut FdSet>>, - E: Into<Option<&'a mut FdSet>>, - T: Into<Option<&'a mut TimeVal>>, -{ - let mut readfds = readfds.into(); - let mut writefds = writefds.into(); - let mut errorfds = errorfds.into(); - let timeout = timeout.into(); - - let nfds = nfds.into().unwrap_or_else(|| { - readfds - .iter_mut() - .chain(writefds.iter_mut()) - .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) - .max() - .unwrap_or(-1) - + 1 - }); - - let readfds = readfds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let writefds = writefds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let errorfds = errorfds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let timeout = timeout - .map(|tv| tv as *mut _ as *mut libc::timeval) - .unwrap_or(null_mut()); - - let res = - unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) }; - - Errno::result(res) -} - -feature! { -#![feature = "signal"] - -use crate::sys::signal::SigSet; - -/// Monitors file descriptors for readiness with an altered signal mask. -/// -/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all -/// file descriptors that are ready for the given operation are set. -/// -/// When this function returns, the original signal mask is restored. -/// -/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value. -/// -/// # Parameters -/// -/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this -/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 -/// to the maximum of that. -/// * `readfds`: File descriptors to check for read readiness -/// * `writefds`: File descriptors to check for write readiness -/// * `errorfds`: File descriptors to check for pending error conditions. -/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block -/// indefinitely). -/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn -/// ready (`None` to set no alternative signal mask). -/// -/// # References -/// -/// [pselect(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) -/// -/// [The new pselect() system call](https://lwn.net/Articles/176911/) -/// -/// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, - sigmask: S) -> Result<c_int> -where - N: Into<Option<c_int>>, - R: Into<Option<&'a mut FdSet>>, - W: Into<Option<&'a mut FdSet>>, - E: Into<Option<&'a mut FdSet>>, - T: Into<Option<&'a TimeSpec>>, - S: Into<Option<&'a SigSet>>, -{ - let mut readfds = readfds.into(); - let mut writefds = writefds.into(); - let mut errorfds = errorfds.into(); - let sigmask = sigmask.into(); - let timeout = timeout.into(); - - let nfds = nfds.into().unwrap_or_else(|| { - readfds.iter_mut() - .chain(writefds.iter_mut()) - .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) - .max() - .unwrap_or(-1) + 1 - }); - - let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null()); - let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null()); - - let res = unsafe { - libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask) - }; - - Errno::result(res) -} -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{pipe, write}; - use std::os::unix::io::RawFd; - - #[test] - fn fdset_insert() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - - fd_set.insert(7); - - assert!(fd_set.contains(7)); - } - - #[test] - fn fdset_remove() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - - fd_set.insert(7); - fd_set.remove(7); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - } - - #[test] - fn fdset_clear() { - let mut fd_set = FdSet::new(); - fd_set.insert(1); - fd_set.insert((FD_SETSIZE / 2) as RawFd); - fd_set.insert((FD_SETSIZE - 1) as RawFd); - - fd_set.clear(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - } - - #[test] - fn fdset_highest() { - let mut set = FdSet::new(); - assert_eq!(set.highest(), None); - set.insert(0); - assert_eq!(set.highest(), Some(0)); - set.insert(90); - assert_eq!(set.highest(), Some(90)); - set.remove(0); - assert_eq!(set.highest(), Some(90)); - set.remove(90); - assert_eq!(set.highest(), None); - - set.insert(4); - set.insert(5); - set.insert(7); - assert_eq!(set.highest(), Some(7)); - } - - #[test] - fn fdset_fds() { - let mut set = FdSet::new(); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]); - set.insert(0); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]); - set.insert(90); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]); - - // highest limit - assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]); - assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]); - } - - #[test] - fn test_select() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select(None, &mut fd_set, None, None, &mut timeout).unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } - - #[test] - fn test_select_nfds() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - Some(fd_set.highest().unwrap() + 1), - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } - - #[test] - fn test_select_nfds2() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - ::std::cmp::max(r1, r2) + 1, - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } -} diff --git a/vendor/nix/src/sys/sendfile.rs b/vendor/nix/src/sys/sendfile.rs deleted file mode 100644 index fb293a4e7..000000000 --- a/vendor/nix/src/sys/sendfile.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Send data from a file to a socket, bypassing userland. - -use cfg_if::cfg_if; -use std::os::unix::io::RawFd; -use std::ptr; - -use libc::{self, off_t}; - -use crate::errno::Errno; -use crate::Result; - -/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. -/// -/// Returns a `Result` with the number of bytes written. -/// -/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will -/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified -/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to -/// the byte after the last byte copied. -/// -/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. -/// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile( - out_fd: RawFd, - in_fd: RawFd, - offset: Option<&mut off_t>, - count: usize, -) -> Result<usize> { - let offset = offset - .map(|offset| offset as *mut _) - .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; - Errno::result(ret).map(|r| r as usize) -} - -/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. -/// -/// Returns a `Result` with the number of bytes written. -/// -/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will -/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified -/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to -/// the byte after the last byte copied. -/// -/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. -/// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile64( - out_fd: RawFd, - in_fd: RawFd, - offset: Option<&mut libc::off64_t>, - count: usize, -) -> Result<usize> { - let offset = offset - .map(|offset| offset as *mut _) - .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; - Errno::result(ret).map(|r| r as usize) -} - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { - use std::io::IoSlice; - - #[derive(Clone, Debug)] - struct SendfileHeaderTrailer<'a>( - libc::sf_hdtr, - Option<Vec<IoSlice<'a>>>, - Option<Vec<IoSlice<'a>>>, - ); - - impl<'a> SendfileHeaderTrailer<'a> { - fn new( - headers: Option<&'a [&'a [u8]]>, - trailers: Option<&'a [&'a [u8]]> - ) -> SendfileHeaderTrailer<'a> { - let header_iovecs: Option<Vec<IoSlice<'_>>> = - headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - let trailer_iovecs: Option<Vec<IoSlice<'_>>> = - trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - SendfileHeaderTrailer( - libc::sf_hdtr { - headers: { - header_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec - }, - hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32, - trailers: { - trailer_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec - }, - trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 - }, - header_iovecs, - trailer_iovecs, - ) - } - } - } -} - -cfg_if! { - if #[cfg(target_os = "freebsd")] { - use libc::c_int; - - libc_bitflags!{ - /// Configuration options for [`sendfile`.](fn.sendfile.html) - pub struct SfFlags: c_int { - /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a - /// busy page. - SF_NODISKIO; - /// Causes `sendfile` to sleep until the network stack releases its reference to the - /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been - /// sent, but it is safe to modify the file. - SF_SYNC; - /// Causes `sendfile` to cache exactly the number of pages specified in the - /// `readahead` parameter, disabling caching heuristics. - SF_USER_READAHEAD; - /// Causes `sendfile` not to cache the data read. - SF_NOCACHE; - } - } - - /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a - /// stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `headers` and `trailers` specify optional slices of byte slices to be sent before and - /// after the data read from `in_fd`, respectively. The length of headers and trailers sent - /// is included in the returned count of bytes written. The values of `offset` and `count` - /// do not apply to headers or trailers. - /// - /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page - /// currently being sent. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) - #[allow(clippy::too_many_arguments)] - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<usize>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]>, - flags: SfFlags, - readahead: u16 - ) -> (Result<()>, off_t) { - // Readahead goes in upper 16 bits - // Flags goes in lower 16 bits - // see `man 2 sendfile` - let ra32 = u32::from(readahead); - let flags: u32 = (ra32 << 16) | (flags.bits() as u32); - let mut bytes_sent: off_t = 0; - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - count.unwrap_or(0), - hdtr_ptr as *mut libc::sf_hdtr, - &mut bytes_sent as *mut off_t, - flags as c_int) - }; - (Errno::result(return_code).and(Ok(())), bytes_sent) - } - } else if #[cfg(target_os = "dragonfly")] { - /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `headers` and `trailers` specify optional slices of byte slices to be sent before and - /// after the data read from `in_fd`, respectively. The length of headers and trailers sent - /// is included in the returned count of bytes written. The values of `offset` and `count` - /// do not apply to headers or trailers. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<usize>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]>, - ) -> (Result<()>, off_t) { - let mut bytes_sent: off_t = 0; - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - count.unwrap_or(0), - hdtr_ptr as *mut libc::sf_hdtr, - &mut bytes_sent as *mut off_t, - 0) - }; - (Errno::result(return_code).and(Ok(())), bytes_sent) - } - } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { - /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to - /// `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `hdtr` specifies an optional list of headers and trailers to be sent before and after - /// the data read from `in_fd`, respectively. The length of headers and trailers sent is - /// included in the returned count of bytes written. If any headers are specified and - /// `count` is non-zero, the length of the headers will be counted in the limit of total - /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent - /// regardless. The value of `offset` does not affect headers or trailers. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<off_t>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]> - ) -> (Result<()>, off_t) { - let mut len = count.unwrap_or(0); - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - &mut len as *mut off_t, - hdtr_ptr as *mut libc::sf_hdtr, - 0) - }; - (Errno::result(return_code).and(Ok(())), len) - } - } -} diff --git a/vendor/nix/src/sys/signal.rs b/vendor/nix/src/sys/signal.rs deleted file mode 100644 index d3746e609..000000000 --- a/vendor/nix/src/sys/signal.rs +++ /dev/null @@ -1,1348 +0,0 @@ -// Portions of this file are Copyright 2014 The Rust Project Developers. -// See https://www.rust-lang.org/policies/licenses. - -//! Operating system signals. - -use crate::errno::Errno; -use crate::{Error, Result}; -use cfg_if::cfg_if; -use std::fmt; -use std::mem; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] -use std::os::unix::io::RawFd; -use std::ptr; -use std::str::FromStr; - -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[cfg(any(feature = "aio", feature = "signal"))] -pub use self::sigevent::*; - -#[cfg(any(feature = "aio", feature = "process", feature = "signal"))] -libc_enum! { - /// Types of operating system signals - // Currently there is only one definition of c_int in libc, as well as only one - // type for signal constants. - // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately - // this is not (yet) possible. - #[repr(i32)] - #[non_exhaustive] - #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))] - pub enum Signal { - /// Hangup - SIGHUP, - /// Interrupt - SIGINT, - /// Quit - SIGQUIT, - /// Illegal instruction (not reset when caught) - SIGILL, - /// Trace trap (not reset when caught) - SIGTRAP, - /// Abort - SIGABRT, - /// Bus error - SIGBUS, - /// Floating point exception - SIGFPE, - /// Kill (cannot be caught or ignored) - SIGKILL, - /// User defined signal 1 - SIGUSR1, - /// Segmentation violation - SIGSEGV, - /// User defined signal 2 - SIGUSR2, - /// Write on a pipe with no one to read it - SIGPIPE, - /// Alarm clock - SIGALRM, - /// Software termination signal from kill - SIGTERM, - /// Stack fault (obsolete) - #[cfg(all(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"), - not(any(target_arch = "mips", target_arch = "mips64", - target_arch = "sparc64"))))] - SIGSTKFLT, - /// To parent on child stop or exit - SIGCHLD, - /// Continue a stopped process - SIGCONT, - /// Sendable stop signal not from tty - SIGSTOP, - /// Stop signal from tty - SIGTSTP, - /// To readers pgrp upon background tty read - SIGTTIN, - /// Like TTIN if (tp->t_local<OSTOP) - SIGTTOU, - /// Urgent condition on IO channel - SIGURG, - /// Exceeded CPU time limit - SIGXCPU, - /// Exceeded file size limit - SIGXFSZ, - /// Virtual time alarm - SIGVTALRM, - /// Profiling time alarm - SIGPROF, - /// Window size changes - SIGWINCH, - /// Input/output possible signal - #[cfg(not(target_os = "haiku"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SIGIO, - #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Power failure imminent. - SIGPWR, - /// Bad system call - SIGSYS, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Emulator trap - SIGEMT, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Information request - SIGINFO, - } - impl TryFrom<i32> -} - -#[cfg(feature = "signal")] -impl FromStr for Signal { - type Err = Error; - fn from_str(s: &str) -> Result<Signal> { - Ok(match s { - "SIGHUP" => Signal::SIGHUP, - "SIGINT" => Signal::SIGINT, - "SIGQUIT" => Signal::SIGQUIT, - "SIGILL" => Signal::SIGILL, - "SIGTRAP" => Signal::SIGTRAP, - "SIGABRT" => Signal::SIGABRT, - "SIGBUS" => Signal::SIGBUS, - "SIGFPE" => Signal::SIGFPE, - "SIGKILL" => Signal::SIGKILL, - "SIGUSR1" => Signal::SIGUSR1, - "SIGSEGV" => Signal::SIGSEGV, - "SIGUSR2" => Signal::SIGUSR2, - "SIGPIPE" => Signal::SIGPIPE, - "SIGALRM" => Signal::SIGALRM, - "SIGTERM" => Signal::SIGTERM, - #[cfg(all( - any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) - ))] - "SIGSTKFLT" => Signal::SIGSTKFLT, - "SIGCHLD" => Signal::SIGCHLD, - "SIGCONT" => Signal::SIGCONT, - "SIGSTOP" => Signal::SIGSTOP, - "SIGTSTP" => Signal::SIGTSTP, - "SIGTTIN" => Signal::SIGTTIN, - "SIGTTOU" => Signal::SIGTTOU, - "SIGURG" => Signal::SIGURG, - "SIGXCPU" => Signal::SIGXCPU, - "SIGXFSZ" => Signal::SIGXFSZ, - "SIGVTALRM" => Signal::SIGVTALRM, - "SIGPROF" => Signal::SIGPROF, - "SIGWINCH" => Signal::SIGWINCH, - #[cfg(not(target_os = "haiku"))] - "SIGIO" => Signal::SIGIO, - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - "SIGPWR" => Signal::SIGPWR, - "SIGSYS" => Signal::SIGSYS, - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - "SIGEMT" => Signal::SIGEMT, - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - "SIGINFO" => Signal::SIGINFO, - _ => return Err(Errno::EINVAL), - }) - } -} - -#[cfg(feature = "signal")] -impl Signal { - /// Returns name of signal. - /// - /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`, - /// with difference that returned string is `'static` - /// and not bound to `self`'s lifetime. - pub const fn as_str(self) -> &'static str { - match self { - Signal::SIGHUP => "SIGHUP", - Signal::SIGINT => "SIGINT", - Signal::SIGQUIT => "SIGQUIT", - Signal::SIGILL => "SIGILL", - Signal::SIGTRAP => "SIGTRAP", - Signal::SIGABRT => "SIGABRT", - Signal::SIGBUS => "SIGBUS", - Signal::SIGFPE => "SIGFPE", - Signal::SIGKILL => "SIGKILL", - Signal::SIGUSR1 => "SIGUSR1", - Signal::SIGSEGV => "SIGSEGV", - Signal::SIGUSR2 => "SIGUSR2", - Signal::SIGPIPE => "SIGPIPE", - Signal::SIGALRM => "SIGALRM", - Signal::SIGTERM => "SIGTERM", - #[cfg(all( - any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) - ))] - Signal::SIGSTKFLT => "SIGSTKFLT", - Signal::SIGCHLD => "SIGCHLD", - Signal::SIGCONT => "SIGCONT", - Signal::SIGSTOP => "SIGSTOP", - Signal::SIGTSTP => "SIGTSTP", - Signal::SIGTTIN => "SIGTTIN", - Signal::SIGTTOU => "SIGTTOU", - Signal::SIGURG => "SIGURG", - Signal::SIGXCPU => "SIGXCPU", - Signal::SIGXFSZ => "SIGXFSZ", - Signal::SIGVTALRM => "SIGVTALRM", - Signal::SIGPROF => "SIGPROF", - Signal::SIGWINCH => "SIGWINCH", - #[cfg(not(target_os = "haiku"))] - Signal::SIGIO => "SIGIO", - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - Signal::SIGPWR => "SIGPWR", - Signal::SIGSYS => "SIGSYS", - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - Signal::SIGEMT => "SIGEMT", - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - Signal::SIGINFO => "SIGINFO", - } - } -} - -#[cfg(feature = "signal")] -impl AsRef<str> for Signal { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[cfg(feature = "signal")] -impl fmt::Display for Signal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.as_ref()) - } -} - -#[cfg(feature = "signal")] -pub use self::Signal::*; - -#[cfg(target_os = "redox")] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 29] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGSYS, -]; -#[cfg(target_os = "haiku")] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 28] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGSYS, -]; -#[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) -))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 31] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, - SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, - SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, -]; -#[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") -))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 30] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, -]; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "emscripten", - target_os = "redox", - target_os = "haiku" -)))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 31] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, -]; - -feature! { -#![feature = "signal"] - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -/// Iterate through all signals defined by this operating system -pub struct SignalIterator { - next: usize, -} - -impl Iterator for SignalIterator { - type Item = Signal; - - fn next(&mut self) -> Option<Signal> { - if self.next < SIGNALS.len() { - let next_signal = SIGNALS[self.next]; - self.next += 1; - Some(next_signal) - } else { - None - } - } -} - -impl Signal { - /// Iterate through all signals defined by this OS - pub const fn iterator() -> SignalIterator { - SignalIterator{next: 0} - } -} - -/// Alias for [`SIGABRT`] -pub const SIGIOT : Signal = SIGABRT; -/// Alias for [`SIGIO`] -#[cfg(not(target_os = "haiku"))] -pub const SIGPOLL : Signal = SIGIO; -/// Alias for [`SIGSYS`] -pub const SIGUNUSED : Signal = SIGSYS; - -cfg_if! { - if #[cfg(target_os = "redox")] { - type SaFlags_t = libc::c_ulong; - } else if #[cfg(target_env = "uclibc")] { - type SaFlags_t = libc::c_ulong; - } else { - type SaFlags_t = libc::c_int; - } -} -} - -#[cfg(feature = "signal")] -libc_bitflags! { - /// Controls the behavior of a [`SigAction`] - #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] - pub struct SaFlags: SaFlags_t { - /// When catching a [`Signal::SIGCHLD`] signal, the signal will be - /// generated only when a child process exits, not when a child process - /// stops. - SA_NOCLDSTOP; - /// When catching a [`Signal::SIGCHLD`] signal, the system will not - /// create zombie processes when children of the calling process exit. - SA_NOCLDWAIT; - /// Further occurrences of the delivered signal are not masked during - /// the execution of the handler. - SA_NODEFER; - /// The system will deliver the signal to the process on a signal stack, - /// specified by each thread with sigaltstack(2). - SA_ONSTACK; - /// The handler is reset back to the default at the moment the signal is - /// delivered. - SA_RESETHAND; - /// Requests that certain system calls restart if interrupted by this - /// signal. See the man page for complete details. - SA_RESTART; - /// This flag is controlled internally by Nix. - SA_SIGINFO; - } -} - -#[cfg(feature = "signal")] -libc_enum! { - /// Specifies how certain functions should manipulate a signal mask - #[repr(i32)] - #[non_exhaustive] - #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] - pub enum SigmaskHow { - /// The new mask is the union of the current mask and the specified set. - SIG_BLOCK, - /// The new mask is the intersection of the current mask and the - /// complement of the specified set. - SIG_UNBLOCK, - /// The current mask is replaced by the specified set. - SIG_SETMASK, - } -} - -feature! { -#![feature = "signal"] - -use crate::unistd::Pid; -use std::iter::Extend; -use std::iter::FromIterator; -use std::iter::IntoIterator; - -/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. -// We are using `transparent` here to be super sure that `SigSet` -// is represented exactly like the `sigset_t` struct from C. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SigSet { - sigset: libc::sigset_t -} - -impl SigSet { - /// Initialize to include all signals. - #[doc(alias("sigfillset"))] - pub fn all() -> SigSet { - let mut sigset = mem::MaybeUninit::uninit(); - let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; - - unsafe{ SigSet { sigset: sigset.assume_init() } } - } - - /// Initialize to include nothing. - #[doc(alias("sigemptyset"))] - pub fn empty() -> SigSet { - let mut sigset = mem::MaybeUninit::uninit(); - let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; - - unsafe{ SigSet { sigset: sigset.assume_init() } } - } - - /// Add the specified signal to the set. - #[doc(alias("sigaddset"))] - pub fn add(&mut self, signal: Signal) { - unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; - } - - /// Remove all signals from this set. - #[doc(alias("sigemptyset"))] - pub fn clear(&mut self) { - unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; - } - - /// Remove the specified signal from this set. - #[doc(alias("sigdelset"))] - pub fn remove(&mut self, signal: Signal) { - unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; - } - - /// Return whether this set includes the specified signal. - #[doc(alias("sigismember"))] - pub fn contains(&self, signal: Signal) -> bool { - let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; - - match res { - 1 => true, - 0 => false, - _ => unreachable!("unexpected value from sigismember"), - } - } - - /// Returns an iterator that yields the signals contained in this set. - pub fn iter(&self) -> SigSetIter<'_> { - self.into_iter() - } - - /// Gets the currently blocked (masked) set of signals for the calling thread. - pub fn thread_get_mask() -> Result<SigSet> { - let mut oldmask = mem::MaybeUninit::uninit(); - do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?; - Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) - } - - /// Sets the set of signals as the signal mask for the calling thread. - pub fn thread_set_mask(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None) - } - - /// Adds the set of signals to the signal mask for the calling thread. - pub fn thread_block(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None) - } - - /// Removes the set of signals from the signal mask for the calling thread. - pub fn thread_unblock(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None) - } - - /// Sets the set of signals as the signal mask, and returns the old mask. - pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> { - let mut oldmask = mem::MaybeUninit::uninit(); - do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?; - Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) - } - - /// Suspends execution of the calling thread until one of the signals in the - /// signal mask becomes pending, and returns the accepted signal. - #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn wait(&self) -> Result<Signal> { - use std::convert::TryFrom; - - let mut signum = mem::MaybeUninit::uninit(); - let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; - - Errno::result(res).map(|_| unsafe { - Signal::try_from(signum.assume_init()).unwrap() - }) - } - - /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the - /// `libc::sigset_t` is already initialized. - /// - /// # Safety - /// - /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either - /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or - /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html). - /// Otherwise, the results are undefined. - pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet { - SigSet { sigset } - } -} - -impl AsRef<libc::sigset_t> for SigSet { - fn as_ref(&self) -> &libc::sigset_t { - &self.sigset - } -} - -// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. -impl Extend<Signal> for SigSet { - fn extend<T>(&mut self, iter: T) - where T: IntoIterator<Item = Signal> { - for signal in iter { - self.add(signal); - } - } -} - -impl FromIterator<Signal> for SigSet { - fn from_iter<T>(iter: T) -> Self - where T: IntoIterator<Item = Signal> { - let mut sigset = SigSet::empty(); - sigset.extend(iter); - sigset - } -} - -/// Iterator for a [`SigSet`]. -/// -/// Call [`SigSet::iter`] to create an iterator. -#[derive(Clone, Debug)] -pub struct SigSetIter<'a> { - sigset: &'a SigSet, - inner: SignalIterator, -} - -impl Iterator for SigSetIter<'_> { - type Item = Signal; - fn next(&mut self) -> Option<Signal> { - loop { - match self.inner.next() { - None => return None, - Some(signal) if self.sigset.contains(signal) => return Some(signal), - Some(_signal) => continue, - } - } - } -} - -impl<'a> IntoIterator for &'a SigSet { - type Item = Signal; - type IntoIter = SigSetIter<'a>; - fn into_iter(self) -> Self::IntoIter { - SigSetIter { sigset: self, inner: Signal::iterator() } - } -} - -/// A signal handler. -#[allow(unknown_lints)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SigHandler { - /// Default signal handling. - SigDfl, - /// Request that the signal be ignored. - SigIgn, - /// Use the given signal-catching function, which takes in the signal. - Handler(extern fn(libc::c_int)), - /// Use the given signal-catching function, which takes in the signal, information about how - /// the signal was generated, and a pointer to the threads `ucontext_t`. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) -} - -/// Action to take on receipt of a signal. Corresponds to `sigaction`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SigAction { - sigaction: libc::sigaction -} - -impl SigAction { - /// Creates a new action. - /// - /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` - /// is the `SigAction` variant). `mask` specifies other signals to block during execution of - /// the signal-catching function. - pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { - unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_sigaction = match handler { - SigHandler::SigDfl => libc::SIG_DFL, - SigHandler::SigIgn => libc::SIG_IGN, - SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, - }; - } - - let mut s = mem::MaybeUninit::<libc::sigaction>::uninit(); - unsafe { - let p = s.as_mut_ptr(); - install_sig(p, handler); - (*p).sa_flags = match handler { - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(), - _ => (flags - SaFlags::SA_SIGINFO).bits(), - }; - (*p).sa_mask = mask.sigset; - - SigAction { sigaction: s.assume_init() } - } - } - - /// Returns the flags set on the action. - pub fn flags(&self) -> SaFlags { - SaFlags::from_bits_truncate(self.sigaction.sa_flags) - } - - /// Returns the set of signals that are blocked during execution of the action's - /// signal-catching function. - pub fn mask(&self) -> SigSet { - SigSet { sigset: self.sigaction.sa_mask } - } - - /// Returns the action's handler. - pub fn handler(&self) -> SigHandler { - match self.sigaction.sa_sigaction { - libc::SIG_DFL => SigHandler::SigDfl, - libc::SIG_IGN => SigHandler::SigIgn, - #[cfg(not(target_os = "redox"))] - p if self.flags().contains(SaFlags::SA_SIGINFO) => - SigHandler::SigAction( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(_, _, _)) - } - as extern fn(_, _, _)), - p => SigHandler::Handler( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(libc::c_int)) - } - as extern fn(libc::c_int)), - } - } -} - -/// Changes the action taken by a process on receipt of a specific signal. -/// -/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous -/// action for the given signal. If `sigaction` fails, no new signal handler is installed. -/// -/// # Safety -/// -/// * Signal handlers may be called at any point during execution, which limits -/// what is safe to do in the body of the signal-catching function. Be certain -/// to only make syscalls that are explicitly marked safe for signal handlers -/// and only share global data using atomics. -/// -/// * There is also no guarantee that the old signal handler was installed -/// correctly. If it was installed by this crate, it will be. But if it was -/// installed by, for example, C code, then there is no guarantee its function -/// pointer is valid. In that case, this function effectively dereferences a -/// raw pointer of unknown provenance. -pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { - let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit(); - - let res = libc::sigaction(signal as libc::c_int, - &sigaction.sigaction as *const libc::sigaction, - oldact.as_mut_ptr()); - - Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) -} - -/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) -/// -/// Installs `handler` for the given `signal`, returning the previous signal -/// handler. `signal` should only be used following another call to `signal` or -/// if the current handler is the default. The return value of `signal` is -/// undefined after setting the handler with [`sigaction`][SigActionFn]. -/// -/// # Safety -/// -/// If the pointer to the previous signal handler is invalid, undefined -/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. -/// -/// # Examples -/// -/// Ignore `SIGINT`: -/// -/// ```no_run -/// # use nix::sys::signal::{self, Signal, SigHandler}; -/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); -/// ``` -/// -/// Use a signal handler to set a flag variable: -/// -/// ```no_run -/// # #[macro_use] extern crate lazy_static; -/// # use std::convert::TryFrom; -/// # use std::sync::atomic::{AtomicBool, Ordering}; -/// # use nix::sys::signal::{self, Signal, SigHandler}; -/// lazy_static! { -/// static ref SIGNALED: AtomicBool = AtomicBool::new(false); -/// } -/// -/// extern fn handle_sigint(signal: libc::c_int) { -/// let signal = Signal::try_from(signal).unwrap(); -/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); -/// } -/// -/// fn main() { -/// let handler = SigHandler::Handler(handle_sigint); -/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); -/// } -/// ``` -/// -/// # Errors -/// -/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is -/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. -/// -/// `signal` also returns any error from `libc::signal`, such as when an attempt -/// is made to catch a signal that cannot be caught or to ignore a signal that -/// cannot be ignored. -/// -/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation -/// [SigActionStruct]: struct.SigAction.html -/// [sigactionFn]: fn.sigaction.html -pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { - let signal = signal as libc::c_int; - let res = match handler { - SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), - SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), - SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), - }; - Errno::result(res).map(|oldhandler| { - match oldhandler { - libc::SIG_DFL => SigHandler::SigDfl, - libc::SIG_IGN => SigHandler::SigIgn, - p => SigHandler::Handler( - *(&p as *const usize - as *const extern fn(libc::c_int)) - as extern fn(libc::c_int)), - } - }) -} - -fn do_pthread_sigmask(how: SigmaskHow, - set: Option<&SigSet>, - oldset: Option<*mut libc::sigset_t>) -> Result<()> { - if set.is_none() && oldset.is_none() { - return Ok(()) - } - - let res = unsafe { - // if set or oldset is None, pass in null pointers instead - libc::pthread_sigmask(how as libc::c_int, - set.map_or_else(ptr::null::<libc::sigset_t>, - |s| &s.sigset as *const libc::sigset_t), - oldset.unwrap_or(ptr::null_mut()) - ) - }; - - Errno::result(res).map(drop) -} - -/// Manages the signal mask (set of blocked signals) for the calling thread. -/// -/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. -/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, -/// and no modification will take place. -/// -/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. -/// -/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, -/// and then it will be updated with `set`. -/// -/// If both `set` and `oldset` is None, this function is a no-op. -/// -/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), -/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. -pub fn pthread_sigmask(how: SigmaskHow, - set: Option<&SigSet>, - oldset: Option<&mut SigSet>) -> Result<()> -{ - do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ )) -} - -/// Examine and change blocked signals. -/// -/// For more information see the [`sigprocmask` man -/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). -pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { - if set.is_none() && oldset.is_none() { - return Ok(()) - } - - let res = unsafe { - // if set or oldset is None, pass in null pointers instead - libc::sigprocmask(how as libc::c_int, - set.map_or_else(ptr::null::<libc::sigset_t>, - |s| &s.sigset as *const libc::sigset_t), - oldset.map_or_else(ptr::null_mut::<libc::sigset_t>, - |os| &mut os.sigset as *mut libc::sigset_t)) - }; - - Errno::result(res).map(drop) -} - -/// Send a signal to a process -/// -/// # Arguments -/// -/// * `pid` - Specifies which processes should receive the signal. -/// - If positive, specifies an individual process. -/// - If zero, the signal will be sent to all processes whose group -/// ID is equal to the process group ID of the sender. This is a -#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] -#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] -/// - If `-1` and the process has super-user privileges, the signal -/// is sent to all processes exclusing system processes. -/// - If less than `-1`, the signal is sent to all processes whose -/// process group ID is equal to the absolute value of `pid`. -/// * `signal` - Signal to send. If `None`, error checking is performed -/// but no signal is actually sent. -/// -/// See Also -/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) -pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { - let res = unsafe { libc::kill(pid.into(), - match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }) }; - - Errno::result(res).map(drop) -} - -/// Send a signal to a process group -/// -/// # Arguments -/// -/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior -/// is platform-specific. -/// * `signal` - Signal to send. If `None`, `killpg` will only preform error -/// checking and won't send any signal. -/// -/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). -#[cfg(not(target_os = "fuchsia"))] -pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { - let res = unsafe { libc::killpg(pgrp.into(), - match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }) }; - - Errno::result(res).map(drop) -} - -/// Send a signal to the current thread -/// -/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) -pub fn raise(signal: Signal) -> Result<()> { - let res = unsafe { libc::raise(signal as libc::c_int) }; - - Errno::result(res).map(drop) -} -} - -feature! { -#![any(feature = "aio", feature = "signal")] - -/// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(target_os = "freebsd")] -pub type type_of_thread_id = libc::lwpid_t; -/// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(target_os = "linux")] -pub type type_of_thread_id = libc::pid_t; - -/// Specifies the notification method used by a [`SigEvent`] -// sigval is actually a union of a int and a void*. But it's never really used -// as a pointer, because neither libc nor the kernel ever dereference it. nix -// therefore presents it as an intptr_t, which is how kevent uses it. -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SigevNotify { - /// No notification will be delivered - SigevNone, - /// Notify by delivering a signal to the process. - SigevSignal { - /// Signal to deliver - signal: Signal, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, - // Note: SIGEV_THREAD is not implemented because libc::sigevent does not - // expose a way to set the union members needed by SIGEV_THREAD. - /// Notify by delivering an event to a kqueue. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigevKevent { - /// File descriptor of the kqueue to notify. - kq: RawFd, - /// Will be contained in the kevent's `udata` field. - udata: libc::intptr_t - }, - /// Notify by delivering a signal to a thread. - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigevThreadId { - /// Signal to send - signal: Signal, - /// LWP ID of the thread to notify - thread_id: type_of_thread_id, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, -} -} - -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod sigevent { - feature! { - #![any(feature = "aio", feature = "signal")] - - use std::mem; - use std::ptr; - use super::SigevNotify; - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - use super::type_of_thread_id; - - /// Used to request asynchronous notification of the completion of certain - /// events, such as POSIX AIO and timers. - #[repr(C)] - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct SigEvent { - sigevent: libc::sigevent - } - - impl SigEvent { - /// **Note:** this constructor does not allow the user to set the - /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD - /// at least those flags don't do anything useful. That field is part of a - /// union that shares space with the more genuinely useful fields. - /// - /// **Note:** This constructor also doesn't allow the caller to set the - /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are - /// required for `SIGEV_THREAD`. That's considered ok because on no operating - /// system is `SIGEV_THREAD` the most efficient way to deliver AIO - /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. - /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or - /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the - /// more genuinely useful `sigev_notify_thread_id` - // Allow invalid_value warning on Fuchsia only. - // See https://github.com/nix-rust/nix/issues/1441 - #[cfg_attr(target_os = "fuchsia", allow(invalid_value))] - pub fn new(sigev_notify: SigevNotify) -> SigEvent { - let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() }; - sev.sigev_notify = match sigev_notify { - SigevNotify::SigevNone => libc::SIGEV_NONE, - SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, - #[cfg(target_os = "freebsd")] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] - SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined - }; - sev.sigev_signo = match sigev_notify { - SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ kq, ..} => kq, - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, - _ => 0 - }; - sev.sigev_value.sival_ptr = match sigev_notify { - SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(), - SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, - }; - SigEvent::set_tid(&mut sev, &sigev_notify); - SigEvent{sigevent: sev} - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { - sev.sigev_notify_thread_id = match *sigev_notify { - SigevNotify::SigevThreadId { thread_id, .. } => thread_id, - _ => 0 as type_of_thread_id - }; - } - - #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] - fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { - } - - /// Return a copy of the inner structure - pub fn sigevent(&self) -> libc::sigevent { - self.sigevent - } - - /// Returns a mutable pointer to the `sigevent` wrapped by `self` - pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { - &mut self.sigevent - } - } - - impl<'a> From<&'a libc::sigevent> for SigEvent { - fn from(sigevent: &libc::sigevent) -> Self { - SigEvent{ sigevent: *sigevent } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[cfg(not(target_os = "redox"))] - use std::thread; - - #[test] - fn test_contains() { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let all = SigSet::all(); - assert!(all.contains(SIGUSR1)); - assert!(all.contains(SIGUSR2)); - } - - #[test] - fn test_clear() { - let mut set = SigSet::all(); - set.clear(); - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - } - - #[test] - fn test_from_str_round_trips() { - for signal in Signal::iterator() { - assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal); - assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal); - } - } - - #[test] - fn test_from_str_invalid_value() { - let errval = Err(Errno::EINVAL); - assert_eq!("NOSIGNAL".parse::<Signal>(), errval); - assert_eq!("kill".parse::<Signal>(), errval); - assert_eq!("9".parse::<Signal>(), errval); - } - - #[test] - fn test_extend() { - let mut one_signal = SigSet::empty(); - one_signal.add(SIGUSR1); - - let mut two_signals = SigSet::empty(); - two_signals.add(SIGUSR2); - two_signals.extend(&one_signal); - - assert!(two_signals.contains(SIGUSR1)); - assert!(two_signals.contains(SIGUSR2)); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_set_mask() { - thread::spawn(|| { - let prev_mask = SigSet::thread_get_mask() - .expect("Failed to get existing signal mask!"); - - let mut test_mask = prev_mask; - test_mask.add(SIGUSR1); - - test_mask.thread_set_mask().expect("assertion failed"); - let new_mask = - SigSet::thread_get_mask().expect("Failed to get new mask!"); - - assert!(new_mask.contains(SIGUSR1)); - assert!(!new_mask.contains(SIGUSR2)); - - prev_mask - .thread_set_mask() - .expect("Failed to revert signal mask!"); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_block() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_block().expect("assertion failed"); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_unblock() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_unblock().expect("assertion failed"); - - assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_swap() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.thread_block().unwrap(); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - - let mut mask2 = SigSet::empty(); - mask2.add(SIGUSR2); - - let oldmask = - mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); - - assert!(oldmask.contains(SIGUSR1)); - assert!(!oldmask.contains(SIGUSR2)); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_and_into_iterator() { - let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); - let signals = sigset.into_iter().collect::<Vec<Signal>>(); - assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigaction() { - thread::spawn(|| { - extern "C" fn test_sigaction_handler(_: libc::c_int) {} - extern "C" fn test_sigaction_action( - _: libc::c_int, - _: *mut libc::siginfo_t, - _: *mut libc::c_void, - ) { - } - - let handler_sig = SigHandler::Handler(test_sigaction_handler); - - let flags = - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; - - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - let action_sig = SigAction::new(handler_sig, flags, mask); - - assert_eq!( - action_sig.flags(), - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART - ); - assert_eq!(action_sig.handler(), handler_sig); - - mask = action_sig.mask(); - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let handler_act = SigHandler::SigAction(test_sigaction_action); - let action_act = SigAction::new(handler_act, flags, mask); - assert_eq!(action_act.handler(), handler_act); - - let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); - assert_eq!(action_dfl.handler(), SigHandler::SigDfl); - - let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); - assert_eq!(action_ign.handler(), SigHandler::SigIgn); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigwait() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.add(SIGUSR2); - mask.thread_block().unwrap(); - - raise(SIGUSR1).unwrap(); - assert_eq!(mask.wait().unwrap(), SIGUSR1); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_sigset_t_unchecked() { - let src_set = SigSet::empty(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - - let src_set = SigSet::all(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(set.contains(signal)); - } - } -} diff --git a/vendor/nix/src/sys/signalfd.rs b/vendor/nix/src/sys/signalfd.rs deleted file mode 100644 index 095e59085..000000000 --- a/vendor/nix/src/sys/signalfd.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Interface for the `signalfd` syscall. -//! -//! # Signal discarding -//! When a signal can't be delivered to a process (or thread), it will become a pending signal. -//! Failure to deliver could happen if the signal is blocked by every thread in the process or if -//! the signal handler is still handling a previous signal. -//! -//! If a signal is sent to a process (or thread) that already has a pending signal of the same -//! type, it will be discarded. This means that if signals of the same type are received faster than -//! they are processed, some of those signals will be dropped. Because of this limitation, -//! `signalfd` in itself cannot be used for reliable communication between processes or threads. -//! -//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending -//! (ie. not consumed from a signalfd) it will be delivered to the signal handler. -//! -//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular -//! signal handlers. -use crate::errno::Errno; -pub use crate::sys::signal::{self, SigSet}; -use crate::unistd; -use crate::Result; -pub use libc::signalfd_siginfo as siginfo; - -use std::mem; -use std::os::unix::io::{AsRawFd, RawFd}; - -libc_bitflags! { - pub struct SfdFlags: libc::c_int { - SFD_NONBLOCK; - SFD_CLOEXEC; - } -} - -pub const SIGNALFD_NEW: RawFd = -1; -#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")] -pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); - -/// Creates a new file descriptor for reading signals. -/// -/// **Important:** please read the module level documentation about signal discarding before using -/// this function! -/// -/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor. -/// -/// A signal must be blocked on every thread in a process, otherwise it won't be visible from -/// signalfd (the default handler will be invoked instead). -/// -/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) -pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> { - unsafe { - Errno::result(libc::signalfd( - fd as libc::c_int, - mask.as_ref(), - flags.bits(), - )) - } -} - -/// A helper struct for creating, reading and closing a `signalfd` instance. -/// -/// **Important:** please read the module level documentation about signal discarding before using -/// this struct! -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::signalfd::*; -/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used -/// let mut mask = SigSet::empty(); -/// mask.add(signal::SIGUSR1); -/// mask.thread_block().unwrap(); -/// -/// // Signals are queued up on the file descriptor -/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); -/// -/// match sfd.read_signal() { -/// // we caught a signal -/// Ok(Some(sig)) => (), -/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set, -/// // otherwise the read_signal call blocks) -/// Ok(None) => (), -/// Err(err) => (), // some error happend -/// } -/// ``` -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct SignalFd(RawFd); - -impl SignalFd { - pub fn new(mask: &SigSet) -> Result<SignalFd> { - Self::with_flags(mask, SfdFlags::empty()) - } - - pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> { - let fd = signalfd(SIGNALFD_NEW, mask, flags)?; - - Ok(SignalFd(fd)) - } - - pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - signalfd(self.0, mask, SfdFlags::empty()).map(drop) - } - - pub fn read_signal(&mut self) -> Result<Option<siginfo>> { - let mut buffer = mem::MaybeUninit::<siginfo>::uninit(); - - let size = mem::size_of_val(&buffer); - let res = Errno::result(unsafe { - libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) - }) - .map(|r| r as usize); - match res { - Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), - Ok(_) => unreachable!("partial read on signalfd"), - Err(Errno::EAGAIN) => Ok(None), - Err(error) => Err(error), - } - } -} - -impl Drop for SignalFd { - fn drop(&mut self) { - let e = unistd::close(self.0); - if !std::thread::panicking() && e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; - } -} - -impl AsRawFd for SignalFd { - fn as_raw_fd(&self) -> RawFd { - self.0 - } -} - -impl Iterator for SignalFd { - type Item = siginfo; - - fn next(&mut self) -> Option<Self::Item> { - match self.read_signal() { - Ok(Some(sig)) => Some(sig), - Ok(None) | Err(_) => None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn create_signalfd() { - let mask = SigSet::empty(); - SignalFd::new(&mask).unwrap(); - } - - #[test] - fn create_signalfd_with_opts() { - let mask = SigSet::empty(); - SignalFd::with_flags( - &mask, - SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, - ) - .unwrap(); - } - - #[test] - fn read_empty_signalfd() { - let mask = SigSet::empty(); - let mut fd = - SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); - - let res = fd.read_signal(); - assert!(res.unwrap().is_none()); - } -} diff --git a/vendor/nix/src/sys/socket/addr.rs b/vendor/nix/src/sys/socket/addr.rs deleted file mode 100644 index 4e565a5b6..000000000 --- a/vendor/nix/src/sys/socket/addr.rs +++ /dev/null @@ -1,3247 +0,0 @@ -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "haiku", - target_os = "fuchsia" -))] -#[cfg(feature = "net")] -pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::vsock::VsockAddr; -use super::sa_family_t; -use crate::errno::Errno; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") -))] -use crate::sys::socket::addr::sys_control::SysControlAddr; -use crate::{NixPath, Result}; -use cfg_if::cfg_if; -use memoffset::offset_of; -use std::convert::TryInto; -use std::ffi::OsStr; -use std::hash::{Hash, Hasher}; -use std::os::unix::ffi::OsStrExt; -#[cfg(any(target_os = "ios", target_os = "macos"))] -use std::os::unix::io::RawFd; -use std::path::Path; -use std::{fmt, mem, net, ptr, slice}; - -/// Convert a std::net::Ipv4Addr into the libc form. -#[cfg(feature = "net")] -pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { - static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); - // Safe because both types have the same memory layout, and no fancy Drop - // impls. - unsafe { - mem::transmute(addr) - } -} - -/// Convert a std::net::Ipv6Addr into the libc form. -#[cfg(feature = "net")] -pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { - static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); - // Safe because both are Newtype wrappers around the same libc type - unsafe { - mem::transmute(*addr) - } -} - -/// These constants specify the protocol family to be used -/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) -/// -/// # References -/// -/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) -// Should this be u8? -#[repr(i32)] -#[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub enum AddressFamily { - /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) - Unix = libc::AF_UNIX, - /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) - Inet = libc::AF_INET, - /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) - Inet6 = libc::AF_INET6, - /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Netlink = libc::AF_NETLINK, - /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "illumos", - target_os = "fuchsia", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Packet = libc::AF_PACKET, - /// KEXT Controls and Notifications - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - System = libc::AF_SYSTEM, - /// Amateur radio AX.25 protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ax25 = libc::AF_AX25, - /// IPX - Novell protocols - Ipx = libc::AF_IPX, - /// AppleTalk - AppleTalk = libc::AF_APPLETALK, - /// AX.25 packet layer protocol. - /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetRom = libc::AF_NETROM, - /// Can't be used for creating sockets; mostly used for bridge - /// links in - /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) - /// protocol commands. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Bridge = libc::AF_BRIDGE, - /// Access to raw ATM PVCs - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AtmPvc = libc::AF_ATMPVC, - /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - X25 = libc::AF_X25, - /// RATS (Radio Amateur Telecommunications Society) Open - /// Systems environment (ROSE) AX.25 packet layer protocol. - /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Rose = libc::AF_ROSE, - /// DECet protocol sockets. - #[cfg(not(target_os = "haiku"))] - Decnet = libc::AF_DECnet, - /// Reserved for "802.2LLC project"; never used. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetBeui = libc::AF_NETBEUI, - /// This was a short-lived (between Linux 2.1.30 and - /// 2.1.99pre2) protocol family for firewall upcalls. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Security = libc::AF_SECURITY, - /// Key management protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Key = libc::AF_KEY, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ash = libc::AF_ASH, - /// Acorn Econet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Econet = libc::AF_ECONET, - /// Access to ATM Switched Virtual Circuits - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AtmSvc = libc::AF_ATMSVC, - /// Reliable Datagram Sockets (RDS) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Rds = libc::AF_RDS, - /// IBM SNA - #[cfg(not(target_os = "haiku"))] - Sna = libc::AF_SNA, - /// Socket interface over IrDA - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Irda = libc::AF_IRDA, - /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Pppox = libc::AF_PPPOX, - /// Legacy protocol for wide area network (WAN) connectivity that was used - /// by Sangoma WAN cards - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Wanpipe = libc::AF_WANPIPE, - /// Logical link control (IEEE 802.2 LLC) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Llc = libc::AF_LLC, - /// InfiniBand native addressing - #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ib = libc::AF_IB, - /// Multiprotocol Label Switching - #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Mpls = libc::AF_MPLS, - /// Controller Area Network automotive bus protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Can = libc::AF_CAN, - /// TIPC, "cluster domain sockets" protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Tipc = libc::AF_TIPC, - /// Bluetooth low-level socket protocol - #[cfg(not(any( - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Bluetooth = libc::AF_BLUETOOTH, - /// IUCV (inter-user communication vehicle) z/VM protocol for - /// hypervisor-guest interaction - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Iucv = libc::AF_IUCV, - /// Rx, Andrew File System remote procedure call protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxRpc = libc::AF_RXRPC, - /// New "modular ISDN" driver interface protocol - #[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Isdn = libc::AF_ISDN, - /// Nokia cellular modem IPC/RPC interface - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Phonet = libc::AF_PHONET, - /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ieee802154 = libc::AF_IEEE802154, - /// Ericsson's Communication CPU to Application CPU interface (CAIF) - /// protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Caif = libc::AF_CAIF, - /// Interface to kernel crypto API - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Alg = libc::AF_ALG, - /// Near field communication - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - Nfc = libc::AF_NFC, - /// VMWare VSockets protocol for hypervisor-guest interaction. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Vsock = libc::AF_VSOCK, - /// ARPANet IMP addresses - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ImpLink = libc::AF_IMPLINK, - /// PUP protocols, e.g. BSP - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Pup = libc::AF_PUP, - /// MIT CHAOS protocols - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Chaos = libc::AF_CHAOS, - /// Novell and Xerox protocol - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ns = libc::AF_NS, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Iso = libc::AF_ISO, - /// Bell Labs virtual circuit switch ? - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Datakit = libc::AF_DATAKIT, - /// CCITT protocols, X.25 etc - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ccitt = libc::AF_CCITT, - /// DEC Direct data link interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Dli = libc::AF_DLI, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Lat = libc::AF_LAT, - /// NSC Hyperchannel - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Hylink = libc::AF_HYLINK, - /// Link layer interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Link = libc::AF_LINK, - /// connection-oriented IP, aka ST II - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Coip = libc::AF_COIP, - /// Computer Network Technology - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Cnt = libc::AF_CNT, - /// Native ATM access - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Natm = libc::AF_NATM, - /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Unspec = libc::AF_UNSPEC, -} - -impl AddressFamily { - /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from - /// the `sa_family` field of a `sockaddr`. - /// - /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet - /// and System. Returns None for unsupported or unknown address families. - pub const fn from_i32(family: i32) -> Option<AddressFamily> { - match family { - libc::AF_UNIX => Some(AddressFamily::Unix), - libc::AF_INET => Some(AddressFamily::Inet), - libc::AF_INET6 => Some(AddressFamily::Inet6), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => Some(AddressFamily::Netlink), - #[cfg(any(target_os = "macos", target_os = "macos"))] - libc::AF_SYSTEM => Some(AddressFamily::System), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_PACKET => Some(AddressFamily::Packet), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => Some(AddressFamily::Vsock), - _ => None, - } - } -} - -feature! { -#![feature = "net"] - -#[deprecated( - since = "0.24.0", - note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum InetAddr { - V4(libc::sockaddr_in), - V6(libc::sockaddr_in6), -} - -#[allow(missing_docs)] // It's deprecated anyway -#[allow(deprecated)] -impl InetAddr { - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn from_std(std: &net::SocketAddr) -> InetAddr { - match *std { - net::SocketAddr::V4(ref addr) => { - InetAddr::V4(libc::sockaddr_in { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin_len: mem::size_of::<libc::sockaddr_in>() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order - sin_addr: Ipv4Addr::from_std(addr.ip()).0, - .. unsafe { mem::zeroed() } - }) - } - net::SocketAddr::V6(ref addr) => { - InetAddr::V6(libc::sockaddr_in6 { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order - sin6_addr: Ipv6Addr::from_std(addr.ip()).0, - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - .. unsafe { mem::zeroed() } - }) - } - } - } - - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn new(ip: IpAddr, port: u16) -> InetAddr { - match ip { - IpAddr::V4(ref ip) => { - InetAddr::V4(libc::sockaddr_in { - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: port.to_be(), - sin_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - IpAddr::V6(ref ip) => { - InetAddr::V6(libc::sockaddr_in6 { - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: port.to_be(), - sin6_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - } - } - /// Gets the IP address associated with this socket address. - pub const fn ip(&self) -> IpAddr { - match *self { - InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), - InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), - } - } - - /// Gets the port number associated with this socket address - pub const fn port(&self) -> u16 { - match *self { - InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), - InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), - } - } - - pub fn to_std(&self) -> net::SocketAddr { - match *self { - InetAddr::V4(ref sa) => net::SocketAddr::V4( - net::SocketAddrV4::new( - Ipv4Addr(sa.sin_addr).to_std(), - self.port())), - InetAddr::V6(ref sa) => net::SocketAddr::V6( - net::SocketAddrV6::new( - Ipv6Addr(sa.sin6_addr).to_std(), - self.port(), - sa.sin6_flowinfo, - sa.sin6_scope_id)), - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } -} - -#[allow(deprecated)] -impl fmt::Display for InetAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), - InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), - } - } -} - -/* - * - * ===== IpAddr ===== - * - */ -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "Use std::net::IpAddr instead" -)] -pub enum IpAddr { - V4(Ipv4Addr), - V6(Ipv6Addr), -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl IpAddr { - /// Create a new IpAddr that contains an IPv4 address. - /// - /// The result will represent the IP address a.b.c.d - pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { - IpAddr::V4(Ipv4Addr::new(a, b, c, d)) - } - - /// Create a new IpAddr that contains an IPv6 address. - /// - /// The result will represent the IP address a:b:c:d:e:f - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) - } - - pub fn from_std(std: &net::IpAddr) -> IpAddr { - match *std { - net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)), - net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)), - } - } - - pub const fn to_std(&self) -> net::IpAddr { - match *self { - IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), - IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for IpAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpAddr::V4(ref v4) => v4.fmt(f), - IpAddr::V6(ref v6) => v6.fmt(f) - } - } -} - -/* - * - * ===== Ipv4Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv4Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv4Addr(pub libc::in_addr); - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv4Addr { - #[allow(clippy::identity_op)] // More readable this way - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - let ip = (((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - ((d as u32) << 0)).to_be(); - - Ipv4Addr(libc::in_addr { s_addr: ip }) - } - - // Use pass by reference for symmetry with Ipv6Addr::from_std - #[allow(clippy::trivially_copy_pass_by_ref)] - pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr { - let bits = std.octets(); - Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } - - pub const fn any() -> Ipv4Addr { - Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) - } - - pub const fn octets(self) -> [u8; 4] { - let bits = u32::from_be(self.0.s_addr); - [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] - } - - pub const fn to_std(self) -> net::Ipv4Addr { - let bits = self.octets(); - net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let octets = self.octets(); - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) - } -} - -/* - * - * ===== Ipv6Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv6Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv6Addr(pub libc::in6_addr); - -// Note that IPv6 addresses are stored in big endian order on all architectures. -// See https://tools.ietf.org/html/rfc1700 or consult your favorite search -// engine. - -macro_rules! to_u8_array { - ($($num:ident),*) => { - [ $(($num>>8) as u8, ($num&0xff) as u8,)* ] - } -} - -macro_rules! to_u16_array { - ($slf:ident, $($first:expr, $second:expr),*) => { - [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*] - } -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv6Addr { - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { - Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) - } - - pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr { - let s = std.segments(); - Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } - - /// Return the eight 16-bit segments that make up this address - pub const fn segments(&self) -> [u16; 8] { - to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) - } - - pub const fn to_std(&self) -> net::Ipv6Addr { - let s = self.segments(); - net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.to_std().fmt(fmt) - } -} -} - -/// A wrapper around `sockaddr_un`. -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct UnixAddr { - // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts - sun: libc::sockaddr_un, - /// The length of the valid part of `sun`, including the sun_family field - /// but excluding any trailing nul. - // On the BSDs, this field is built into sun - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - sun_len: u8, -} - -// linux man page unix(7) says there are 3 kinds of unix socket: -// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 -// unnamed: addrlen = sizeof(sa_family_t) -// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] -// -// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) -#[derive(PartialEq, Eq, Hash)] -enum UnixAddrKind<'a> { - Pathname(&'a Path), - Unnamed, - #[cfg(any(target_os = "android", target_os = "linux"))] - Abstract(&'a [u8]), -} -impl<'a> UnixAddrKind<'a> { - /// Safety: sun & sun_len must be valid - unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { - assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); - let path_len = - sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); - if path_len == 0 { - return Self::Unnamed; - } - #[cfg(any(target_os = "android", target_os = "linux"))] - if sun.sun_path[0] == 0 { - let name = slice::from_raw_parts( - sun.sun_path.as_ptr().add(1) as *const u8, - path_len - 1, - ); - return Self::Abstract(name); - } - let pathname = - slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); - if pathname.last() == Some(&0) { - // A trailing NUL is not considered part of the path, and it does - // not need to be included in the addrlen passed to functions like - // bind(). However, Linux adds a trailing NUL, even if one was not - // originally present, when returning addrs from functions like - // getsockname() (the BSDs do not do that). So we need to filter - // out any trailing NUL here, so sockaddrs can round-trip through - // the kernel and still compare equal. - Self::Pathname(Path::new(OsStr::from_bytes( - &pathname[0..pathname.len() - 1], - ))) - } else { - Self::Pathname(Path::new(OsStr::from_bytes(pathname))) - } - } -} - -impl UnixAddr { - /// Create a new sockaddr_un representing a filesystem path. - pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { - path.with_nix_path(|cstr| unsafe { - let mut ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - ..mem::zeroed() - }; - - let bytes = cstr.to_bytes(); - - if bytes.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); - } - - let sun_len = (bytes.len() - + offset_of!(libc::sockaddr_un, sun_path)) - .try_into() - .unwrap(); - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - { - ret.sun_len = sun_len; - } - ptr::copy_nonoverlapping( - bytes.as_ptr(), - ret.sun_path.as_mut_ptr() as *mut u8, - bytes.len(), - ); - - Ok(UnixAddr::from_raw_parts(ret, sun_len)) - })? - } - - /// Create a new `sockaddr_un` representing an address in the "abstract namespace". - /// - /// The leading nul byte for the abstract namespace is automatically added; - /// thus the input `path` is expected to be the bare name, not NUL-prefixed. - /// This is a Linux-specific extension, primarily used to allow chrooted - /// processes to communicate with processes having a different filesystem view. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { - unsafe { - let mut ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - ..mem::zeroed() - }; - - if path.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); - } - let sun_len = - (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) - .try_into() - .unwrap(); - - // Abstract addresses are represented by sun_path[0] == - // b'\0', so copy starting one byte in. - ptr::copy_nonoverlapping( - path.as_ptr(), - ret.sun_path.as_mut_ptr().offset(1) as *mut u8, - path.len(), - ); - - Ok(UnixAddr::from_raw_parts(ret, sun_len)) - } - } - - /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_unnamed() -> UnixAddr { - let ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - .. unsafe { mem::zeroed() } - }; - - let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); - - unsafe { UnixAddr::from_raw_parts(ret, sun_len) } - } - - /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` - /// is the size of the valid portion of the struct, excluding any trailing - /// NUL. - /// - /// # Safety - /// This pair of sockaddr_un & sun_len must be a valid unix addr, which - /// means: - /// - sun_len >= offset_of(sockaddr_un, sun_path) - /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) - /// - if this is a unix addr with a pathname, sun.sun_path is a - /// fs path, not necessarily nul-terminated. - pub(crate) unsafe fn from_raw_parts( - sun: libc::sockaddr_un, - sun_len: u8, - ) -> UnixAddr { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - UnixAddr { sun, sun_len } - } else { - assert_eq!(sun_len, sun.sun_len); - UnixAddr {sun} - } - } - } - - fn kind(&self) -> UnixAddrKind<'_> { - // SAFETY: our sockaddr is always valid because of the invariant on the struct - unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } - } - - /// If this address represents a filesystem path, return that path. - pub fn path(&self) -> Option<&Path> { - match self.kind() { - UnixAddrKind::Pathname(path) => Some(path), - _ => None, - } - } - - /// If this address represents an abstract socket, return its name. - /// - /// For abstract sockets only the bare name is returned, without the - /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn as_abstract(&self) -> Option<&[u8]> { - match self.kind() { - UnixAddrKind::Abstract(name) => Some(name), - _ => None, - } - } - - /// Check if this address is an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[inline] - pub fn is_unnamed(&self) -> bool { - matches!(self.kind(), UnixAddrKind::Unnamed) - } - - /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` - #[inline] - pub fn path_len(&self) -> usize { - self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) - } - /// Returns a pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_ptr(&self) -> *const libc::sockaddr_un { - &self.sun - } - /// Returns a mutable pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { - &mut self.sun - } - - fn sun_len(&self) -> u8 { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - self.sun_len - } else { - self.sun.sun_len - } - } - } -} - -impl private::SockaddrLikePriv for UnixAddr {} -impl SockaddrLike for UnixAddr { - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - fn len(&self) -> libc::socklen_t { - self.sun_len.into() - } - - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) - || l > u8::MAX as libc::socklen_t - { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_UNIX { - return None; - } - let mut su: libc::sockaddr_un = mem::zeroed(); - let sup = &mut su as *mut libc::sockaddr_un as *mut u8; - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] { - let su_len = len.unwrap_or( - mem::size_of::<libc::sockaddr_un>() as libc::socklen_t - ); - } else { - let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); - } - }; - ptr::copy(addr as *const u8, sup, su_len as usize); - Some(Self::from_raw_parts(su, su_len as u8)) - } - - fn size() -> libc::socklen_t - where - Self: Sized, - { - mem::size_of::<libc::sockaddr_un>() as libc::socklen_t - } -} - -impl AsRef<libc::sockaddr_un> for UnixAddr { - fn as_ref(&self) -> &libc::sockaddr_un { - &self.sun - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - use fmt::Write; - f.write_str("@\"")?; - for &b in abs { - use fmt::Display; - char::from(b).escape_default().fmt(f)?; - } - f.write_char('"')?; - Ok(()) -} - -impl fmt::Display for UnixAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.kind() { - UnixAddrKind::Pathname(path) => path.display().fmt(f), - UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"), - #[cfg(any(target_os = "android", target_os = "linux"))] - UnixAddrKind::Abstract(name) => fmt_abstract(name, f), - } - } -} - -impl PartialEq for UnixAddr { - fn eq(&self, other: &UnixAddr) -> bool { - self.kind() == other.kind() - } -} - -impl Eq for UnixAddr {} - -impl Hash for UnixAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - self.kind().hash(s) - } -} - -/// Anything that, in C, can be cast back and forth to `sockaddr`. -/// -/// Most implementors also implement `AsRef<libc::XXX>` to access their -/// inner type read-only. -#[allow(clippy::len_without_is_empty)] -pub trait SockaddrLike: private::SockaddrLikePriv { - /// Returns a raw pointer to the inner structure. Useful for FFI. - fn as_ptr(&self) -> *const libc::sockaddr { - self as *const Self as *const libc::sockaddr - } - - /// Unsafe constructor from a variable length source - /// - /// Some C APIs from provide `len`, and others do not. If it's provided it - /// will be validated. If not, it will be guessed based on the family. - /// - /// # Arguments - /// - /// - `addr`: raw pointer to something that can be cast to a - /// `libc::sockaddr`. For example, `libc::sockaddr_in`, - /// `libc::sockaddr_in6`, etc. - /// - `len`: For fixed-width types like `sockaddr_in`, it will be - /// validated if present and ignored if not. For variable-width - /// types it is required and must be the total length of valid - /// data. For example, if `addr` points to a - /// named `sockaddr_un`, then `len` must be the length of the - /// structure up to but not including the trailing NUL. - /// - /// # Safety - /// - /// `addr` must be valid for the specific type of sockaddr. `len`, if - /// present, must not exceed the length of valid data in `addr`. - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized; - - /// Return the address family of this socket - /// - /// # Examples - /// One common use is to match on the family of a union type, like this: - /// ``` - /// # use nix::sys::socket::*; - /// let fd = socket(AddressFamily::Inet, SockType::Stream, - /// SockFlag::empty(), None).unwrap(); - /// let ss: SockaddrStorage = getsockname(fd).unwrap(); - /// match ss.family().unwrap() { - /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), - /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), - /// _ => println!("Unexpected address family") - /// } - /// ``` - fn family(&self) -> Option<AddressFamily> { - // Safe since all implementors have a sa_family field at the same - // address, and they're all repr(C) - AddressFamily::from_i32(unsafe { - (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 - }) - } - - cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { - /// Return the length of valid data in the sockaddr structure. - /// - /// For fixed-size sockaddrs, this should be the size of the - /// structure. But for variable-sized types like [`UnixAddr`] it - /// may be less. - fn len(&self) -> libc::socklen_t { - // Safe since all implementors have a sa_len field at the same - // address, and they're all repr(transparent). - // Robust for all implementors. - unsafe { - (*(self as *const Self as *const libc::sockaddr)).sa_len - }.into() - } - } else { - /// Return the length of valid data in the sockaddr structure. - /// - /// For fixed-size sockaddrs, this should be the size of the - /// structure. But for variable-sized types like [`UnixAddr`] it - /// may be less. - fn len(&self) -> libc::socklen_t { - // No robust default implementation is possible without an - // sa_len field. Implementors with a variable size must - // override this method. - mem::size_of_val(self) as libc::socklen_t - } - } - } - - /// Return the available space in the structure - fn size() -> libc::socklen_t - where - Self: Sized, - { - mem::size_of::<Self>() as libc::socklen_t - } -} - -impl private::SockaddrLikePriv for () { - fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { - ptr::null_mut() - } -} - -/// `()` can be used in place of a real Sockaddr when no address is expected, -/// for example for a field of `Option<S> where S: SockaddrLike`. -// If this RFC ever stabilizes, then ! will be a better choice. -// https://github.com/rust-lang/rust/issues/35121 -impl SockaddrLike for () { - fn as_ptr(&self) -> *const libc::sockaddr { - ptr::null() - } - - unsafe fn from_raw( - _: *const libc::sockaddr, - _: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - None - } - - fn family(&self) -> Option<AddressFamily> { - None - } - - fn len(&self) -> libc::socklen_t { - 0 - } -} - -/// An IPv4 socket address -// This is identical to net::SocketAddrV4. But the standard library -// doesn't allow direct access to the libc fields, which we need. So we -// reimplement it here. -#[cfg(feature = "net")] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SockaddrIn(libc::sockaddr_in); - -#[cfg(feature = "net")] -impl SockaddrIn { - /// Returns the IP address associated with this socket address, in native - /// endian. - pub const fn ip(&self) -> libc::in_addr_t { - u32::from_be(self.0.sin_addr.s_addr) - } - - /// Creates a new socket address from IPv4 octets and a port number. - pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { - Self(libc::sockaddr_in { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" - ))] - sin_len: Self::size() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: u16::to_be(port), - sin_addr: libc::in_addr { - s_addr: u32::from_ne_bytes([a, b, c, d]), - }, - sin_zero: unsafe { mem::zeroed() }, - }) - } - - /// Returns the port number associated with this socket address, in native - /// endian. - pub const fn port(&self) -> u16 { - u16::from_be(self.0.sin_port) - } -} - -#[cfg(feature = "net")] -impl private::SockaddrLikePriv for SockaddrIn {} -#[cfg(feature = "net")] -impl SockaddrLike for SockaddrIn { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_INET { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } -} - -#[cfg(feature = "net")] -impl AsRef<libc::sockaddr_in> for SockaddrIn { - fn as_ref(&self) -> &libc::sockaddr_in { - &self.0 - } -} - -#[cfg(feature = "net")] -impl fmt::Display for SockaddrIn { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ne = u32::from_be(self.0.sin_addr.s_addr); - let port = u16::from_be(self.0.sin_port); - write!( - f, - "{}.{}.{}.{}:{}", - ne >> 24, - (ne >> 16) & 0xFF, - (ne >> 8) & 0xFF, - ne & 0xFF, - port - ) - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV4> for SockaddrIn { - fn from(addr: net::SocketAddrV4) -> Self { - Self(libc::sockaddr_in { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "haiku", - target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - sin_len: mem::size_of::<libc::sockaddr_in>() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order - sin_addr: ipv4addr_to_libc(*addr.ip()), - ..unsafe { mem::zeroed() } - }) - } -} - -#[cfg(feature = "net")] -impl From<SockaddrIn> for net::SocketAddrV4 { - fn from(addr: SockaddrIn) -> Self { - net::SocketAddrV4::new( - net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), - u16::from_be(addr.0.sin_port), - ) - } -} - -#[cfg(feature = "net")] -impl std::str::FromStr for SockaddrIn { - type Err = net::AddrParseError; - - fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { - net::SocketAddrV4::from_str(s).map(SockaddrIn::from) - } -} - -/// An IPv6 socket address -#[cfg(feature = "net")] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SockaddrIn6(libc::sockaddr_in6); - -#[cfg(feature = "net")] -impl SockaddrIn6 { - /// Returns the flow information associated with this address. - pub const fn flowinfo(&self) -> u32 { - self.0.sin6_flowinfo - } - - /// Returns the IP address associated with this socket address. - pub fn ip(&self) -> net::Ipv6Addr { - net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) - } - - /// Returns the port number associated with this socket address, in native - /// endian. - pub const fn port(&self) -> u16 { - u16::from_be(self.0.sin6_port) - } - - /// Returns the scope ID associated with this address. - pub const fn scope_id(&self) -> u32 { - self.0.sin6_scope_id - } -} - -#[cfg(feature = "net")] -impl private::SockaddrLikePriv for SockaddrIn6 {} -#[cfg(feature = "net")] -impl SockaddrLike for SockaddrIn6 { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_INET6 { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } -} - -#[cfg(feature = "net")] -impl AsRef<libc::sockaddr_in6> for SockaddrIn6 { - fn as_ref(&self) -> &libc::sockaddr_in6 { - &self.0 - } -} - -#[cfg(feature = "net")] -impl fmt::Display for SockaddrIn6 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // These things are really hard to display properly. Easier to let std - // do it. - let std = net::SocketAddrV6::new( - self.ip(), - self.port(), - self.flowinfo(), - self.scope_id(), - ); - std.fmt(f) - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV6> for SockaddrIn6 { - fn from(addr: net::SocketAddrV6) -> Self { - #[allow(clippy::needless_update)] // It isn't needless on Illumos - Self(libc::sockaddr_in6 { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "haiku", - target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order - sin6_addr: ipv6addr_to_libc(addr.ip()), - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - ..unsafe { mem::zeroed() } - }) - } -} - -#[cfg(feature = "net")] -impl From<SockaddrIn6> for net::SocketAddrV6 { - fn from(addr: SockaddrIn6) -> Self { - net::SocketAddrV6::new( - net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), - u16::from_be(addr.0.sin6_port), - addr.0.sin6_flowinfo, - addr.0.sin6_scope_id, - ) - } -} - -#[cfg(feature = "net")] -impl std::str::FromStr for SockaddrIn6 { - type Err = net::AddrParseError; - - fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { - net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) - } -} - -/// A container for any sockaddr type -/// -/// Just like C's `sockaddr_storage`, this type is large enough to hold any type -/// of sockaddr. It can be used as an argument with functions like -/// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is -/// a union, it can be safely accessed through the `as_*` methods. -/// -/// # Example -/// ``` -/// # use nix::sys::socket::*; -/// # use std::str::FromStr; -/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); -/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), -/// None).unwrap(); -/// bind(fd, &localhost).expect("bind"); -/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); -/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); -/// ``` -#[derive(Clone, Copy, Eq)] -#[repr(C)] -pub union SockaddrStorage { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - alg: AlgAddr, - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - dl: LinkAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] - nl: NetlinkAddr, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - sctl: SysControlAddr, - #[cfg(feature = "net")] - sin: SockaddrIn, - #[cfg(feature = "net")] - sin6: SockaddrIn6, - ss: libc::sockaddr_storage, - su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - vsock: VsockAddr, -} -impl private::SockaddrLikePriv for SockaddrStorage {} -impl SockaddrLike for SockaddrStorage { - unsafe fn from_raw( - addr: *const libc::sockaddr, - l: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if addr.is_null() { - return None; - } - if let Some(len) = l { - let ulen = len as usize; - if ulen < offset_of!(libc::sockaddr, sa_data) - || ulen > mem::size_of::<libc::sockaddr_storage>() - { - None - } else { - let mut ss: libc::sockaddr_storage = mem::zeroed(); - let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; - ptr::copy(addr as *const u8, ssp, len as usize); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - if i32::from(ss.ss_family) == libc::AF_UNIX { - // Safe because we UnixAddr is strictly smaller than - // SockaddrStorage, and we just initialized the structure. - (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8; - } - Some(Self { ss }) - } - } else { - // If length is not available and addr is of a fixed-length type, - // copy it. If addr is of a variable length type and len is not - // available, then there's nothing we can do. - match (*addr).sa_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { - AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) - } - #[cfg(feature = "net")] - libc::AF_INET => { - SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) - } - #[cfg(feature = "net")] - libc::AF_INET6 => { - SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) - } - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => { - LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { - NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) - } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => { - LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - libc::AF_SYSTEM => { - SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => { - VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) - } - _ => None, - } - } - } - - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - fn len(&self) -> libc::socklen_t { - match self.as_unix_addr() { - // The UnixAddr type knows its own length - Some(ua) => ua.len(), - // For all else, we're just a boring SockaddrStorage - None => mem::size_of_val(self) as libc::socklen_t - } - } -} - -macro_rules! accessors { - ( - $fname:ident, - $fname_mut:ident, - $sockty:ty, - $family:expr, - $libc_ty:ty, - $field:ident) => { - /// Safely and falliably downcast to an immutable reference - pub fn $fname(&self) -> Option<&$sockty> { - if self.family() == Some($family) - && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t - { - // Safe because family and len are validated - Some(unsafe { &self.$field }) - } else { - None - } - } - - /// Safely and falliably downcast to a mutable reference - pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { - if self.family() == Some($family) - && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t - { - // Safe because family and len are validated - Some(unsafe { &mut self.$field }) - } else { - None - } - } - }; -} - -impl SockaddrStorage { - /// Downcast to an immutable `[UnixAddr]` reference. - pub fn as_unix_addr(&self) -> Option<&UnixAddr> { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; - // Safe because UnixAddr is strictly smaller than - // sockaddr_storage, and we're fully initialized - let len = unsafe { - (*(p as *const UnixAddr )).sun_len as usize - }; - } else { - let len = self.len() as usize; - } - } - // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::<libc::sockaddr_un>() { - None - } else { - Some(unsafe{&self.su}) - } - } - - /// Downcast to a mutable `[UnixAddr]` reference. - pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; - // Safe because UnixAddr is strictly smaller than - // sockaddr_storage, and we're fully initialized - let len = unsafe { - (*(p as *const UnixAddr )).sun_len as usize - }; - } else { - let len = self.len() as usize; - } - } - // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::<libc::sockaddr_un>() { - None - } else { - Some(unsafe{&mut self.su}) - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, - AddressFamily::Alg, libc::sockaddr_alg, alg} - - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - accessors! { - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Packet, libc::sockaddr_ll, dl} - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - accessors! { - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Link, libc::sockaddr_dl, dl} - - #[cfg(feature = "net")] - accessors! { - as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, - AddressFamily::Inet, libc::sockaddr_in, sin} - - #[cfg(feature = "net")] - accessors! { - as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, - AddressFamily::Inet6, libc::sockaddr_in6, sin6} - - #[cfg(any(target_os = "android", target_os = "linux"))] - accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, - AddressFamily::Netlink, libc::sockaddr_nl, nl} - - #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, - AddressFamily::System, libc::sockaddr_ctl, sctl} - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, - AddressFamily::Vsock, libc::sockaddr_vm, vsock} -} - -impl fmt::Debug for SockaddrStorage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SockaddrStorage") - // Safe because sockaddr_storage has the least specific - // field types - .field("ss", unsafe { &self.ss }) - .finish() - } -} - -impl fmt::Display for SockaddrStorage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => self.alg.fmt(f), - #[cfg(feature = "net")] - libc::AF_INET => self.sin.fmt(f), - #[cfg(feature = "net")] - libc::AF_INET6 => self.sin6.fmt(f), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => self.dl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => self.nl.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => self.dl.fmt(f), - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - libc::AF_SYSTEM => self.sctl.fmt(f), - libc::AF_UNIX => self.su.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => self.vsock.fmt(f), - _ => "<Address family unspecified>".fmt(f), - } - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV4> for SockaddrStorage { - fn from(s: net::SocketAddrV4) -> Self { - unsafe { - let mut ss: Self = mem::zeroed(); - ss.sin = SockaddrIn::from(s); - ss - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV6> for SockaddrStorage { - fn from(s: net::SocketAddrV6) -> Self { - unsafe { - let mut ss: Self = mem::zeroed(); - ss.sin6 = SockaddrIn6::from(s); - ss - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddr> for SockaddrStorage { - fn from(s: net::SocketAddr) -> Self { - match s { - net::SocketAddr::V4(sa4) => Self::from(sa4), - net::SocketAddr::V6(sa6) => Self::from(sa6), - } - } -} - -impl Hash for SockaddrStorage { - fn hash<H: Hasher>(&self, s: &mut H) { - unsafe { - match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => self.alg.hash(s), - #[cfg(feature = "net")] - libc::AF_INET => self.sin.hash(s), - #[cfg(feature = "net")] - libc::AF_INET6 => self.sin6.hash(s), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => self.dl.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => self.nl.hash(s), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => self.dl.hash(s), - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - libc::AF_SYSTEM => self.sctl.hash(s), - libc::AF_UNIX => self.su.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => self.vsock.hash(s), - _ => self.ss.hash(s), - } - } - } -} - -impl PartialEq for SockaddrStorage { - fn eq(&self, other: &Self) -> bool { - unsafe { - match (self.ss.ss_family as i32, other.ss.ss_family as i32) { - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, - #[cfg(feature = "net")] - (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, - #[cfg(feature = "net")] - (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, - (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, - _ => false, - } - } - } -} - -mod private { - pub trait SockaddrLikePriv { - /// Returns a mutable raw pointer to the inner structure. - /// - /// # Safety - /// - /// This method is technically safe, but modifying the inner structure's - /// `family` or `len` fields may result in violating Nix's invariants. - /// It is best to use this method only with foreign functions that do - /// not change the sockaddr type. - fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { - self as *mut Self as *mut libc::sockaddr - } - } -} - -/// Represents a socket address -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[non_exhaustive] -pub enum SockAddr { - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Inet(InetAddr), - Unix(UnixAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Netlink(NetlinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Alg(AlgAddr), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - SysControl(SysControlAddr), - /// Datalink address (MAC) - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Link(LinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Vsock(VsockAddr), -} - -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -impl SockAddr { - feature! { - #![feature = "net"] - pub fn new_inet(addr: InetAddr) -> SockAddr { - SockAddr::Inet(addr) - } - } - - pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> { - Ok(SockAddr::Unix(UnixAddr::new(path)?)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { - SockAddr::Netlink(NetlinkAddr::new(pid, groups)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { - SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) - } - - feature! { - #![feature = "ioctl"] - #[cfg(any(target_os = "ios", target_os = "macos"))] - pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> { - SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_vsock(cid: u32, port: u32) -> SockAddr { - SockAddr::Vsock(VsockAddr::new(cid, port)) - } - - pub fn family(&self) -> AddressFamily { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, - SockAddr::Unix(..) => AddressFamily::Unix, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(..) => AddressFamily::Netlink, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(..) => AddressFamily::Alg, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(..) => AddressFamily::System, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Packet, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Link, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(..) => AddressFamily::Vsock, - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } - - /// Creates a `SockAddr` struct from libc's sockaddr. - /// - /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. - /// Returns None for unsupported families. - /// - /// # Safety - /// - /// unsafe because it takes a raw pointer as argument. The caller must - /// ensure that the pointer is valid. - #[cfg(not(target_os = "fuchsia"))] - #[cfg(feature = "net")] - pub(crate) unsafe fn from_libc_sockaddr( - addr: *const libc::sockaddr, - ) -> Option<SockAddr> { - if addr.is_null() { - None - } else { - match AddressFamily::from_i32(i32::from((*addr).sa_family)) { - Some(AddressFamily::Unix) => None, - #[cfg(feature = "net")] - Some(AddressFamily::Inet) => Some(SockAddr::Inet( - InetAddr::V4(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(feature = "net")] - Some(AddressFamily::Inet6) => Some(SockAddr::Inet( - InetAddr::V6(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( - NetlinkAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - Some(AddressFamily::System) => Some(SockAddr::SysControl( - SysControlAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr( - ptr::read_unaligned(addr as *const _), - ))), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - Some(AddressFamily::Link) => { - let ether_addr = - LinkAddr(ptr::read_unaligned(addr as *const _)); - if ether_addr.is_empty() { - None - } else { - Some(SockAddr::Link(ether_addr)) - } - } - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr( - ptr::read_unaligned(addr as *const _), - ))), - // Other address families are currently not supported and simply yield a None - // entry instead of a proper conversion to a `SockAddr`. - Some(_) | None => None, - } - } - } - - /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. - /// - /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. - /// Returns a reference to the underlying data type (as a sockaddr reference) along - /// with the size of the actual data type. sockaddr is commonly used as a proxy for - /// a superclass as C doesn't support inheritance, so many functions that take - /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. - pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in6 - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - SockAddr::Unix(ref unix_addr) => ( - // This cast is always allowed in C - unsafe { - &*(&unix_addr.sun as *const libc::sockaddr_un - as *const libc::sockaddr) - }, - unix_addr.sun_len() as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(NetlinkAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(AlgAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(SysControlAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_ll - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_dl - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(VsockAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for SockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(ref inet) => inet.fmt(f), - SockAddr::Unix(ref unix) => unix.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(ref nl) => nl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(ref nl) => nl.fmt(f), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(ref sc) => sc.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(ref svm) => svm.fmt(f), - } - } -} - -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl private::SockaddrLikePriv for SockAddr {} -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl SockaddrLike for SockAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - _len: Option<libc::socklen_t>, - ) -> Option<Self> { - Self::from_libc_sockaddr(addr) - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod netlink { - use super::*; - use crate::sys::socket::addr::AddressFamily; - use libc::{sa_family_t, sockaddr_nl}; - use std::{fmt, mem}; - - /// Address for the Linux kernel user interface device. - /// - /// # References - /// - /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) - #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); - - impl NetlinkAddr { - /// Construct a new socket address from its port ID and multicast groups - /// mask. - pub fn new(pid: u32, groups: u32) -> NetlinkAddr { - let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; - addr.nl_family = AddressFamily::Netlink as sa_family_t; - addr.nl_pid = pid; - addr.nl_groups = groups; - - NetlinkAddr(addr) - } - - /// Return the socket's port ID. - pub const fn pid(&self) -> u32 { - self.0.nl_pid - } - - /// Return the socket's multicast groups mask - pub const fn groups(&self) -> u32 { - self.0.nl_groups - } - } - - impl private::SockaddrLikePriv for NetlinkAddr {} - impl SockaddrLike for NetlinkAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_NETLINK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_nl> for NetlinkAddr { - fn as_ref(&self) -> &libc::sockaddr_nl { - &self.0 - } - } - - impl fmt::Display for NetlinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "pid: {} groups: {}", self.pid(), self.groups()) - } - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod alg { - use super::*; - use libc::{c_char, sockaddr_alg, AF_ALG}; - use std::ffi::CStr; - use std::hash::{Hash, Hasher}; - use std::{fmt, mem, str}; - - /// Socket address for the Linux kernel crypto API - #[derive(Copy, Clone)] - #[repr(transparent)] - pub struct AlgAddr(pub(in super::super) sockaddr_alg); - - impl private::SockaddrLikePriv for AlgAddr {} - impl SockaddrLike for AlgAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - l: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = l { - if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t - { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_ALG { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_alg> for AlgAddr { - fn as_ref(&self) -> &libc::sockaddr_alg { - &self.0 - } - } - - // , PartialEq, Eq, Debug, Hash - impl PartialEq for AlgAddr { - fn eq(&self, other: &Self) -> bool { - let (inner, other) = (self.0, other.0); - ( - inner.salg_family, - &inner.salg_type[..], - inner.salg_feat, - inner.salg_mask, - &inner.salg_name[..], - ) == ( - other.salg_family, - &other.salg_type[..], - other.salg_feat, - other.salg_mask, - &other.salg_name[..], - ) - } - } - - impl Eq for AlgAddr {} - - impl Hash for AlgAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - let inner = self.0; - ( - inner.salg_family, - &inner.salg_type[..], - inner.salg_feat, - inner.salg_mask, - &inner.salg_name[..], - ) - .hash(s); - } - } - - impl AlgAddr { - /// Construct an `AF_ALG` socket from its cipher name and type. - pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { - let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; - addr.salg_family = AF_ALG as u16; - addr.salg_type[..alg_type.len()] - .copy_from_slice(alg_type.to_string().as_bytes()); - addr.salg_name[..alg_name.len()] - .copy_from_slice(alg_name.to_string().as_bytes()); - - AlgAddr(addr) - } - - /// Return the socket's cipher type, for example `hash` or `aead`. - pub fn alg_type(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) - } - } - - /// Return the socket's cipher name, for example `sha1`. - pub fn alg_name(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) - } - } - } - - impl fmt::Display for AlgAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "type: {} alg: {}", - self.alg_name().to_string_lossy(), - self.alg_type().to_string_lossy() - ) - } - } - - impl fmt::Debug for AlgAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } -} - -feature! { -#![feature = "ioctl"] -#[cfg(any(target_os = "ios", target_os = "macos"))] -pub mod sys_control { - use crate::sys::socket::addr::AddressFamily; - use libc::{self, c_uchar}; - use std::{fmt, mem, ptr}; - use std::os::unix::io::RawFd; - use crate::{Errno, Result}; - use super::{private, SockaddrLike}; - - // FIXME: Move type into `libc` - #[repr(C)] - #[derive(Clone, Copy)] - #[allow(missing_debug_implementations)] - pub struct ctl_ioc_info { - pub ctl_id: u32, - pub ctl_name: [c_uchar; MAX_KCTL_NAME], - } - - const CTL_IOC_MAGIC: u8 = b'N'; - const CTL_IOC_INFO: u8 = 3; - const MAX_KCTL_NAME: usize = 96; - - ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); - - /// Apple system control socket - /// - /// # References - /// - /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl> - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); - - impl private::SockaddrLikePriv for SysControlAddr {} - impl SockaddrLike for SysControlAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_SYSTEM { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_ctl> for SysControlAddr { - fn as_ref(&self) -> &libc::sockaddr_ctl { - &self.0 - } - } - - impl SysControlAddr { - /// Construct a new `SysControlAddr` from its kernel unique identifier - /// and unit number. - pub const fn new(id: u32, unit: u32) -> SysControlAddr { - let addr = libc::sockaddr_ctl { - sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, - sc_family: AddressFamily::System as c_uchar, - ss_sysaddr: libc::AF_SYS_CONTROL as u16, - sc_id: id, - sc_unit: unit, - sc_reserved: [0; 5] - }; - - SysControlAddr(addr) - } - - /// Construct a new `SysControlAddr` from its human readable name and - /// unit number. - pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { - if name.len() > MAX_KCTL_NAME { - return Err(Errno::ENAMETOOLONG); - } - - let mut ctl_name = [0; MAX_KCTL_NAME]; - ctl_name[..name.len()].clone_from_slice(name.as_bytes()); - let mut info = ctl_ioc_info { ctl_id: 0, ctl_name }; - - unsafe { ctl_info(sockfd, &mut info)?; } - - Ok(SysControlAddr::new(info.ctl_id, unit)) - } - - /// Return the kernel unique identifier - pub const fn id(&self) -> u32 { - self.0.sc_id - } - - /// Return the kernel controller private unit number. - pub const fn unit(&self) -> u32 { - self.0.sc_unit - } - } - - impl fmt::Display for SysControlAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } - } -} -} - -#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod datalink { - feature! { - #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; - - /// Hardware Address - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); - - impl LinkAddr { - /// Physical-layer protocol - pub fn protocol(&self) -> u16 { - self.0.sll_protocol - } - - /// Interface number - pub fn ifindex(&self) -> usize { - self.0.sll_ifindex as usize - } - - /// ARP hardware type - pub fn hatype(&self) -> u16 { - self.0.sll_hatype - } - - /// Packet type - pub fn pkttype(&self) -> u8 { - self.0.sll_pkttype - } - - /// Length of MAC address - pub fn halen(&self) -> usize { - self.0.sll_halen as usize - } - - /// Physical-layer address (MAC) - // Returns an Option just for cross-platform compatibility - pub fn addr(&self) -> Option<[u8; 6]> { - Some([ - self.0.sll_addr[0], - self.0.sll_addr[1], - self.0.sll_addr[2], - self.0.sll_addr[3], - self.0.sll_addr[4], - self.0.sll_addr[5], - ]) - } - } - - impl fmt::Display for LinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(addr) = self.addr() { - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) - } else { - Ok(()) - } - } - } - impl private::SockaddrLikePriv for LinkAddr {} - impl SockaddrLike for LinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, - len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_PACKET { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_ll> for LinkAddr { - fn as_ref(&self) -> &libc::sockaddr_ll { - &self.0 - } - } - - } -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod datalink { - feature! { - #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; - - /// Hardware Address - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); - - impl LinkAddr { - /// interface index, if != 0, system given index for interface - #[cfg(not(target_os = "haiku"))] - pub fn ifindex(&self) -> usize { - self.0.sdl_index as usize - } - - /// Datalink type - #[cfg(not(target_os = "haiku"))] - pub fn datalink_type(&self) -> u8 { - self.0.sdl_type - } - - /// MAC address start position - pub fn nlen(&self) -> usize { - self.0.sdl_nlen as usize - } - - /// link level address length - pub fn alen(&self) -> usize { - self.0.sdl_alen as usize - } - - /// link layer selector length - #[cfg(not(target_os = "haiku"))] - pub fn slen(&self) -> usize { - self.0.sdl_slen as usize - } - - /// if link level address length == 0, - /// or `sdl_data` not be larger. - pub fn is_empty(&self) -> bool { - let nlen = self.nlen(); - let alen = self.alen(); - let data_len = self.0.sdl_data.len(); - - alen == 0 || nlen + alen >= data_len - } - - /// Physical-layer address (MAC) - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn addr(&self) -> Option<[u8; 6]> { - let nlen = self.nlen(); - let data = self.0.sdl_data; - - if self.is_empty() { - None - } else { - Some([ - data[nlen] as u8, - data[nlen + 1] as u8, - data[nlen + 2] as u8, - data[nlen + 3] as u8, - data[nlen + 4] as u8, - data[nlen + 5] as u8, - ]) - } - } - } - - impl fmt::Display for LinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(addr) = self.addr() { - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) - } else { - Ok(()) - } - } - } - impl private::SockaddrLikePriv for LinkAddr {} - impl SockaddrLike for LinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, - len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_LINK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_dl> for LinkAddr { - fn as_ref(&self) -> &libc::sockaddr_dl { - &self.0 - } - } - - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod vsock { - use super::*; - use crate::sys::socket::addr::AddressFamily; - use libc::{sa_family_t, sockaddr_vm}; - use std::hash::{Hash, Hasher}; - use std::{fmt, mem}; - - /// Socket address for VMWare VSockets protocol - /// - /// # References - /// - /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) - #[derive(Copy, Clone)] - #[repr(transparent)] - pub struct VsockAddr(pub(in super::super) sockaddr_vm); - - impl private::SockaddrLikePriv for VsockAddr {} - impl SockaddrLike for VsockAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_VSOCK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_vm> for VsockAddr { - fn as_ref(&self) -> &libc::sockaddr_vm { - &self.0 - } - } - - impl PartialEq for VsockAddr { - fn eq(&self, other: &Self) -> bool { - let (inner, other) = (self.0, other.0); - (inner.svm_family, inner.svm_cid, inner.svm_port) - == (other.svm_family, other.svm_cid, other.svm_port) - } - } - - impl Eq for VsockAddr {} - - impl Hash for VsockAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - let inner = self.0; - (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); - } - } - - /// VSOCK Address - /// - /// The address for AF_VSOCK socket is defined as a combination of a - /// 32-bit Context Identifier (CID) and a 32-bit port number. - impl VsockAddr { - /// Construct a `VsockAddr` from its raw fields. - pub fn new(cid: u32, port: u32) -> VsockAddr { - let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; - addr.svm_family = AddressFamily::Vsock as sa_family_t; - addr.svm_cid = cid; - addr.svm_port = port; - - VsockAddr(addr) - } - - /// Context Identifier (CID) - pub fn cid(&self) -> u32 { - self.0.svm_cid - } - - /// Port number - pub fn port(&self) -> u32 { - self.0.svm_port - } - } - - impl fmt::Display for VsockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "cid: {} port: {}", self.cid(), self.port()) - } - } - - impl fmt::Debug for VsockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - mod types { - use super::*; - - #[test] - fn test_ipv4addr_to_libc() { - let s = std::net::Ipv4Addr::new(1, 2, 3, 4); - let l = ipv4addr_to_libc(s); - assert_eq!(l.s_addr, u32::to_be(0x01020304)); - } - - #[test] - fn test_ipv6addr_to_libc() { - let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); - let l = ipv6addr_to_libc(&s); - assert_eq!( - l.s6_addr, - [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] - ); - } - } - - mod link { - #![allow(clippy::cast_ptr_alignment)] - - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "illumos" - ))] - use super::super::super::socklen_t; - use super::*; - - /// Don't panic when trying to display an empty datalink address - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[test] - fn test_datalink_display() { - use super::super::LinkAddr; - use std::mem; - - let la = LinkAddr(libc::sockaddr_dl { - sdl_len: 56, - sdl_family: 18, - sdl_index: 5, - sdl_type: 24, - sdl_nlen: 3, - sdl_alen: 0, - sdl_slen: 0, - ..unsafe { mem::zeroed() } - }); - format!("{}", la); - } - - #[cfg(all( - any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ), - target_endian = "little" - ))] - #[test] - fn linux_loopback() { - #[repr(align(2))] - struct Raw([u8; 20]); - - let bytes = Raw([ - 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, - ]); - let sa = bytes.0.as_ptr() as *const libc::sockaddr; - let len = None; - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); - assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); - match sock_addr.as_link_addr() { - Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[test] - fn macos_loopback() { - let bytes = - [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); - assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); - match sock_addr.as_link_addr() { - Some(dl) => { - assert!(dl.addr().is_none()); - } - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[test] - fn macos_tap() { - let bytes = [ - 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, - 76, -80, - ]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; - assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); - match sock_addr.as_link_addr() { - Some(dl) => { - assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) - } - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(target_os = "illumos")] - #[test] - fn illumos_tap() { - let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; - - assert!(_sock_addr.is_some()); - - let sock_addr = _sock_addr.unwrap(); - - assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); - - assert_eq!( - sock_addr.as_link_addr().unwrap().addr(), - Some([24u8, 101, 144, 221, 76, 176]) - ); - } - - #[test] - fn size() { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd", - target_os = "haiku" - ))] - let l = mem::size_of::<libc::sockaddr_dl>(); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - let l = mem::size_of::<libc::sockaddr_ll>(); - assert_eq!(LinkAddr::size() as usize, l); - } - } - - mod sockaddr_in { - use super::*; - use std::str::FromStr; - - #[test] - fn display() { - let s = "127.0.0.1:8080"; - let addr = SockaddrIn::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_in>(), - SockaddrIn::size() as usize - ); - } - } - - mod sockaddr_in6 { - use super::*; - use std::str::FromStr; - - #[test] - fn display() { - let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; - let addr = SockaddrIn6::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_in6>(), - SockaddrIn6::size() as usize - ); - } - - #[test] - // Ensure that we can convert to-and-from std::net variants without change. - fn to_and_from() { - let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; - let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); - nix_sin6.0.sin6_flowinfo = 0x12345678; - nix_sin6.0.sin6_scope_id = 0x9abcdef0; - - let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into(); - assert_eq!(nix_sin6, std_sin6.into()); - } - } - - mod sockaddr_storage { - use super::*; - - #[test] - fn from_sockaddr_un_named() { - let ua = UnixAddr::new("/var/run/mysock").unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn from_sockaddr_un_abstract_named() { - let name = String::from("nix\0abstract\0test"); - let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn from_sockaddr_un_abstract_unnamed() { - let ua = UnixAddr::new_unnamed(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - } - - mod unixaddr { - use super::*; - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn abstract_sun_path() { - let name = String::from("nix\0abstract\0test"); - let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - - let sun_path1 = - unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [ - 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, - 116, 101, 115, 116, - ]; - assert_eq!(sun_path1, sun_path2); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_un>(), - UnixAddr::size() as usize - ); - } - } -} diff --git a/vendor/nix/src/sys/socket/mod.rs b/vendor/nix/src/sys/socket/mod.rs deleted file mode 100644 index 8513b6fbe..000000000 --- a/vendor/nix/src/sys/socket/mod.rs +++ /dev/null @@ -1,2487 +0,0 @@ -//! Socket interface functions -//! -//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -#[cfg(target_os = "linux")] -#[cfg(feature = "uio")] -use crate::sys::time::TimeSpec; -#[cfg(feature = "uio")] -use crate::sys::time::TimeVal; -use crate::{errno::Errno, Result}; -use cfg_if::cfg_if; -use libc::{ - self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, - CMSG_LEN, CMSG_NXTHDR, -}; -use std::convert::{TryFrom, TryInto}; -use std::io::{IoSlice, IoSliceMut}; -#[cfg(feature = "net")] -use std::net; -use std::os::unix::io::RawFd; -use std::{mem, ptr, slice}; - -#[deny(missing_docs)] -mod addr; -#[deny(missing_docs)] -pub mod sockopt; - -/* - * - * ===== Re-exports ===== - * - */ - -pub use self::addr::{SockaddrLike, SockaddrStorage}; - -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; -#[cfg(any(target_os = "illumos", target_os = "solaris"))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; -#[allow(deprecated)] -#[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" -)))] -#[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, -}; -#[allow(deprecated)] -#[cfg(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" -))] -#[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, -}; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "ios", target_os = "macos"))] -#[cfg(feature = "ioctl")] -pub use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::vsock::VsockAddr; - -#[cfg(feature = "uio")] -pub use libc::{cmsghdr, msghdr}; -pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; -#[cfg(feature = "net")] -pub use libc::{sockaddr_in, sockaddr_in6}; - -// Needed by the cmsg_space macro -#[doc(hidden)] -pub use libc::{c_uint, CMSG_SPACE}; - -#[cfg(feature = "net")] -use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; - -/// These constants are used to specify the communication semantics -/// when creating a socket with [`socket()`](fn.socket.html) -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[repr(i32)] -#[non_exhaustive] -pub enum SockType { - /// Provides sequenced, reliable, two-way, connection- - /// based byte streams. An out-of-band data transmission - /// mechanism may be supported. - Stream = libc::SOCK_STREAM, - /// Supports datagrams (connectionless, unreliable - /// messages of a fixed maximum length). - Datagram = libc::SOCK_DGRAM, - /// Provides a sequenced, reliable, two-way connection- - /// based data transmission path for datagrams of fixed - /// maximum length; a consumer is required to read an - /// entire packet with each input system call. - SeqPacket = libc::SOCK_SEQPACKET, - /// Provides raw network protocol access. - Raw = libc::SOCK_RAW, - /// Provides a reliable datagram layer that does not - /// guarantee ordering. - #[cfg(not(any(target_os = "haiku")))] - Rdm = libc::SOCK_RDM, -} -// The TryFrom impl could've been derived using libc_enum!. But for -// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to -// keep the old variant names. -impl TryFrom<i32> for SockType { - type Error = crate::Error; - - fn try_from(x: i32) -> Result<Self> { - match x { - libc::SOCK_STREAM => Ok(Self::Stream), - libc::SOCK_DGRAM => Ok(Self::Datagram), - libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), - libc::SOCK_RAW => Ok(Self::Raw), - #[cfg(not(any(target_os = "haiku")))] - libc::SOCK_RDM => Ok(Self::Rdm), - _ => Err(Errno::EINVAL) - } - } -} - -/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) -/// to specify the protocol to use. -#[repr(i32)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum SockProtocol { - /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) - Tcp = libc::IPPROTO_TCP, - /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) - Udp = libc::IPPROTO_UDP, - /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) - Raw = libc::IPPROTO_RAW, - /// Allows applications and other KEXTs to be notified when certain kernel events occur - /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - KextEvent = libc::SYSPROTO_EVENT, - /// Allows applications to configure and control a KEXT - /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - KextControl = libc::SYSPROTO_CONTROL, - /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link - // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkRoute = libc::NETLINK_ROUTE, - /// Reserved for user-mode socket protocols - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkUserSock = libc::NETLINK_USERSOCK, - /// Query information about sockets of various protocol families from the kernel - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, - /// SELinux event notifications. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSELinux = libc::NETLINK_SELINUX, - /// Open-iSCSI - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkISCSI = libc::NETLINK_ISCSI, - /// Auditing - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkAudit = libc::NETLINK_AUDIT, - /// Access to FIB lookup from user space - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, - /// Netfilter subsystem - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkNetFilter = libc::NETLINK_NETFILTER, - /// SCSI Transports - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, - /// Infiniband RDMA - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkRDMA = libc::NETLINK_RDMA, - /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, - /// DECnet routing messages - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, - /// Kernel messages to user space - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, - /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow - /// configuration of the kernel crypto API. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkCrypto = libc::NETLINK_CRYPTO, - /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols - /// defined in the interface to be received. - /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) - // The protocol number is fed into the socket syscall in network byte order. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - EthAll = libc::ETH_P_ALL.to_be(), -} - -#[cfg(any(target_os = "linux"))] -libc_bitflags! { - /// Configuration flags for `SO_TIMESTAMPING` interface - /// - /// For use with [`Timestamping`][sockopt::Timestamping]. - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - pub struct TimestampingFlag: c_uint { - /// Report any software timestamps when available. - SOF_TIMESTAMPING_SOFTWARE; - /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. - SOF_TIMESTAMPING_RAW_HARDWARE; - /// Collect transmiting timestamps as reported by hardware - SOF_TIMESTAMPING_TX_HARDWARE; - /// Collect transmiting timestamps as reported by software - SOF_TIMESTAMPING_TX_SOFTWARE; - /// Collect receiving timestamps as reported by hardware - SOF_TIMESTAMPING_RX_HARDWARE; - /// Collect receiving timestamps as reported by software - SOF_TIMESTAMPING_RX_SOFTWARE; - } -} - -libc_bitflags! { - /// Additional socket options - pub struct SockFlag: c_int { - /// Set non-blocking mode on the new socket - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_NONBLOCK; - /// Set close-on-exec on the new descriptor - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_CLOEXEC; - /// Return `EPIPE` instead of raising `SIGPIPE` - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_NOSIGPIPE; - /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` - /// to the DNS port (typically 53) - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_DNS; - } -} - -libc_bitflags! { - /// Flags for send/recv and their relatives - pub struct MsgFlags: c_int { - /// Sends or requests out-of-band data on sockets that support this notion - /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also - /// support out-of-band data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_OOB; - /// Peeks at an incoming message. The data is treated as unread and the next - /// [`recv()`](fn.recv.html) - /// or similar function shall still return this data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_PEEK; - /// Receive operation blocks until the full amount of data can be - /// returned. The function may return smaller amount of data if a signal - /// is caught, an error or disconnect occurs. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_WAITALL; - /// Enables nonblocking operation; if the operation would block, - /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar - /// behavior to setting the `O_NONBLOCK` flag - /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) - /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- - /// call option, whereas `O_NONBLOCK` is a setting on the open file - /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), - /// which will affect all threads in - /// the calling process and as well as other processes that hold - /// file descriptors referring to the same open file description. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_DONTWAIT; - /// Receive flags: Control Data was discarded (buffer too small) - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_CTRUNC; - /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram - /// (since Linux 2.4.27/2.6.8), - /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) - /// sockets: return the real length of the packet or datagram, even - /// when it was longer than the passed buffer. Not implemented for UNIX - /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. - /// - /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_TRUNC; - /// Terminates a record (when this notion is supported, as for - /// sockets of type [`SeqPacket`](enum.SockType.html)). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_EOR; - /// This flag specifies that queued errors should be received from - /// the socket error queue. (For more details, see - /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_ERRQUEUE; - /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain - /// file descriptor using the `SCM_RIGHTS` operation (described in - /// [unix(7)](https://linux.die.net/man/7/unix)). - /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of - /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). - /// - /// Only used in [`recvmsg`](fn.recvmsg.html) function. - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_CMSG_CLOEXEC; - /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. - /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_NOSIGNAL; - } -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - /// Unix credentials of the sending process. - /// - /// This struct is used with the `SO_PEERCRED` ancillary message - /// and the `SCM_CREDENTIALS` control message for UNIX sockets. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct UnixCredentials(libc::ucred); - - impl UnixCredentials { - /// Creates a new instance with the credentials of the current process - pub fn new() -> Self { - // Safe because these FFI functions are inherently safe - unsafe { - UnixCredentials(libc::ucred { - pid: libc::getpid(), - uid: libc::getuid(), - gid: libc::getgid() - }) - } - } - - /// Returns the process identifier - pub fn pid(&self) -> libc::pid_t { - self.0.pid - } - - /// Returns the user identifier - pub fn uid(&self) -> libc::uid_t { - self.0.uid - } - - /// Returns the group identifier - pub fn gid(&self) -> libc::gid_t { - self.0.gid - } - } - - impl Default for UnixCredentials { - fn default() -> Self { - Self::new() - } - } - - impl From<libc::ucred> for UnixCredentials { - fn from(cred: libc::ucred) -> Self { - UnixCredentials(cred) - } - } - - impl From<UnixCredentials> for libc::ucred { - fn from(uc: UnixCredentials) -> Self { - uc.0 - } - } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { - /// Unix credentials of the sending process. - /// - /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct UnixCredentials(libc::cmsgcred); - - impl UnixCredentials { - /// Returns the process identifier - pub fn pid(&self) -> libc::pid_t { - self.0.cmcred_pid - } - - /// Returns the real user identifier - pub fn uid(&self) -> libc::uid_t { - self.0.cmcred_uid - } - - /// Returns the effective user identifier - pub fn euid(&self) -> libc::uid_t { - self.0.cmcred_euid - } - - /// Returns the real group identifier - pub fn gid(&self) -> libc::gid_t { - self.0.cmcred_gid - } - - /// Returns a list group identifiers (the first one being the effective GID) - pub fn groups(&self) -> &[libc::gid_t] { - unsafe { - slice::from_raw_parts( - self.0.cmcred_groups.as_ptr() as *const libc::gid_t, - self.0.cmcred_ngroups as _ - ) - } - } - } - - impl From<libc::cmsgcred> for UnixCredentials { - fn from(cred: libc::cmsgcred) -> Self { - UnixCredentials(cred) - } - } - } -} - -cfg_if! { - if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" - ))] { - /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct XuCred(libc::xucred); - - impl XuCred { - /// Structure layout version - pub fn version(&self) -> u32 { - self.0.cr_version - } - - /// Effective user ID - pub fn uid(&self) -> libc::uid_t { - self.0.cr_uid - } - - /// Returns a list of group identifiers (the first one being the - /// effective GID) - pub fn groups(&self) -> &[libc::gid_t] { - &self.0.cr_groups - } - } - } -} - -feature! { -#![feature = "net"] -/// Request for multicast socket operations -/// -/// This is a wrapper type around `ip_mreq`. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct IpMembershipRequest(libc::ip_mreq); - -impl IpMembershipRequest { - /// Instantiate a new `IpMembershipRequest` - /// - /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. - pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>) - -> Self - { - let imr_addr = match interface { - None => net::Ipv4Addr::UNSPECIFIED, - Some(addr) => addr - }; - IpMembershipRequest(libc::ip_mreq { - imr_multiaddr: ipv4addr_to_libc(group), - imr_interface: ipv4addr_to_libc(imr_addr) - }) - } -} - -/// Request for ipv6 multicast socket operations -/// -/// This is a wrapper type around `ipv6_mreq`. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Ipv6MembershipRequest(libc::ipv6_mreq); - -impl Ipv6MembershipRequest { - /// Instantiate a new `Ipv6MembershipRequest` - pub const fn new(group: net::Ipv6Addr) -> Self { - Ipv6MembershipRequest(libc::ipv6_mreq { - ipv6mr_multiaddr: ipv6addr_to_libc(&group), - ipv6mr_interface: 0, - }) - } -} -} - -feature! { -#![feature = "uio"] - -/// Create a buffer large enough for storing some control messages as returned -/// by [`recvmsg`](fn.recvmsg.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # use nix::sys::time::TimeVal; -/// # use std::os::unix::io::RawFd; -/// # fn main() { -/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message -/// let _ = cmsg_space!(TimeVal); -/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message -/// // with two file descriptors -/// let _ = cmsg_space!([RawFd; 2]); -/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message -/// // and a `ControlMessageOwned::ScmTimestamp` message -/// let _ = cmsg_space!(RawFd, TimeVal); -/// # } -/// ``` -// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a -// stack-allocated array. -#[macro_export] -macro_rules! cmsg_space { - ( $( $x:ty ),* ) => { - { - let mut space = 0; - $( - // CMSG_SPACE is always safe - space += unsafe { - $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) - } as usize; - )* - Vec::<u8>::with_capacity(space) - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -/// Contains outcome of sending or receiving a message -/// -/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and -/// [`iovs`][RecvMsg::iovs`] to access underlying io slices. -pub struct RecvMsg<'a, 's, S> { - pub bytes: usize, - cmsghdr: Option<&'a cmsghdr>, - pub address: Option<S>, - pub flags: MsgFlags, - iobufs: std::marker::PhantomData<& 's()>, - mhdr: msghdr, -} - -impl<'a, S> RecvMsg<'a, '_, S> { - /// Iterate over the valid control messages pointed to by this - /// msghdr. - pub fn cmsgs(&self) -> CmsgIterator { - CmsgIterator { - cmsghdr: self.cmsghdr, - mhdr: &self.mhdr - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CmsgIterator<'a> { - /// Control message buffer to decode from. Must adhere to cmsg alignment. - cmsghdr: Option<&'a cmsghdr>, - mhdr: &'a msghdr -} - -impl<'a> Iterator for CmsgIterator<'a> { - type Item = ControlMessageOwned; - - fn next(&mut self) -> Option<ControlMessageOwned> { - match self.cmsghdr { - None => None, // No more messages - Some(hdr) => { - // Get the data. - // Safe if cmsghdr points to valid data returned by recvmsg(2) - let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; - // Advance the internal pointer. Safe if mhdr and cmsghdr point - // to valid data returned by recvmsg(2) - self.cmsghdr = unsafe { - let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); - p.as_ref() - }; - cm - } - } - } -} - -/// A type-safe wrapper around a single control message, as used with -/// [`recvmsg`](#fn.recvmsg). -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) -// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and -// sendmsg. However, on some platforms the messages returned by recvmsg may be -// unaligned. ControlMessageOwned takes those messages by copy, obviating any -// alignment issues. -// -// See https://github.com/nix-rust/nix/issues/999 -#[derive(Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum ControlMessageOwned { - /// Received version of [`ControlMessage::ScmRights`] - ScmRights(Vec<RawFd>), - /// Received version of [`ControlMessage::ScmCredentials`] - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCredentials(UnixCredentials), - /// Received version of [`ControlMessage::ScmCreds`] - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCreds(UnixCredentials), - /// A message of type `SCM_TIMESTAMP`, containing the time the - /// packet was received by the kernel. - /// - /// See the kernel's explanation in "SO_TIMESTAMP" of - /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). - /// - /// # Examples - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// # use nix::sys::socket::*; - /// # use nix::sys::time::*; - /// # use std::io::{IoSlice, IoSliceMut}; - /// # use std::time::*; - /// # use std::str::FromStr; - /// # fn main() { - /// // Set up - /// let message = "Ohayō!".as_bytes(); - /// let in_socket = socket( - /// AddressFamily::Inet, - /// SockType::Datagram, - /// SockFlag::empty(), - /// None).unwrap(); - /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); - /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - /// bind(in_socket, &localhost).unwrap(); - /// let address: SockaddrIn = getsockname(in_socket).unwrap(); - /// // Get initial time - /// let time0 = SystemTime::now(); - /// // Send the message - /// let iov = [IoSlice::new(message)]; - /// let flags = MsgFlags::empty(); - /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - /// assert_eq!(message.len(), l); - /// // Receive the message - /// let mut buffer = vec![0u8; message.len()]; - /// let mut cmsgspace = cmsg_space!(TimeVal); - /// let mut iov = [IoSliceMut::new(&mut buffer)]; - /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags) - /// .unwrap(); - /// let rtime = match r.cmsgs().next() { - /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, - /// Some(_) => panic!("Unexpected control message"), - /// None => panic!("No control message") - /// }; - /// // Check the final time - /// let time1 = SystemTime::now(); - /// // the packet's received timestamp should lie in-between the two system - /// // times, unless the system clock was adjusted in the meantime. - /// let rduration = Duration::new(rtime.tv_sec() as u64, - /// rtime.tv_usec() as u32 * 1000); - /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - /// // Close socket - /// nix::unistd::close(in_socket).unwrap(); - /// # } - /// ``` - ScmTimestamp(TimeVal), - /// A set of nanosecond resolution timestamps - /// - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] - ScmTimestampsns(Timestamps), - /// Nanoseconds resolution timestamp - /// - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmTimestampns(TimeSpec), - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4PacketInfo(libc::in_pktinfo), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6PacketInfo(libc::in6_pktinfo), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvIf(libc::sockaddr_dl), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvDstAddr(libc::in_addr), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4OrigDstAddr(libc::sockaddr_in), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6OrigDstAddr(libc::sockaddr_in6), - - /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP - /// packets from a single sender. - /// Fixed-size payloads are following one by one in a receive buffer. - /// This Control Message indicates the size of all smaller packets, - /// except, maybe, the last one. - /// - /// `UdpGroSegment` socket option should be enabled on a socket - /// to allow receiving GRO packets. - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - UdpGroSegments(u16), - - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - /// - /// `RxqOvfl` socket option should be enabled on a socket - /// to allow receiving the drop counter. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxqOvfl(u32), - - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>), - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), - - /// Catch-all variant for unimplemented cmsg types. - #[doc(hidden)] - Unknown(UnknownCmsg), -} - -/// For representing packet timestamps via `SO_TIMESTAMPING` interface -#[cfg(all(target_os = "linux"))] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Timestamps { - /// software based timestamp, usually one containing data - pub system: TimeSpec, - /// legacy timestamp, usually empty - pub hw_trans: TimeSpec, - /// hardware based timestamp - pub hw_raw: TimeSpec, -} - -impl ControlMessageOwned { - /// Decodes a `ControlMessageOwned` from raw bytes. - /// - /// This is only safe to call if the data is correct for the message type - /// specified in the header. Normally, the kernel ensures that this is the - /// case. "Correct" in this case includes correct length, alignment and - /// actual content. - // Clippy complains about the pointer alignment of `p`, not understanding - // that it's being fed to a function that can handle that. - #[allow(clippy::cast_ptr_alignment)] - unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned - { - let p = CMSG_DATA(header); - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - let len = header as *const _ as usize + header.cmsg_len as usize - - p as usize; - match (header.cmsg_level, header.cmsg_type) { - (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { - let n = len / mem::size_of::<RawFd>(); - let mut fds = Vec::with_capacity(n); - for i in 0..n { - let fdp = (p as *const RawFd).add(i); - fds.push(ptr::read_unaligned(fdp)); - } - ControlMessageOwned::ScmRights(fds) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { - let cred: libc::ucred = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmCredentials(cred.into()) - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - (libc::SOL_SOCKET, libc::SCM_CREDS) => { - let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmCreds(cred.into()) - } - #[cfg(not(target_os = "haiku"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { - let tv: libc::timeval = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) - }, - #[cfg(all(target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { - let ts: libc::timespec = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) - } - #[cfg(all(target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { - let tp = p as *const libc::timespec; - let ts: libc::timespec = ptr::read_unaligned(tp); - let system = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); - let hw_trans = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); - let hw_raw = TimeSpec::from(ts); - let timestamping = Timestamps { system, hw_trans, hw_raw }; - ControlMessageOwned::ScmTimestampsns(timestamping) - } - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); - ControlMessageOwned::Ipv6PacketInfo(info) - } - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in_pktinfo); - ControlMessageOwned::Ipv4PacketInfo(info) - } - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVIF) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); - ControlMessageOwned::Ipv4RecvIf(dl) - }, - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::in_addr); - ControlMessageOwned::Ipv4RecvDstAddr(dl) - }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); - ControlMessageOwned::Ipv4OrigDstAddr(dl) - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - (libc::SOL_UDP, libc::UDP_GRO) => { - let gso_size: u16 = ptr::read_unaligned(p as *const _); - ControlMessageOwned::UdpGroSegments(gso_size) - }, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { - let drop_counter = ptr::read_unaligned(p as *const u32); - ControlMessageOwned::RxqOvfl(drop_counter) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); - ControlMessageOwned::Ipv4RecvErr(err, addr) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); - ControlMessageOwned::Ipv6RecvErr(err, addr) - }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); - ControlMessageOwned::Ipv6OrigDstAddr(dl) - }, - (_, _) => { - let sl = slice::from_raw_parts(p, len); - let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl)); - ControlMessageOwned::Unknown(ucmsg) - } - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[allow(clippy::cast_ptr_alignment)] // False positive - unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) { - let ee = p as *const libc::sock_extended_err; - let err = ptr::read_unaligned(ee); - - // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] - // CMSG_DATA buffer. For local errors, there is no address included in the control - // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to - // validate that the address object is in-bounds before we attempt to copy it. - let addrp = libc::SO_EE_OFFENDER(ee) as *const T; - - if addrp.offset(1) as usize - (p as usize) > len { - (err, None) - } else { - (err, Some(ptr::read_unaligned(addrp))) - } - } -} - -/// A type-safe zero-copy wrapper around a single control message, as used wih -/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not -/// exhaustively pattern-match it. -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum ControlMessage<'a> { - /// A message of type `SCM_RIGHTS`, containing an array of file - /// descriptors passed between processes. - /// - /// See the description in the "Ancillary messages" section of the - /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). - /// - /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't - /// recommended since it causes platform-dependent behaviour: It might - /// swallow all but the first `ScmRights` message or fail with `EINVAL`. - /// Instead, you can put all fds to be passed into a single `ScmRights` - /// message. - ScmRights(&'a [RawFd]), - /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of - /// a process connected to the socket. - /// - /// This is similar to the socket option `SO_PEERCRED`, but requires a - /// process to explicitly send its credentials. A process running as root is - /// allowed to specify any credentials, while credentials sent by other - /// processes are verified by the kernel. - /// - /// For further information, please refer to the - /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCredentials(&'a UnixCredentials), - /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of - /// a process connected to the socket. - /// - /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but - /// requires a process to explicitly send its credentials. - /// - /// Credentials are always overwritten by the kernel, so this variant does have - /// any data, unlike the receive-side - /// [`ControlMessageOwned::ScmCreds`]. - /// - /// For further information, please refer to the - /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCreds, - - /// Set IV for `AF_ALG` crypto API. - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetIv(&'a [u8]), - /// Set crypto operation for `AF_ALG` crypto API. It may be one of - /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetOp(&'a libc::c_int), - /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) - /// for `AF_ALG` crypto API. - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetAeadAssoclen(&'a u32), - - /// UDP GSO makes it possible for applications to generate network packets - /// for a virtual MTU much greater than the real one. - /// The length of the send data no longer matches the expected length on - /// the wire. - /// The size of the datagram payload as it should appear on the wire may be - /// passed through this control message. - /// Send buffer should consist of multiple fixed-size wire payloads - /// following one by one, and the last, possibly smaller one. - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - UdpGsoSegments(&'a u16), - - /// Configure the sending addressing and interface for v4 - /// - /// For further information, please refer to the - /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4PacketInfo(&'a libc::in_pktinfo), - - /// Configure the sending addressing and interface for v6 - /// - /// For further information, please refer to the - /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "freebsd", - target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6PacketInfo(&'a libc::in6_pktinfo), - - /// Configure the IPv4 source address with `IP_SENDSRCADDR`. - #[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4SendSrcAddr(&'a libc::in_addr), - - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxqOvfl(&'a u32), - - /// Configure the transmission time of packets. - /// - /// For further information, please refer to the - /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man - /// page. - #[cfg(target_os = "linux")] - TxTime(&'a u64), -} - -// An opaque structure used to prevent cmsghdr from being a public type -#[doc(hidden)] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UnknownCmsg(cmsghdr, Vec<u8>); - -impl<'a> ControlMessage<'a> { - /// The value of CMSG_SPACE on this message. - /// Safe because CMSG_SPACE is always safe - fn space(&self) -> usize { - unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} - } - - /// The value of CMSG_LEN on this message. - /// Safe because CMSG_LEN is always safe - #[cfg(any(target_os = "android", - all(target_os = "linux", not(target_env = "musl"))))] - fn cmsg_len(&self) -> usize { - unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} - } - - #[cfg(not(any(target_os = "android", - all(target_os = "linux", not(target_env = "musl")))))] - fn cmsg_len(&self) -> libc::c_uint { - unsafe{CMSG_LEN(self.len() as libc::c_uint)} - } - - /// Return a reference to the payload data as a byte pointer - fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { - let data_ptr = match *self { - ControlMessage::ScmRights(fds) => { - fds as *const _ as *const u8 - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(creds) => { - &creds.0 as *const libc::ucred as *const u8 - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => { - // The kernel overwrites the data, we just zero it - // to make sure it's not uninitialized memory - unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; - return - } - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(iv) => { - #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 - let af_alg_iv = libc::af_alg_iv { - ivlen: iv.len() as u32, - iv: [0u8; 0], - }; - - let size = mem::size_of_val(&af_alg_iv); - - unsafe { - ptr::copy_nonoverlapping( - &af_alg_iv as *const _ as *const u8, - cmsg_data, - size, - ); - ptr::copy_nonoverlapping( - iv.as_ptr(), - cmsg_data.add(size), - iv.len() - ); - }; - - return - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(op) => { - op as *const _ as *const u8 - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(len) => { - len as *const _ as *const u8 - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(gso_size) => { - gso_size as *const _ as *const u8 - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - drop_count as *const _ as *const u8 - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(tx_time) => { - tx_time as *const _ as *const u8 - }, - }; - unsafe { - ptr::copy_nonoverlapping( - data_ptr, - cmsg_data, - self.len() - ) - }; - } - - /// The size of the payload, excluding its cmsghdr - fn len(&self) -> usize { - match *self { - ControlMessage::ScmRights(fds) => { - mem::size_of_val(fds) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(creds) => { - mem::size_of_val(creds) - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => { - mem::size_of::<libc::cmsgcred>() - } - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(iv) => { - mem::size_of::<&[u8]>() + iv.len() - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(op) => { - mem::size_of_val(op) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(len) => { - mem::size_of_val(len) - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(gso_size) => { - mem::size_of_val(gso_size) - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - mem::size_of_val(drop_count) - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(tx_time) => { - mem::size_of_val(tx_time) - }, - } - } - - /// Returns the value to put into the `cmsg_level` field of the header. - fn cmsg_level(&self) -> libc::c_int { - match *self { - ControlMessage::ScmRights(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | - ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(_) => libc::SOL_SOCKET, - } - } - - /// Returns the value to put into the `cmsg_type` field of the header. - fn cmsg_type(&self) -> libc::c_int { - match *self { - ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => libc::SCM_CREDS, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(_) => { - libc::ALG_SET_IV - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(_) => { - libc::ALG_SET_OP - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(_) => { - libc::ALG_SET_AEAD_ASSOCLEN - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(_) => { - libc::UDP_SEGMENT - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => { - libc::SO_RXQ_OVFL - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(_) => { - libc::SCM_TXTIME - }, - } - } - - // Unsafe: cmsg must point to a valid cmsghdr with enough space to - // encode self. - unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { - (*cmsg).cmsg_level = self.cmsg_level(); - (*cmsg).cmsg_type = self.cmsg_type(); - (*cmsg).cmsg_len = self.cmsg_len(); - self.copy_to_cmsg_data(CMSG_DATA(cmsg)); - } -} - - -/// Send data in scatter-gather vectors to a socket, possibly accompanied -/// by ancillary data. Optionally direct the message at the given address, -/// as with sendto. -/// -/// Allocates if cmsgs is nonempty. -/// -/// # Examples -/// When not directing to any specific address, use `()` for the generic type -/// ``` -/// # use nix::sys::socket::*; -/// # use nix::unistd::pipe; -/// # use std::io::IoSlice; -/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, -/// SockFlag::empty()) -/// .unwrap(); -/// let (r, w) = pipe().unwrap(); -/// -/// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; -/// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); -/// ``` -/// When directing to a specific address, the generic type will be inferred. -/// ``` -/// # use nix::sys::socket::*; -/// # use nix::unistd::pipe; -/// # use std::io::IoSlice; -/// # use std::str::FromStr; -/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); -/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), -/// None).unwrap(); -/// let (r, w) = pipe().unwrap(); -/// -/// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; -/// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); -/// ``` -pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], - flags: MsgFlags, addr: Option<&S>) -> Result<usize> - where S: SockaddrLike -{ - let capacity = cmsgs.iter().map(|c| c.space()).sum(); - - // First size the buffer needed to hold the cmsgs. It must be zeroed, - // because subsequent code will not clear the padding bytes. - let mut cmsg_buffer = vec![0u8; capacity]; - - let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr); - - let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; - - Errno::result(ret).map(|r| r as usize) -} - - -/// An extension of `sendmsg` that allows the caller to transmit multiple -/// messages on a socket using a single system call. This has performance -/// benefits for some applications. -/// -/// Allocations are performed for cmsgs and to build `msghdr` buffer -/// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items -/// * `flags`: Optional flags passed directly to the operating system. -/// -/// # Returns -/// `Vec` with numbers of sent bytes on each sent message. -/// -/// # References -/// [`sendmsg`](fn.sendmsg.html) -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -pub fn sendmmsg<'a, XS, AS, C, I, S>( - fd: RawFd, - data: &'a mut MultiHeaders<S>, - slices: XS, - // one address per group of slices - addrs: AS, - // shared across all the messages - cmsgs: C, - flags: MsgFlags -) -> crate::Result<MultiResults<'a, S>> - where - XS: IntoIterator<Item = &'a I>, - AS: AsRef<[Option<S>]>, - I: AsRef<[IoSlice<'a>]> + 'a, - C: AsRef<[ControlMessage<'a>]> + 'a, - S: SockaddrLike + 'a -{ - - let mut count = 0; - - - for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; - p.msg_iovlen = slice.as_ref().len() as _; - - p.msg_namelen = addr.as_ref().map_or(0, S::len); - p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; - - // Encode each cmsg. This must happen after initializing the header because - // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. - // CMSG_FIRSTHDR is always safe - let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) }; - for cmsg in cmsgs.as_ref() { - assert_ne!(pmhdr, ptr::null_mut()); - // Safe because we know that pmhdr is valid, and we initialized it with - // sufficient space - unsafe { cmsg.encode_into(pmhdr) }; - // Safe because mhdr is valid - pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; - } - - count = i+1; - } - - let sent = Errno::result(unsafe { - libc::sendmmsg( - fd, - data.items.as_mut_ptr(), - count as _, - flags.bits() as _ - ) - })? as usize; - - Ok(MultiResults { - rmm: data, - current_index: 0, - received: sent - }) - -} - - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] -/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions -pub struct MultiHeaders<S> { - // preallocated boxed slice of mmsghdr - items: Box<[libc::mmsghdr]>, - addresses: Box<[mem::MaybeUninit<S>]>, - // while we are not using it directly - this is used to store control messages - // and we retain pointers to them inside items array - #[allow(dead_code)] - cmsg_buffers: Option<Box<[u8]>>, - msg_controllen: usize, -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -impl<S> MultiHeaders<S> { - /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate - /// - /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed - pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self - where - S: Copy + SockaddrLike, - { - // we will be storing pointers to addresses inside mhdr - convert it into boxed - // slice so it can'be changed later by pushing anything into self.addresses - let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); - - let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); - - // we'll need a cmsg_buffer for each slice, we preallocate a vector and split - // it into "slices" parts - let cmsg_buffers = - cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); - - let items = addresses - .iter_mut() - .enumerate() - .map(|(ix, address)| { - let (ptr, cap) = match &cmsg_buffers { - Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), - None => (std::ptr::null(), 0), - }; - let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; - libc::mmsghdr { - msg_hdr, - msg_len: 0, - } - }) - .collect::<Vec<_>>(); - - Self { - items: items.into_boxed_slice(), - addresses, - cmsg_buffers, - msg_controllen, - } - } -} - -/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. -/// -/// This has performance benefits for some applications. -/// -/// This method performs no allocations. -/// -/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce -/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and -/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs]. -/// -/// # Bugs (in underlying implementation, at least in Linux) -/// The timeout argument does not work as intended. The timeout is checked only after the receipt -/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires, -/// but then no further datagrams are received, the call will block forever. -/// -/// If an error occurs after at least one message has been received, the call succeeds, and returns -/// the number of messages received. The error code is expected to be returned on a subsequent -/// call to recvmmsg(). In the current implementation, however, the error code can be -/// overwritten in the meantime by an unrelated network event on a socket, for example an -/// incoming ICMP packet. - -// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not -// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more -// details - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -pub fn recvmmsg<'a, XS, S, I>( - fd: RawFd, - data: &'a mut MultiHeaders<S>, - slices: XS, - flags: MsgFlags, - mut timeout: Option<crate::sys::time::TimeSpec>, -) -> crate::Result<MultiResults<'a, S>> -where - XS: IntoIterator<Item = &'a I>, - I: AsRef<[IoSliceMut<'a>]> + 'a, -{ - let mut count = 0; - for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; - p.msg_iovlen = slice.as_ref().len() as _; - count = i + 1; - } - - let timeout_ptr = timeout - .as_mut() - .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); - - let received = Errno::result(unsafe { - libc::recvmmsg( - fd, - data.items.as_mut_ptr(), - count as _, - flags.bits() as _, - timeout_ptr, - ) - })? as usize; - - Ok(MultiResults { - rmm: data, - current_index: 0, - received, - }) -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] -/// Iterator over results of [`recvmmsg`]/[`sendmmsg`] -/// -/// -pub struct MultiResults<'a, S> { - // preallocated structures - rmm: &'a MultiHeaders<S>, - current_index: usize, - received: usize, -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -impl<'a, S> Iterator for MultiResults<'a, S> -where - S: Copy + SockaddrLike, -{ - type Item = RecvMsg<'a, 'a, S>; - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn next(&mut self) -> Option<Self::Item> { - if self.current_index >= self.received { - return None; - } - let mmsghdr = self.rmm.items[self.current_index]; - - // as long as we are not reading past the index writen by recvmmsg - address - // will be initialized - let address = unsafe { self.rmm.addresses[self.current_index].assume_init() }; - - self.current_index += 1; - Some(unsafe { - read_mhdr( - mmsghdr.msg_hdr, - mmsghdr.msg_len as isize, - self.rmm.msg_controllen, - address, - ) - }) - } -} - -impl<'a, S> RecvMsg<'_, 'a, S> { - /// Iterate over the filled io slices pointed by this msghdr - pub fn iovs(&self) -> IoSliceIterator<'a> { - IoSliceIterator { - index: 0, - remaining: self.bytes, - slices: unsafe { - // safe for as long as mgdr is properly initialized and references are valid. - // for multi messages API we initialize it with an empty - // slice and replace with a concrete buffer - // for single message API we hold a lifetime reference to ioslices - std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _) - }, - } - } -} - -#[derive(Debug)] -pub struct IoSliceIterator<'a> { - index: usize, - remaining: usize, - slices: &'a [IoSlice<'a>], -} - -impl<'a> Iterator for IoSliceIterator<'a> { - type Item = &'a [u8]; - - fn next(&mut self) -> Option<Self::Item> { - if self.index >= self.slices.len() { - return None; - } - let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())]; - self.remaining -= slice.len(); - self.index += 1; - if slice.is_empty() { - return None; - } - - Some(slice) - } -} - -// test contains both recvmmsg and timestaping which is linux only -// there are existing tests for recvmmsg only in tests/ -#[cfg(target_os = "linux")] -#[cfg(test)] -mod test { - use crate::sys::socket::{AddressFamily, ControlMessageOwned}; - use crate::*; - use std::str::FromStr; - - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recvmm2() -> crate::Result<()> { - use crate::sys::socket::{ - sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, - SockaddrIn, TimestampingFlag, - }; - use std::io::{IoSlice, IoSliceMut}; - - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); - - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - )?; - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::SOCK_NONBLOCK, - None, - )?; - - crate::sys::socket::bind(rsock, &sock_addr)?; - - setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; - - let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>(); - - let mut recv_buf = vec![0; 1024]; - - let mut recv_iovs = Vec::new(); - let mut pkt_iovs = Vec::new(); - - for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { - pkt_iovs.push(IoSliceMut::new(chunk)); - if ix % 2 == 1 { - recv_iovs.push(pkt_iovs); - pkt_iovs = Vec::new(); - } - } - drop(pkt_iovs); - - let flags = MsgFlags::empty(); - let iov1 = [IoSlice::new(&sbuf)]; - - let cmsg = cmsg_space!(crate::sys::socket::Timestamps); - sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - - let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); - - let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); - - let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; - - for rmsg in recv { - #[cfg(not(any(qemu, target_arch = "aarch64")))] - let mut saw_time = false; - let mut recvd = 0; - for cmsg in rmsg.cmsgs() { - if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { - let ts = timestamps.system; - - let sys_time = - crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; - let diff = if ts > sys_time { - ts - sys_time - } else { - sys_time - ts - }; - assert!(std::time::Duration::from(diff).as_secs() < 60); - #[cfg(not(any(qemu, target_arch = "aarch64")))] - { - saw_time = true; - } - } - } - - #[cfg(not(any(qemu, target_arch = "aarch64")))] - assert!(saw_time); - - for iov in rmsg.iovs() { - recvd += iov.len(); - } - assert_eq!(recvd, 400); - } - - Ok(()) - } -} -unsafe fn read_mhdr<'a, 'i, S>( - mhdr: msghdr, - r: isize, - msg_controllen: usize, - address: S, -) -> RecvMsg<'a, 'i, S> - where S: SockaddrLike -{ - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - let cmsghdr = { - if mhdr.msg_controllen > 0 { - debug_assert!(!mhdr.msg_control.is_null()); - debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); - CMSG_FIRSTHDR(&mhdr as *const msghdr) - } else { - ptr::null() - }.as_ref() - }; - - RecvMsg { - bytes: r as usize, - cmsghdr, - address: Some(address), - flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), - mhdr, - iobufs: std::marker::PhantomData, - } -} - -/// Pack pointers to various structures into into msghdr -/// -/// # Safety -/// `iov_buffer` and `iov_buffer_len` must point to a slice -/// of `IoSliceMut` and number of available elements or be a null pointer and 0 -/// -/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used -/// to store control headers later or be a null pointer and 0 if control -/// headers are not used -/// -/// Buffers must remain valid for the whole lifetime of msghdr -unsafe fn pack_mhdr_to_receive<S>( - iov_buffer: *const IoSliceMut, - iov_buffer_len: usize, - cmsg_buffer: *const u8, - cmsg_capacity: usize, - address: *mut S, -) -> msghdr - where - S: SockaddrLike -{ - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; - (*p).msg_namelen = S::size(); - (*p).msg_iov = iov_buffer as *mut iovec; - (*p).msg_iovlen = iov_buffer_len as _; - (*p).msg_control = cmsg_buffer as *mut c_void; - (*p).msg_controllen = cmsg_capacity as _; - (*p).msg_flags = 0; - mhdr.assume_init() -} - -fn pack_mhdr_to_send<'a, I, C, S>( - cmsg_buffer: &mut [u8], - iov: I, - cmsgs: C, - addr: Option<&S> -) -> msghdr - where - I: AsRef<[IoSlice<'a>]>, - C: AsRef<[ControlMessage<'a>]>, - S: SockaddrLike + 'a -{ - let capacity = cmsg_buffer.len(); - - // The message header must be initialized before the individual cmsgs. - let cmsg_ptr = if capacity > 0 { - cmsg_buffer.as_ptr() as *mut c_void - } else { - ptr::null_mut() - }; - - let mhdr = unsafe { - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; - (*p).msg_namelen = addr.map(S::len).unwrap_or(0); - // transmute iov into a mutable pointer. sendmsg doesn't really mutate - // the buffer, but the standard says that it takes a mutable pointer - (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; - (*p).msg_iovlen = iov.as_ref().len() as _; - (*p).msg_control = cmsg_ptr; - (*p).msg_controllen = capacity as _; - (*p).msg_flags = 0; - mhdr.assume_init() - }; - - // Encode each cmsg. This must happen after initializing the header because - // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. - // CMSG_FIRSTHDR is always safe - let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }; - for cmsg in cmsgs.as_ref() { - assert_ne!(pmhdr, ptr::null_mut()); - // Safe because we know that pmhdr is valid, and we initialized it with - // sufficient space - unsafe { cmsg.encode_into(pmhdr) }; - // Safe because mhdr is valid - pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) }; - } - - mhdr -} - -/// Receive message in scatter-gather vectors from a socket, and -/// optionally receive ancillary data into the provided buffer. -/// If no ancillary data is desired, use () as the type parameter. -/// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `iov`: Scatter-gather list of buffers to receive the message -/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by -/// [`cmsg_space!`](../../macro.cmsg_space.html) -/// * `flags`: Optional flags passed directly to the operating system. -/// -/// # References -/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], - mut cmsg_buffer: Option<&'a mut Vec<u8>>, - flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>> - where S: SockaddrLike + 'a, - 'inner: 'outer -{ - let mut address = mem::MaybeUninit::uninit(); - - let (msg_control, msg_controllen) = cmsg_buffer.as_mut() - .map(|v| (v.as_mut_ptr(), v.capacity())) - .unwrap_or((ptr::null_mut(), 0)); - let mut mhdr = unsafe { - pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) - }; - - let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; - - let r = Errno::result(ret)?; - - Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) -} -} - -/// Create an endpoint for communication -/// -/// The `protocol` specifies a particular protocol to be used with the -/// socket. Normally only a single protocol exists to support a -/// particular socket type within a given protocol family, in which case -/// protocol can be specified as `None`. However, it is possible that many -/// protocols may exist, in which case a particular protocol must be -/// specified in this manner. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) -pub fn socket<T: Into<Option<SockProtocol>>>( - domain: AddressFamily, - ty: SockType, - flags: SockFlag, - protocol: T, -) -> Result<RawFd> { - let protocol = match protocol.into() { - None => 0, - Some(p) => p as c_int, - }; - - // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a - // little easier to understand by separating it out. So we have to merge these bitfields - // here. - let mut ty = ty as c_int; - ty |= flags.bits(); - - let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; - - Errno::result(res) -} - -/// Create a pair of connected sockets -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) -pub fn socketpair<T: Into<Option<SockProtocol>>>( - domain: AddressFamily, - ty: SockType, - protocol: T, - flags: SockFlag, -) -> Result<(RawFd, RawFd)> { - let protocol = match protocol.into() { - None => 0, - Some(p) => p as c_int, - }; - - // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a - // little easier to understand by separating it out. So we have to merge these bitfields - // here. - let mut ty = ty as c_int; - ty |= flags.bits(); - - let mut fds = [-1, -1]; - - let res = unsafe { - libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) - }; - Errno::result(res)?; - - Ok((fds[0], fds[1])) -} - -/// Listen for connections on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) -pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { - let res = unsafe { libc::listen(sockfd, backlog as c_int) }; - - Errno::result(res).map(drop) -} - -/// Bind a name to a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) -pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) }; - - Errno::result(res).map(drop) -} - -/// Accept a connection on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) -pub fn accept(sockfd: RawFd) -> Result<RawFd> { - let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; - - Errno::result(res) -} - -/// Accept a connection on a socket -/// -/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) -#[cfg(any( - all( - target_os = "android", - any( - target_arch = "aarch64", - target_arch = "x86", - target_arch = "x86_64" - ) - ), - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" -))] -pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { - let res = unsafe { - libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) - }; - - Errno::result(res) -} - -/// Initiate a connection on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) -pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) }; - - Errno::result(res).map(drop) -} - -/// Receive data from a connection-oriented socket. Returns the number of -/// bytes read -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) -pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { - unsafe { - let ret = libc::recv( - sockfd, - buf.as_ptr() as *mut c_void, - buf.len() as size_t, - flags.bits(), - ); - - Errno::result(ret).map(|r| r as usize) - } -} - -/// Receive data from a connectionless or connection-oriented socket. Returns -/// the number of bytes read and, for connectionless sockets, the socket -/// address of the sender. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom<T: SockaddrLike>( - sockfd: RawFd, - buf: &mut [u8], -) -> Result<(usize, Option<T>)> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = mem::size_of_val(&addr) as socklen_t; - - let ret = Errno::result(libc::recvfrom( - sockfd, - buf.as_ptr() as *mut c_void, - buf.len() as size_t, - 0, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len as *mut socklen_t, - ))? as usize; - - Ok(( - ret, - T::from_raw( - addr.assume_init().as_ptr() as *const libc::sockaddr, - Some(len), - ), - )) - } -} - -/// Send a message to a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) -pub fn sendto( - fd: RawFd, - buf: &[u8], - addr: &dyn SockaddrLike, - flags: MsgFlags, -) -> Result<usize> { - let ret = unsafe { - libc::sendto( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - flags.bits(), - addr.as_ptr(), - addr.len(), - ) - }; - - Errno::result(ret).map(|r| r as usize) -} - -/// Send data to a connection-oriented socket. Returns the number of bytes read -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) -pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { - let ret = unsafe { - libc::send( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - flags.bits(), - ) - }; - - Errno::result(ret).map(|r| r as usize) -} - -/* - * - * ===== Socket Options ===== - * - */ - -/// Represents a socket option that can be retrieved. -pub trait GetSockOpt: Copy { - type Val; - - /// Look up the value of this socket option on the given socket. - fn get(&self, fd: RawFd) -> Result<Self::Val>; -} - -/// Represents a socket option that can be set. -pub trait SetSockOpt: Clone { - type Val; - - /// Set the value of this socket option on the given socket. - fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; -} - -/// Get the current value for the requested socket option -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) -pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { - opt.get(fd) -} - -/// Sets the value for the requested socket option -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) -/// -/// # Examples -/// -/// ``` -/// use nix::sys::socket::setsockopt; -/// use nix::sys::socket::sockopt::KeepAlive; -/// use std::net::TcpListener; -/// use std::os::unix::io::AsRawFd; -/// -/// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); -/// let fd = listener.as_raw_fd(); -/// let res = setsockopt(fd, KeepAlive, &true); -/// assert!(res.is_ok()); -/// ``` -pub fn setsockopt<O: SetSockOpt>( - fd: RawFd, - opt: O, - val: &O::Val, -) -> Result<()> { - opt.set(fd, val) -} - -/// Get the address of the peer connected to the socket `fd`. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) -pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = T::size(); - - let ret = libc::getpeername( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); - - Errno::result(ret)?; - - T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) - } -} - -/// Get the current address to which the socket `fd` is bound. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) -pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = T::size(); - - let ret = libc::getsockname( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); - - Errno::result(ret)?; - - T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) - } -} - -/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a -/// certain size. -/// -/// In C this would usually be done by casting. The `len` argument -/// should be the number of bytes in the `sockaddr_storage` that are actually -/// allocated and valid. It must be at least as large as all the useful parts -/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not -/// include the terminating null. -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(deprecated)] -pub fn sockaddr_storage_to_addr( - addr: &sockaddr_storage, - len: usize, -) -> Result<SockAddr> { - assert!(len <= mem::size_of::<sockaddr_storage>()); - if len < mem::size_of_val(&addr.ss_family) { - return Err(Errno::ENOTCONN); - } - - match c_int::from(addr.ss_family) { - #[cfg(feature = "net")] - libc::AF_INET => { - assert!(len >= mem::size_of::<sockaddr_in>()); - let sin = unsafe { - *(addr as *const sockaddr_storage as *const sockaddr_in) - }; - Ok(SockAddr::Inet(InetAddr::V4(sin))) - } - #[cfg(feature = "net")] - libc::AF_INET6 => { - assert!(len >= mem::size_of::<sockaddr_in6>()); - let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; - Ok(SockAddr::Inet(InetAddr::V6(sin6))) - } - libc::AF_UNIX => unsafe { - let sun = *(addr as *const _ as *const sockaddr_un); - let sun_len = len.try_into().unwrap(); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - libc::AF_PACKET => { - use libc::sockaddr_ll; - // Don't assert anything about the size. - // Apparently the Linux kernel can return smaller sizes when - // the value in the last element of sockaddr_ll (`sll_addr`) is - // smaller than the declared size of that field - let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; - Ok(SockAddr::Link(LinkAddr(sll))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { - use libc::sockaddr_nl; - let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; - Ok(SockAddr::Netlink(NetlinkAddr(snl))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { - use libc::sockaddr_alg; - let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; - Ok(SockAddr::Alg(AlgAddr(salg))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => { - use libc::sockaddr_vm; - let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; - Ok(SockAddr::Vsock(VsockAddr(svm))) - } - af => panic!("unexpected address family {}", af), - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Shutdown { - /// Further receptions will be disallowed. - Read, - /// Further transmissions will be disallowed. - Write, - /// Further receptions and transmissions will be disallowed. - Both, -} - -/// Shut down part of a full-duplex connection. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) -pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { - unsafe { - use libc::shutdown; - - let how = match how { - Shutdown::Read => libc::SHUT_RD, - Shutdown::Write => libc::SHUT_WR, - Shutdown::Both => libc::SHUT_RDWR, - }; - - Errno::result(shutdown(df, how)).map(drop) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn can_use_cmsg_space() { - let _ = cmsg_space!(u8); - } -} diff --git a/vendor/nix/src/sys/socket/sockopt.rs b/vendor/nix/src/sys/socket/sockopt.rs deleted file mode 100644 index 06e9ee456..000000000 --- a/vendor/nix/src/sys/socket/sockopt.rs +++ /dev/null @@ -1,1422 +0,0 @@ -//! Socket options as used by `setsockopt` and `getsockopt`. -use super::{GetSockOpt, SetSockOpt}; -use crate::errno::Errno; -use crate::sys::time::TimeVal; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int, c_void, socklen_t}; -use std::ffi::{OsStr, OsString}; -use std::{ - convert::TryFrom, - mem::{self, MaybeUninit} -}; -#[cfg(target_family = "unix")] -use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::RawFd; - -// Constants -// TCP_CA_NAME_MAX isn't defined in user space include files -#[cfg(any(target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -const TCP_CA_NAME_MAX: usize = 16; - -/// Helper for implementing `SetSockOpt` for a given socket option. See -/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). -/// -/// This macro aims to help implementing `SetSockOpt` for different socket options that accept -/// different kinds of data to be used with `setsockopt`. -/// -/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option -/// you are implementing represents a simple type. -/// -/// # Arguments -/// -/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* -/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), -/// and more. Please refer to your system manual for more options. Will be passed as the second -/// argument (`level`) to the `setsockopt` call. -/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) -/// to the `setsockopt` call. -/// * Type of the value that you are going to set. -/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for -/// `bool`, `SetUsize` for `usize`, etc.). -macro_rules! setsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { - impl SetSockOpt for $name { - type Val = $ty; - - fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { - unsafe { - let setter: $setter = Set::new(val); - - let res = libc::setsockopt( - fd, - $level, - $flag, - setter.ffi_ptr(), - setter.ffi_len(), - ); - Errno::result(res).map(drop) - } - } - } - }; -} - -/// Helper for implementing `GetSockOpt` for a given socket option. See -/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). -/// -/// This macro aims to help implementing `GetSockOpt` for different socket options that accept -/// different kinds of data to be use with `getsockopt`. -/// -/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option -/// you are implementing represents a simple type. -/// -/// # Arguments -/// -/// * Name of the type you want to implement `GetSockOpt` for. -/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip -/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer -/// to your system manual for more options. Will be passed as the second argument (`level`) to -/// the `getsockopt` call. -/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to -/// the `getsockopt` call. -/// * Type of the value that you are going to get. -/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for -/// `bool`, `GetUsize` for `usize`, etc.). -macro_rules! getsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { - impl GetSockOpt for $name { - type Val = $ty; - - fn get(&self, fd: RawFd) -> Result<$ty> { - unsafe { - let mut getter: $getter = Get::uninit(); - - let res = libc::getsockopt( - fd, - $level, - $flag, - getter.ffi_ptr(), - getter.ffi_len(), - ); - Errno::result(res)?; - - match <$ty>::try_from(getter.assume_init()) { - Err(_) => Err(Errno::EINVAL), - Ok(r) => Ok(r) - } - } - } - } - }; -} - -/// Helper to generate the sockopt accessors. See -/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and -/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). -/// -/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options -/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. -/// -/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and -/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. -/// -/// # Arguments -/// -/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or -/// both of them. -/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* -/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), -/// and more. Please refer to your system manual for more options. Will be passed as the second -/// argument (`level`) to the `getsockopt`/`setsockopt` call. -/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) -/// to the `setsockopt`/`getsockopt` call. -/// * `$ty:ty`: type of the value that will be get/set. -/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. -/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. -// Some targets don't use all rules. -#[allow(unknown_lints)] -#[allow(unused_macro_rules)] -macro_rules! sockopt_impl { - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, bool, GetBool); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, usize, GetUsize); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, bool, SetBool); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, usize, SetUsize); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, bool, GetBool, SetBool); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, u8, GetU8, SetU8); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, usize, GetUsize, SetUsize); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, - OsString<$array:ty>) => - { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, OsString, GetOsString<$array>, - SetOsString); - }; - - /* - * Matchers with generic getter types must be placed at the end, so - * they'll only match _after_ specialized matchers fail - */ - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, - $getter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - getsockopt_impl!($name, $level, $flag, $ty, $getter); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, - $setter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - setsockopt_impl!($name, $level, $flag, $ty, $setter); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, - $getter:ty, $setter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - setsockopt_impl!($name, $level, $flag, $ty, $setter); - getsockopt_impl!($name, $level, $flag, $ty, $getter); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, $ty, GetStruct<$ty>, - SetStruct<$ty>); - }; -} - -/* - * - * ===== Define sockopts ===== - * - */ - -sockopt_impl!( - /// Enables local address reuse - ReuseAddr, - Both, - libc::SOL_SOCKET, - libc::SO_REUSEADDR, - bool -); -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -sockopt_impl!( - /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an - /// identical socket address. - ReusePort, - Both, - libc::SOL_SOCKET, - libc::SO_REUSEPORT, - bool -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Under most circumstances, TCP sends data when it is presented; when - /// outstanding data has not yet been acknowledged, it gathers small amounts - /// of output to be sent in a single packet once an acknowledgement is - /// received. For a small number of clients, such as window systems that - /// send a stream of mouse events which receive no replies, this - /// packetization may cause significant delays. The boolean option - /// TCP_NODELAY defeats this algorithm. - TcpNoDelay, - Both, - libc::IPPROTO_TCP, - libc::TCP_NODELAY, - bool -); -sockopt_impl!( - /// When enabled, a close(2) or shutdown(2) will not return until all - /// queued messages for the socket have been successfully sent or the - /// linger timeout has been reached. - Linger, - Both, - libc::SOL_SOCKET, - libc::SO_LINGER, - libc::linger -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join a multicast group - IpAddMembership, - SetOnly, - libc::IPPROTO_IP, - libc::IP_ADD_MEMBERSHIP, - super::IpMembershipRequest -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave a multicast group. - IpDropMembership, - SetOnly, - libc::IPPROTO_IP, - libc::IP_DROP_MEMBERSHIP, - super::IpMembershipRequest -); -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); - } -} -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or read the time-to-live value of outgoing multicast packets for - /// this socket. - IpMulticastTtl, - Both, - libc::IPPROTO_IP, - libc::IP_MULTICAST_TTL, - u8 -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or read a boolean integer argument that determines whether sent - /// multicast packets should be looped back to the local sockets. - IpMulticastLoop, - Both, - libc::IPPROTO_IP, - libc::IP_MULTICAST_LOOP, - bool -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set the protocol-defined priority for all packets to be - /// sent on this socket - Priority, - Both, - libc::SOL_SOCKET, - libc::SO_PRIORITY, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or receive the Type-Of-Service (TOS) field that is - /// sent with every IP packet originating from this socket - IpTos, - Both, - libc::IPPROTO_IP, - libc::IP_TOS, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Traffic class associated with outgoing packets - Ipv6TClass, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_TCLASS, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// If enabled, this boolean option allows binding to an IP address that - /// is nonlocal or does not (yet) exist. - IpFreebind, - Both, - libc::IPPROTO_IP, - libc::IP_FREEBIND, - bool -); -sockopt_impl!( - /// Specify the receiving timeout until reporting an error. - ReceiveTimeout, - Both, - libc::SOL_SOCKET, - libc::SO_RCVTIMEO, - TimeVal -); -sockopt_impl!( - /// Specify the sending timeout until reporting an error. - SendTimeout, - Both, - libc::SOL_SOCKET, - libc::SO_SNDTIMEO, - TimeVal -); -sockopt_impl!( - /// Set or get the broadcast flag. - Broadcast, - Both, - libc::SOL_SOCKET, - libc::SO_BROADCAST, - bool -); -sockopt_impl!( - /// If this option is enabled, out-of-band data is directly placed into - /// the receive data stream. - OobInline, - Both, - libc::SOL_SOCKET, - libc::SO_OOBINLINE, - bool -); -sockopt_impl!( - /// Get and clear the pending socket error. - SocketError, - GetOnly, - libc::SOL_SOCKET, - libc::SO_ERROR, - i32 -); -sockopt_impl!( - /// Set or get the don't route flag. - DontRoute, - Both, - libc::SOL_SOCKET, - libc::SO_DONTROUTE, - bool -); -sockopt_impl!( - /// Enable sending of keep-alive messages on connection-oriented sockets. - KeepAlive, - Both, - libc::SOL_SOCKET, - libc::SO_KEEPALIVE, - bool -); -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] -sockopt_impl!( - /// Get the credentials of the peer process of a connected unix domain - /// socket. - LocalPeerCred, - GetOnly, - 0, - libc::LOCAL_PEERCRED, - super::XuCred -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Return the credentials of the foreign process connected to this socket. - PeerCredentials, - GetOnly, - libc::SOL_SOCKET, - libc::SO_PEERCRED, - super::UnixCredentials -); -#[cfg(any(target_os = "ios", target_os = "macos"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Specify the amount of time, in seconds, that the connection must be idle - /// before keepalive probes (if enabled) are sent. - TcpKeepAlive, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPALIVE, - u32 -); -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The time (in seconds) the connection needs to remain idle before TCP - /// starts sending keepalive probes - TcpKeepIdle, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPIDLE, - u32 -); -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } else { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } -} -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The maximum number of keepalive probes TCP should send before - /// dropping the connection. - TcpKeepCount, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPCNT, - u32 -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - TcpRepair, - Both, - libc::IPPROTO_TCP, - libc::TCP_REPAIR, - u32 -); -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The time (in seconds) between individual keepalive probes. - TcpKeepInterval, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPINTVL, - u32 -); -#[cfg(any(target_os = "fuchsia", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Specifies the maximum amount of time in milliseconds that transmitted - /// data may remain unacknowledged before TCP will forcibly close the - /// corresponding connection - TcpUserTimeout, - Both, - libc::IPPROTO_TCP, - libc::TCP_USER_TIMEOUT, - u32 -); -sockopt_impl!( - /// Sets or gets the maximum socket receive buffer in bytes. - RcvBuf, - Both, - libc::SOL_SOCKET, - libc::SO_RCVBUF, - usize -); -sockopt_impl!( - /// Sets or gets the maximum socket send buffer in bytes. - SndBuf, - Both, - libc::SOL_SOCKET, - libc::SO_SNDBUF, - usize -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be - /// overridden. - RcvBufForce, - SetOnly, - libc::SOL_SOCKET, - libc::SO_RCVBUFFORCE, - usize -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be - /// overridden. - SndBufForce, - SetOnly, - libc::SOL_SOCKET, - libc::SO_SNDBUFFORCE, - usize -); -sockopt_impl!( - /// Gets the socket type as an integer. - SockType, - GetOnly, - libc::SOL_SOCKET, - libc::SO_TYPE, - super::SockType, - GetStruct<i32> -); -sockopt_impl!( - /// Returns a value indicating whether or not this socket has been marked to - /// accept connections with `listen(2)`. - AcceptConn, - GetOnly, - libc::SOL_SOCKET, - libc::SO_ACCEPTCONN, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Bind this socket to a particular device like “eth0”. - BindToDevice, - Both, - libc::SOL_SOCKET, - libc::SO_BINDTODEVICE, - OsString<[u8; libc::IFNAMSIZ]> -); -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - OriginalDst, - GetOnly, - libc::SOL_IP, - libc::SO_ORIGINAL_DST, - libc::sockaddr_in -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - Ip6tOriginalDst, - GetOnly, - libc::SOL_IPV6, - libc::IP6T_SO_ORIGINAL_DST, - libc::sockaddr_in6 -); -#[cfg(any(target_os = "linux"))] -sockopt_impl!( - /// Specifies exact type of timestamping information collected by the kernel - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - Timestamping, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMPING, - super::TimestampingFlag -); -#[cfg(not(target_os = "haiku"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. - ReceiveTimestamp, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMP, - bool -); -#[cfg(all(target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. - ReceiveTimestampns, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMPNS, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Setting this boolean option enables transparent proxying on this socket. - IpTransparent, - Both, - libc::SOL_IP, - libc::IP_TRANSPARENT, - bool -); -#[cfg(target_os = "openbsd")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Allows the socket to be bound to addresses which are not local to the - /// machine, so it can be used to make a transparent proxy. - BindAny, - Both, - libc::SOL_SOCKET, - libc::SO_BINDANY, - bool -); -#[cfg(target_os = "freebsd")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Can `bind(2)` to any address, even one not bound to any available - /// network interface in the system. - BindAny, - Both, - libc::IPPROTO_IP, - libc::IP_BINDANY, - bool -); -#[cfg(target_os = "linux")] -sockopt_impl!( - /// Set the mark for each packet sent through this socket (similar to the - /// netfilter MARK target but socket-based). - Mark, - Both, - libc::SOL_SOCKET, - libc::SO_MARK, - u32 -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SCM_CREDENTIALS` control - /// message. - PassCred, - Both, - libc::SOL_SOCKET, - libc::SO_PASSCRED, - bool -); -#[cfg(any(target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// This option allows the caller to set the TCP congestion control - /// algorithm to be used, on a per-socket basis. - TcpCongestion, - Both, - libc::IPPROTO_TCP, - libc::TCP_CONGESTION, - OsString<[u8; TCP_CA_NAME_MAX]> -); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo - /// structure that supplies some information about the incoming packet. - Ipv4PacketInfo, - Both, - libc::IPPROTO_IP, - libc::IP_PKTINFO, - bool -); -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set delivery of the `IPV6_PKTINFO` control message on incoming - /// datagrams. - Ipv6RecvPacketInfo, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_RECVPKTINFO, - bool -); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to - /// the interface on which the packet was received. - Ipv4RecvIf, - Both, - libc::IPPROTO_IP, - libc::IP_RECVIF, - bool -); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv4RecvDstAddr, - Both, - libc::IPPROTO_IP, - libc::IP_RECVDSTADDR, - bool -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv4OrigDstAddr, - Both, - libc::IPPROTO_IP, - libc::IP_ORIGDSTADDR, - bool -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - UdpGsoSegment, - Both, - libc::SOL_UDP, - libc::UDP_SEGMENT, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - UdpGroSegment, - Both, - libc::IPPROTO_UDP, - libc::UDP_GRO, - bool -); -#[cfg(target_os = "linux")] -sockopt_impl!( - /// Configures the behavior of time-based transmission of packets, for use - /// with the `TxTime` control message. - TxTime, - Both, - libc::SOL_SOCKET, - libc::SO_TXTIME, - libc::sock_txtime -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should - /// be attached to received skbs indicating the number of packets dropped by - /// the socket since its creation. - RxqOvfl, - Both, - libc::SOL_SOCKET, - libc::SO_RXQ_OVFL, - libc::c_int -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The socket is restricted to sending and receiving IPv6 packets only. - Ipv6V6Only, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_V6ONLY, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable extended reliable error message passing. - Ipv4RecvErr, - Both, - libc::IPPROTO_IP, - libc::IP_RECVERR, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Control receiving of asynchronous error options. - Ipv6RecvErr, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_RECVERR, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Fetch the current system-estimated Path MTU. - IpMtu, - GetOnly, - libc::IPPROTO_IP, - libc::IP_MTU, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set or retrieve the current time-to-live field that is used in every - /// packet sent from this socket. - Ipv4Ttl, - Both, - libc::IPPROTO_IP, - libc::IP_TTL, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set the unicast hop limit for the socket. - Ipv6Ttl, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_UNICAST_HOPS, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv6OrigDstAddr, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_ORIGDSTADDR, - bool -); -#[cfg(any(target_os = "ios", target_os = "macos"))] -sockopt_impl!( - /// Set "don't fragment packet" flag on the IP packet. - IpDontFrag, - Both, - libc::IPPROTO_IP, - libc::IP_DONTFRAG, - bool -); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] -sockopt_impl!( - /// Set "don't fragment packet" flag on the IPv6 packet. - Ipv6DontFrag, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_DONTFRAG, - bool -); - -#[allow(missing_docs)] -// Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] -#[derive(Copy, Clone, Debug)] -pub struct AlgSetAeadAuthSize; - -// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` -// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 -#[cfg(any(target_os = "android", target_os = "linux"))] -impl SetSockOpt for AlgSetAeadAuthSize { - type Val = usize; - - fn set(&self, fd: RawFd, val: &usize) -> Result<()> { - unsafe { - let res = libc::setsockopt( - fd, - libc::SOL_ALG, - libc::ALG_SET_AEAD_AUTHSIZE, - ::std::ptr::null(), - *val as libc::socklen_t, - ); - Errno::result(res).map(drop) - } - } -} - -#[allow(missing_docs)] -// Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] -#[derive(Clone, Debug)] -pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); - -#[cfg(any(target_os = "android", target_os = "linux"))] -impl<T> Default for AlgSetKey<T> { - fn default() -> Self { - AlgSetKey(Default::default()) - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -impl<T> SetSockOpt for AlgSetKey<T> -where - T: AsRef<[u8]> + Clone, -{ - type Val = T; - - fn set(&self, fd: RawFd, val: &T) -> Result<()> { - unsafe { - let res = libc::setsockopt( - fd, - libc::SOL_ALG, - libc::ALG_SET_KEY, - val.as_ref().as_ptr() as *const _, - val.as_ref().len() as libc::socklen_t, - ); - Errno::result(res).map(drop) - } - } -} - -/* - * - * ===== Accessor helpers ===== - * - */ - -/// Helper trait that describes what is expected from a `GetSockOpt` getter. -trait Get<T> { - /// Returns an uninitialized value. - fn uninit() -> Self; - /// Returns a pointer to the stored value. This pointer will be passed to the system's - /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). - fn ffi_ptr(&mut self) -> *mut c_void; - /// Returns length of the stored value. This pointer will be passed to the system's - /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). - fn ffi_len(&mut self) -> *mut socklen_t; - /// Returns the hopefully initialized inner value. - unsafe fn assume_init(self) -> T; -} - -/// Helper trait that describes what is expected from a `SetSockOpt` setter. -trait Set<'a, T> { - /// Initialize the setter with a given value. - fn new(val: &'a T) -> Self; - /// Returns a pointer to the stored value. This pointer will be passed to the system's - /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). - fn ffi_ptr(&self) -> *const c_void; - /// Returns length of the stored value. This pointer will be passed to the system's - /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). - fn ffi_len(&self) -> socklen_t; -} - -/// Getter for an arbitrary `struct`. -struct GetStruct<T> { - len: socklen_t, - val: MaybeUninit<T>, -} - -impl<T> Get<T> for GetStruct<T> { - fn uninit() -> Self { - GetStruct { - len: mem::size_of::<T>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> T { - assert_eq!( - self.len as usize, - mem::size_of::<T>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() - } -} - -/// Setter for an arbitrary `struct`. -struct SetStruct<'a, T: 'static> { - ptr: &'a T, -} - -impl<'a, T> Set<'a, T> for SetStruct<'a, T> { - fn new(ptr: &'a T) -> SetStruct<'a, T> { - SetStruct { ptr } - } - - fn ffi_ptr(&self) -> *const c_void { - self.ptr as *const T as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<T>() as socklen_t - } -} - -/// Getter for a boolean value. -struct GetBool { - len: socklen_t, - val: MaybeUninit<c_int>, -} - -impl Get<bool> for GetBool { - fn uninit() -> Self { - GetBool { - len: mem::size_of::<c_int>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> bool { - assert_eq!( - self.len as usize, - mem::size_of::<c_int>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() != 0 - } -} - -/// Setter for a boolean value. -struct SetBool { - val: c_int, -} - -impl<'a> Set<'a, bool> for SetBool { - fn new(val: &'a bool) -> SetBool { - SetBool { - val: i32::from(*val), - } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const c_int as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for an `u8` value. -struct GetU8 { - len: socklen_t, - val: MaybeUninit<u8>, -} - -impl Get<u8> for GetU8 { - fn uninit() -> Self { - GetU8 { - len: mem::size_of::<u8>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> u8 { - assert_eq!( - self.len as usize, - mem::size_of::<u8>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() - } -} - -/// Setter for an `u8` value. -struct SetU8 { - val: u8, -} - -impl<'a> Set<'a, u8> for SetU8 { - fn new(val: &'a u8) -> SetU8 { - SetU8 { val: *val } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const u8 as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for an `usize` value. -struct GetUsize { - len: socklen_t, - val: MaybeUninit<c_int>, -} - -impl Get<usize> for GetUsize { - fn uninit() -> Self { - GetUsize { - len: mem::size_of::<c_int>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> usize { - assert_eq!( - self.len as usize, - mem::size_of::<c_int>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() as usize - } -} - -/// Setter for an `usize` value. -struct SetUsize { - val: c_int, -} - -impl<'a> Set<'a, usize> for SetUsize { - fn new(val: &'a usize) -> SetUsize { - SetUsize { val: *val as c_int } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const c_int as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for a `OsString` value. -struct GetOsString<T: AsMut<[u8]>> { - len: socklen_t, - val: MaybeUninit<T>, -} - -impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { - fn uninit() -> Self { - GetOsString { - len: mem::size_of::<T>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> OsString { - let len = self.len as usize; - let mut v = self.val.assume_init(); - OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() - } -} - -/// Setter for a `OsString` value. -struct SetOsString<'a> { - val: &'a OsStr, -} - -impl<'a> Set<'a, OsString> for SetOsString<'a> { - fn new(val: &'a OsString) -> SetOsString { - SetOsString { - val: val.as_os_str(), - } - } - - fn ffi_ptr(&self) -> *const c_void { - self.val.as_bytes().as_ptr() as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - self.val.len() as socklen_t - } -} - -#[cfg(test)] -mod test { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn can_get_peercred_on_unix_socket() { - use super::super::*; - - let (a, b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); - let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); - assert_eq!(a_cred, b_cred); - assert_ne!(a_cred.pid(), 0); - } - - #[test] - fn is_socket_type_unix() { - use super::super::*; - use crate::unistd::close; - - let (a, b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_type = getsockopt(a, super::SockType).unwrap(); - assert_eq!(a_type, SockType::Stream); - close(a).unwrap(); - close(b).unwrap(); - } - - #[test] - fn is_socket_type_dgram() { - use super::super::*; - use crate::unistd::close; - - let s = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_type = getsockopt(s, super::SockType).unwrap(); - assert_eq!(s_type, SockType::Datagram); - close(s).unwrap(); - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[test] - fn can_get_listen_on_tcp_socket() { - use super::super::*; - use crate::unistd::close; - - let s = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_listening = getsockopt(s, super::AcceptConn).unwrap(); - assert!(!s_listening); - listen(s, 10).unwrap(); - let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); - assert!(s_listening2); - close(s).unwrap(); - } -} diff --git a/vendor/nix/src/sys/stat.rs b/vendor/nix/src/sys/stat.rs deleted file mode 100644 index 78203bfbe..000000000 --- a/vendor/nix/src/sys/stat.rs +++ /dev/null @@ -1,480 +0,0 @@ -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] -pub use libc::c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] -pub use libc::c_ulong; -pub use libc::stat as FileStat; -pub use libc::{dev_t, mode_t}; - -#[cfg(not(target_os = "redox"))] -use crate::fcntl::{at_rawfd, AtFlags}; -use crate::sys::time::{TimeSpec, TimeVal}; -use crate::{errno::Errno, NixPath, Result}; -use std::mem; -use std::os::unix::io::RawFd; - -libc_bitflags!( - /// "File type" flags for `mknod` and related functions. - pub struct SFlag: mode_t { - S_IFIFO; - S_IFCHR; - S_IFDIR; - S_IFBLK; - S_IFREG; - S_IFLNK; - S_IFSOCK; - S_IFMT; - } -); - -libc_bitflags! { - /// "File mode / permissions" flags. - pub struct Mode: mode_t { - /// Read, write and execute for owner. - S_IRWXU; - /// Read for owner. - S_IRUSR; - /// Write for owner. - S_IWUSR; - /// Execute for owner. - S_IXUSR; - /// Read write and execute for group. - S_IRWXG; - /// Read fr group. - S_IRGRP; - /// Write for group. - S_IWGRP; - /// Execute for group. - S_IXGRP; - /// Read, write and execute for other. - S_IRWXO; - /// Read for other. - S_IROTH; - /// Write for other. - S_IWOTH; - /// Execute for other. - S_IXOTH; - /// Set user id on execution. - S_ISUID as mode_t; - /// Set group id on execution. - S_ISGID as mode_t; - S_ISVTX as mode_t; - } -} - -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] -pub type type_of_file_flag = c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] -pub type type_of_file_flag = c_ulong; - -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] -libc_bitflags! { - /// File flags. - #[cfg_attr(docsrs, doc(cfg(all())))] - pub struct FileFlag: type_of_file_flag { - /// The file may only be appended to. - SF_APPEND; - /// The file has been archived. - SF_ARCHIVED; - #[cfg(any(target_os = "dragonfly"))] - SF_CACHE; - /// The file may not be changed. - SF_IMMUTABLE; - /// Indicates a WAPBL journal file. - #[cfg(any(target_os = "netbsd"))] - SF_LOG; - /// Do not retain history for file - #[cfg(any(target_os = "dragonfly"))] - SF_NOHISTORY; - /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - SF_NOUNLINK; - /// Mask of superuser changeable flags - SF_SETTABLE; - /// Snapshot is invalid. - #[cfg(any(target_os = "netbsd"))] - SF_SNAPINVAL; - /// The file is a snapshot file. - #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - SF_SNAPSHOT; - #[cfg(any(target_os = "dragonfly"))] - SF_XLINK; - /// The file may only be appended to. - UF_APPEND; - /// The file needs to be archived. - #[cfg(any(target_os = "freebsd"))] - UF_ARCHIVE; - #[cfg(any(target_os = "dragonfly"))] - UF_CACHE; - /// File is compressed at the file system level. - #[cfg(any(target_os = "macos", target_os = "ios"))] - UF_COMPRESSED; - /// The file may be hidden from directory listings at the application's - /// discretion. - #[cfg(any( - target_os = "freebsd", - target_os = "macos", - target_os = "ios", - ))] - UF_HIDDEN; - /// The file may not be changed. - UF_IMMUTABLE; - /// Do not dump the file. - UF_NODUMP; - #[cfg(any(target_os = "dragonfly"))] - UF_NOHISTORY; - /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - UF_NOUNLINK; - /// The file is offline, or has the Windows and CIFS - /// `FILE_ATTRIBUTE_OFFLINE` attribute. - #[cfg(any(target_os = "freebsd"))] - UF_OFFLINE; - /// The directory is opaque when viewed through a union stack. - UF_OPAQUE; - /// The file is read only, and may not be written or appended. - #[cfg(any(target_os = "freebsd"))] - UF_READONLY; - /// The file contains a Windows reparse point. - #[cfg(any(target_os = "freebsd"))] - UF_REPARSE; - /// Mask of owner changeable flags. - UF_SETTABLE; - /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. - #[cfg(any(target_os = "freebsd"))] - UF_SPARSE; - /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` - /// attribute. - #[cfg(any(target_os = "freebsd"))] - UF_SYSTEM; - /// File renames and deletes are tracked. - #[cfg(any(target_os = "macos", target_os = "ios"))] - UF_TRACKED; - #[cfg(any(target_os = "dragonfly"))] - UF_XLINK; - } -} - -/// Create a special or ordinary file, by pathname. -pub fn mknod<P: ?Sized + NixPath>( - path: &P, - kind: SFlag, - perm: Mode, - dev: dev_t, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) - })?; - - Errno::result(res).map(drop) -} - -/// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mknodat<P: ?Sized + NixPath>( - dirfd: RawFd, - path: &P, - kind: SFlag, - perm: Mode, - dev: dev_t, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknodat( - dirfd, - cstr.as_ptr(), - kind.bits | perm.bits() as mode_t, - dev, - ) - })?; - - Errno::result(res).map(drop) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn major(dev: dev_t) -> u64 { - ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn minor(dev: dev_t) -> u64 { - ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn makedev(major: u64, minor: u64) -> dev_t { - ((major & 0xffff_f000) << 32) - | ((major & 0x0000_0fff) << 8) - | ((minor & 0xffff_ff00) << 12) - | (minor & 0x0000_00ff) -} - -pub fn umask(mode: Mode) -> Mode { - let prev = unsafe { libc::umask(mode.bits() as mode_t) }; - Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") -} - -pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| unsafe { - libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| unsafe { - libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -pub fn fstat(fd: RawFd) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat<P: ?Sized + NixPath>( - dirfd: RawFd, - pathname: &P, - f: AtFlags, -) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = pathname.with_nix_path(|cstr| unsafe { - libc::fstatat( - dirfd, - cstr.as_ptr(), - dst.as_mut_ptr(), - f.bits() as libc::c_int, - ) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -/// Change the file permission bits of the file specified by a file descriptor. -/// -/// # References -/// -/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). -pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { - let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; - - Errno::result(res).map(drop) -} - -/// Flags for `fchmodat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchmodatFlags { - FollowSymlink, - NoFollowSymlink, -} - -/// Change the file permission bits. -/// -/// The file to be changed is determined relative to the directory associated -/// with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. -/// -/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, -/// then the mode of the symbolic link is changed. -/// -/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to -/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented -/// in the `nix` crate. -/// -/// # References -/// -/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fchmodat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - mode: Mode, - flag: FchmodatFlags, -) -> Result<()> { - let atflag = match flag { - FchmodatFlags::FollowSymlink => AtFlags::empty(), - FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - let res = path.with_nix_path(|cstr| unsafe { - libc::fchmodat( - at_rawfd(dirfd), - cstr.as_ptr(), - mode.bits() as mode_t, - atflag.bits() as libc::c_int, - ) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of a file. -/// -/// `utimes(path, times)` is identical to -/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former -/// is a deprecated API so prefer using the latter if the platforms you care -/// about support it. -/// -/// # References -/// -/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). -pub fn utimes<P: ?Sized + NixPath>( - path: &P, - atime: &TimeVal, - mtime: &TimeVal, -) -> Result<()> { - let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::utimes(cstr.as_ptr(), ×[0]) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of a file without following symlinks. -/// -/// `lutimes(path, times)` is identical to -/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former -/// is a deprecated API so prefer using the latter if the platforms you care -/// about support it. -/// -/// # References -/// -/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). -#[cfg(any( - target_os = "linux", - target_os = "haiku", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn lutimes<P: ?Sized + NixPath>( - path: &P, - atime: &TimeVal, - mtime: &TimeVal, -) -> Result<()> { - let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::lutimes(cstr.as_ptr(), ×[0]) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of the file specified by a file descriptor. -/// -/// # References -/// -/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). -#[inline] -pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { - let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = unsafe { libc::futimens(fd, ×[0]) }; - - Errno::result(res).map(drop) -} - -/// Flags for `utimensat` function. -// TODO: replace with fcntl::AtFlags -#[derive(Clone, Copy, Debug)] -pub enum UtimensatFlags { - FollowSymlink, - NoFollowSymlink, -} - -/// Change the access and modification times of a file. -/// -/// The file to be changed is determined relative to the directory associated -/// with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. -/// -/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, -/// then the mode of the symbolic link is changed. -/// -/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to -/// `utimes(path, times)`. The latter is a deprecated API so prefer using the -/// former if the platforms you care about support it. -/// -/// # References -/// -/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn utimensat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - atime: &TimeSpec, - mtime: &TimeSpec, - flag: UtimensatFlags, -) -> Result<()> { - let atflag = match flag { - UtimensatFlags::FollowSymlink => AtFlags::empty(), - UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::utimensat( - at_rawfd(dirfd), - cstr.as_ptr(), - ×[0], - atflag.bits() as libc::c_int, - ) - })?; - - Errno::result(res).map(drop) -} - -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat<P: ?Sized + NixPath>( - fd: RawFd, - path: &P, - mode: Mode, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) - })?; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/sys/statfs.rs b/vendor/nix/src/sys/statfs.rs deleted file mode 100644 index 9be8ca666..000000000 --- a/vendor/nix/src/sys/statfs.rs +++ /dev/null @@ -1,853 +0,0 @@ -//! Get filesystem statistics, non-portably -//! -//! See [`statvfs`](crate::sys::statvfs) for a portable alternative. -#[cfg(not(any(target_os = "linux", target_os = "android")))] -use std::ffi::CStr; -use std::fmt::{self, Debug}; -use std::mem; -use std::os::unix::io::AsRawFd; - -use cfg_if::cfg_if; - -#[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) -))] -use crate::mount::MntFlags; -#[cfg(target_os = "linux")] -use crate::sys::statvfs::FsFlags; -use crate::{errno::Errno, NixPath, Result}; - -/// Identifies a mounted file system -#[cfg(target_os = "android")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type fsid_t = libc::__fsid_t; -/// Identifies a mounted file system -#[cfg(not(target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type fsid_t = libc::fsid_t; - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { - type type_of_statfs = libc::statfs64; - const LIBC_FSTATFS: unsafe extern fn - (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int - = libc::fstatfs64; - const LIBC_STATFS: unsafe extern fn - (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int - = libc::statfs64; - } else { - type type_of_statfs = libc::statfs; - const LIBC_FSTATFS: unsafe extern fn - (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int - = libc::fstatfs; - const LIBC_STATFS: unsafe extern fn - (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int - = libc::statfs; - } -} - -/// Describes a mounted file system -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct Statfs(type_of_statfs); - -#[cfg(target_os = "freebsd")] -type fs_type_t = u32; -#[cfg(target_os = "android")] -type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_arch = "s390x"))] -type fs_type_t = libc::c_uint; -#[cfg(all(target_os = "linux", target_env = "musl"))] -type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_env = "uclibc"))] -type fs_type_t = libc::c_int; -#[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) -))] -type fs_type_t = libc::__fsword_t; - -/// Describes the file system type as known by the operating system. -#[cfg(any( - target_os = "freebsd", - target_os = "android", - all(target_os = "linux", target_arch = "s390x"), - all(target_os = "linux", target_env = "musl"), - all( - target_os = "linux", - not(any(target_arch = "s390x", target_env = "musl")) - ), -))] -#[derive(Eq, Copy, Clone, PartialEq, Debug)] -pub struct FsType(pub fs_type_t); - -// These constants are defined without documentation in the Linux headers, so we -// can't very well document them here. -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ADFS_SUPER_MAGIC: FsType = - FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AFFS_SUPER_MAGIC: FsType = - FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AUTOFS_SUPER_MAGIC: FsType = - FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const BTRFS_SUPER_MAGIC: FsType = - FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CGROUP2_SUPER_MAGIC: FsType = - FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CGROUP_SUPER_MAGIC: FsType = - FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CODA_SUPER_MAGIC: FsType = - FsType(libc::CODA_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const DEVPTS_SUPER_MAGIC: FsType = - FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ECRYPTFS_SUPER_MAGIC: FsType = - FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT2_SUPER_MAGIC: FsType = - FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT3_SUPER_MAGIC: FsType = - FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT4_SUPER_MAGIC: FsType = - FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const F2FS_SUPER_MAGIC: FsType = - FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const FUSE_SUPER_MAGIC: FsType = - FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const FUTEXFS_SUPER_MAGIC: FsType = - FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HOSTFS_SUPER_MAGIC: FsType = - FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HPFS_SUPER_MAGIC: FsType = - FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ISOFS_SUPER_MAGIC: FsType = - FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const JFFS2_SUPER_MAGIC: FsType = - FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC2: FsType = - FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC: FsType = - FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX3_SUPER_MAGIC: FsType = - FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC2: FsType = - FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC: FsType = - FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MSDOS_SUPER_MAGIC: FsType = - FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NILFS_SUPER_MAGIC: FsType = - FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OCFS2_SUPER_MAGIC: FsType = - FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OPENPROM_SUPER_MAGIC: FsType = - FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OVERLAYFS_SUPER_MAGIC: FsType = - FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const PROC_SUPER_MAGIC: FsType = - FsType(libc::PROC_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const QNX4_SUPER_MAGIC: FsType = - FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const QNX6_SUPER_MAGIC: FsType = - FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const RDTGROUP_SUPER_MAGIC: FsType = - FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const REISERFS_SUPER_MAGIC: FsType = - FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SECURITYFS_MAGIC: FsType = - FsType(libc::SECURITYFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const USBDEVICE_SUPER_MAGIC: FsType = - FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const XENFS_SUPER_MAGIC: FsType = - FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); -#[cfg(all( - any(target_os = "linux", target_os = "android"), - not(target_env = "musl") -))] -#[allow(missing_docs)] -pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); - -impl Statfs { - /// Magic code defining system type - #[cfg(not(any( - target_os = "openbsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn filesystem_type(&self) -> FsType { - FsType(self.0.f_type) - } - - /// Magic code defining system type - #[cfg(not(any(target_os = "linux", target_os = "android")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn filesystem_type_name(&self) -> &str { - let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; - c_str.to_str().unwrap() - } - - /// Optimal transfer block size - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> i32 { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u32 { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u32 { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(any( - target_os = "android", - all(target_os = "linux", target_env = "musl") - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::__fsword_t { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_int { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_long { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u64 { - self.0.f_iosize - } - - /// Size of a block - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u32 { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u32 { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_int { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::__fsword_t { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u64 { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_long { - self.0.f_bsize - } - - /// Get the mount flags - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches - pub fn flags(&self) -> MntFlags { - MntFlags::from_bits_truncate(self.0.f_flags as i32) - } - - /// Get the mount flags - // The f_flags field exists on Android and Fuchsia too, but without man - // pages I can't tell if it can be cast to FsFlags. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn flags(&self) -> FsFlags { - FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) - } - - /// Maximum length of filenames - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> u32 { - self.0.f_namemax - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> u32 { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_ulong { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_int { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::__fsword_t { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_ulong { - self.0.f_namelen - } - - /// Total data blocks in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u64 { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> libc::c_long { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u32 { - self.0.f_blocks - } - - /// Free blocks in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u64 { - self.0.f_bfree - } - - /// Free blocks in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> libc::c_long { - self.0.f_bfree - } - - /// Free blocks in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u32 { - self.0.f_bfree - } - - /// Free blocks available to unprivileged user - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "fuchsia", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> libc::c_long { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> i64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u32 { - self.0.f_bavail - } - - /// Total file nodes in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> u64 { - self.0.f_files - } - - /// Total file nodes in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::c_long { - self.0.f_files - } - - /// Total file nodes in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> u32 { - self.0.f_files - } - - /// Free file nodes in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> u64 { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::c_long { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> i64 { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> u32 { - self.0.f_ffree - } - - /// Filesystem ID - pub fn filesystem_id(&self) -> fsid_t { - self.0.f_fsid - } -} - -impl Debug for Statfs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut ds = f.debug_struct("Statfs"); - ds.field("optimal_transfer_size", &self.optimal_transfer_size()); - ds.field("block_size", &self.block_size()); - ds.field("blocks", &self.blocks()); - ds.field("blocks_free", &self.blocks_free()); - ds.field("blocks_available", &self.blocks_available()); - ds.field("files", &self.files()); - ds.field("files_free", &self.files_free()); - ds.field("filesystem_id", &self.filesystem_id()); - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] - ds.field("flags", &self.flags()); - ds.finish() - } -} - -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portable alternative, see -/// [`statvfs`](crate::sys::statvfs::statvfs). -/// -/// # Arguments -/// -/// `path` - Path to any file within the file system to describe -pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { - unsafe { - let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); - let res = path.with_nix_path(|path| { - LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()) - })?; - Errno::result(res).map(|_| Statfs(stat.assume_init())) - } -} - -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portable alternative, see -/// [`fstatvfs`](crate::sys::statvfs::fstatvfs). -/// -/// # Arguments -/// -/// `fd` - File descriptor of any open file within the file system to describe -pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { - unsafe { - let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); - Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) - .map(|_| Statfs(stat.assume_init())) - } -} - -#[cfg(test)] -mod test { - use std::fs::File; - - use crate::sys::statfs::*; - use crate::sys::statvfs::*; - use std::path::Path; - - #[test] - fn statfs_call() { - check_statfs("/tmp"); - check_statfs("/dev"); - check_statfs("/run"); - check_statfs("/"); - } - - #[test] - fn fstatfs_call() { - check_fstatfs("/tmp"); - check_fstatfs("/dev"); - check_fstatfs("/run"); - check_fstatfs("/"); - } - - fn check_fstatfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file).unwrap(); - assert_fs_equals(fs, vfs); - } - - fn check_statfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let fs = statfs(path.as_bytes()).unwrap(); - assert_fs_equals(fs, vfs); - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // statfs call. - #[test] - #[ignore] - fn statfs_call_strict() { - check_statfs_strict("/tmp"); - check_statfs_strict("/dev"); - check_statfs_strict("/run"); - check_statfs_strict("/"); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // fstatfs call. - #[test] - #[ignore] - fn fstatfs_call_strict() { - check_fstatfs_strict("/tmp"); - check_fstatfs_strict("/dev"); - check_fstatfs_strict("/run"); - check_fstatfs_strict("/"); - } - - fn check_fstatfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - fn check_statfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let fs = statfs(path.as_bytes()); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); - assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); - assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } -} diff --git a/vendor/nix/src/sys/statvfs.rs b/vendor/nix/src/sys/statvfs.rs deleted file mode 100644 index 8de369f42..000000000 --- a/vendor/nix/src/sys/statvfs.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Get filesystem statistics -//! -//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) -//! for more details. -use std::mem; -use std::os::unix::io::AsRawFd; - -use libc::{self, c_ulong}; - -use crate::{errno::Errno, NixPath, Result}; - -#[cfg(not(target_os = "redox"))] -libc_bitflags!( - /// File system mount Flags - #[repr(C)] - #[derive(Default)] - pub struct FsFlags: c_ulong { - /// Read Only - #[cfg(not(target_os = "haiku"))] - ST_RDONLY; - /// Do not allow the set-uid bits to have an effect - #[cfg(not(target_os = "haiku"))] - ST_NOSUID; - /// Do not interpret character or block-special devices - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NODEV; - /// Do not allow execution of binaries on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NOEXEC; - /// All IO should be done synchronously - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_SYNCHRONOUS; - /// Allow mandatory locks on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_MANDLOCK; - /// Write on file/directory/symlink - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_WRITE; - /// Append-only file - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_APPEND; - /// Immutable file - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_IMMUTABLE; - /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NOATIME; - /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NODIRATIME; - /// Update access time relative to modify/change time - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_RELATIME; - } -); - -/// Wrapper around the POSIX `statvfs` struct -/// -/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Statvfs(libc::statvfs); - -impl Statvfs { - /// get the file system block size - pub fn block_size(&self) -> c_ulong { - self.0.f_bsize - } - - /// Get the fundamental file system block size - pub fn fragment_size(&self) -> c_ulong { - self.0.f_frsize - } - - /// Get the number of blocks. - /// - /// Units are in units of `fragment_size()` - pub fn blocks(&self) -> libc::fsblkcnt_t { - self.0.f_blocks - } - - /// Get the number of free blocks in the file system - pub fn blocks_free(&self) -> libc::fsblkcnt_t { - self.0.f_bfree - } - - /// Get the number of free blocks for unprivileged users - pub fn blocks_available(&self) -> libc::fsblkcnt_t { - self.0.f_bavail - } - - /// Get the total number of file inodes - pub fn files(&self) -> libc::fsfilcnt_t { - self.0.f_files - } - - /// Get the number of free file inodes - pub fn files_free(&self) -> libc::fsfilcnt_t { - self.0.f_ffree - } - - /// Get the number of free file inodes for unprivileged users - pub fn files_available(&self) -> libc::fsfilcnt_t { - self.0.f_favail - } - - /// Get the file system id - pub fn filesystem_id(&self) -> c_ulong { - self.0.f_fsid - } - - /// Get the mount flags - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn flags(&self) -> FsFlags { - FsFlags::from_bits_truncate(self.0.f_flag) - } - - /// Get the maximum filename length - pub fn name_max(&self) -> c_ulong { - self.0.f_namemax - } -} - -/// Return a `Statvfs` object with information about the `path` -pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> { - unsafe { - Errno::clear(); - let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); - let res = path.with_nix_path(|path| { - libc::statvfs(path.as_ptr(), stat.as_mut_ptr()) - })?; - - Errno::result(res).map(|_| Statvfs(stat.assume_init())) - } -} - -/// Return a `Statvfs` object with information about `fd` -pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> { - unsafe { - Errno::clear(); - let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); - Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr())) - .map(|_| Statvfs(stat.assume_init())) - } -} - -#[cfg(test)] -mod test { - use crate::sys::statvfs::*; - use std::fs::File; - - #[test] - fn statvfs_call() { - statvfs(&b"/"[..]).unwrap(); - } - - #[test] - fn fstatvfs_call() { - let root = File::open("/").unwrap(); - fstatvfs(&root).unwrap(); - } -} diff --git a/vendor/nix/src/sys/sysinfo.rs b/vendor/nix/src/sys/sysinfo.rs deleted file mode 100644 index e8aa00b00..000000000 --- a/vendor/nix/src/sys/sysinfo.rs +++ /dev/null @@ -1,83 +0,0 @@ -use libc::{self, SI_LOAD_SHIFT}; -use std::time::Duration; -use std::{cmp, mem}; - -use crate::errno::Errno; -use crate::Result; - -/// System info structure returned by `sysinfo`. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct SysInfo(libc::sysinfo); - -// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -type mem_blocks_t = u64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -type mem_blocks_t = libc::c_ulong; - -impl SysInfo { - /// Returns the load average tuple. - /// - /// The returned values represent the load average over time intervals of - /// 1, 5, and 15 minutes, respectively. - pub fn load_average(&self) -> (f64, f64, f64) { - ( - self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64, - self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64, - self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64, - ) - } - - /// Returns the time since system boot. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn uptime(&self) -> Duration { - // Truncate negative values to 0 - Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) - } - - /// Current number of processes. - pub fn process_count(&self) -> u16 { - self.0.procs - } - - /// Returns the amount of swap memory in Bytes. - pub fn swap_total(&self) -> u64 { - self.scale_mem(self.0.totalswap) - } - - /// Returns the amount of unused swap memory in Bytes. - pub fn swap_free(&self) -> u64 { - self.scale_mem(self.0.freeswap) - } - - /// Returns the total amount of installed RAM in Bytes. - pub fn ram_total(&self) -> u64 { - self.scale_mem(self.0.totalram) - } - - /// Returns the amount of completely unused RAM in Bytes. - /// - /// "Unused" in this context means that the RAM in neither actively used by - /// programs, nor by the operating system as disk cache or buffer. It is - /// "wasted" RAM since it currently serves no purpose. - pub fn ram_unused(&self) -> u64 { - self.scale_mem(self.0.freeram) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn scale_mem(&self, units: mem_blocks_t) -> u64 { - units as u64 * self.0.mem_unit as u64 - } -} - -/// Returns system information. -/// -/// [See `sysinfo(2)`](https://man7.org/linux/man-pages/man2/sysinfo.2.html). -pub fn sysinfo() -> Result<SysInfo> { - let mut info = mem::MaybeUninit::uninit(); - let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe { SysInfo(info.assume_init()) }) -} diff --git a/vendor/nix/src/sys/termios.rs b/vendor/nix/src/sys/termios.rs deleted file mode 100644 index fba2cd826..000000000 --- a/vendor/nix/src/sys/termios.rs +++ /dev/null @@ -1,1227 +0,0 @@ -//! An interface for controlling asynchronous communication ports -//! -//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The -//! underlying types are all implemented in libc for most platforms and either wrapped in safer -//! types here or exported directly. -//! -//! If you are unfamiliar with the `termios` API, you should first read the -//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and -//! then come back to understand how `nix` safely wraps it. -//! -//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. -//! As this interface is not used with high-bandwidth information, this should be fine in most -//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the -//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields. -//! This means that when crossing the FFI interface to the underlying C library, data is first -//! copied into the underlying `termios` struct, then the operation is done, and the data is copied -//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is -//! relatively small across all platforms (on the order of 32-64 bytes). -//! -//! The following examples highlight some of the API use cases such that users coming from using C -//! or reading the standard documentation will understand how to use the safe API exposed here. -//! -//! Example disabling processing of the end-of-file control character: -//! -//! ``` -//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF; -//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios}; -//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; -//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE; -//! ``` -//! -//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides -//! an interface for working with bitfields that is similar to working with the raw unsigned -//! integer types but offers type safety because of the internal checking that values will always -//! be a valid combination of the defined flags. -//! -//! An example showing some of the basic operations for interacting with the control flags: -//! -//! ``` -//! # use self::nix::sys::termios::{ControlFlags, Termios}; -//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; -//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5; -//! termios.control_flags |= ControlFlags::CS5; -//! ``` -//! -//! # Baud rates -//! -//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both -//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs -//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer -//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following -//! conventions: -//! -//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux -//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! -//! The most common use case of specifying a baud rate using the enum will work the same across -//! platforms: -//! -//! ```rust -//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! cfsetispeed(&mut t, BaudRate::B9600).unwrap(); -//! cfsetospeed(&mut t, BaudRate::B9600).unwrap(); -//! cfsetspeed(&mut t, BaudRate::B9600).unwrap(); -//! # } -//! ``` -//! -//! Additionally round-tripping baud rates is consistent across platforms: -//! -//! ```rust -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap(); -//! let speed = cfgetispeed(&t); -//! assert_eq!(speed, cfgetospeed(&t)); -//! cfsetispeed(&mut t, speed).unwrap(); -//! # } -//! ``` -//! -//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust,ignore" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, BaudRate::B9600); -//! assert_eq!(cfgetispeed(&t), BaudRate::B9600); -//! assert_eq!(cfgetospeed(&t), BaudRate::B9600); -//! # } -//! ``` -//! -//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, 9600u32); -//! assert_eq!(cfgetispeed(&t), 9600u32); -//! assert_eq!(cfgetospeed(&t), 9600u32); -//! # } -//! ``` -//! -//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, 9600u32); -//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into()); -//! assert_eq!(u32::from(BaudRate::B9600), 9600u32); -//! # } -//! ``` -//! -//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) -//! by specifying baud rates directly using `u32`s: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! cfsetispeed(&mut t, 9600u32); -//! cfsetospeed(&mut t, 9600u32); -//! cfsetspeed(&mut t, 9600u32); -//! # } -//! ``` -use crate::errno::Errno; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int, tcflag_t}; -use std::cell::{Ref, RefCell}; -use std::convert::From; -use std::mem; -use std::os::unix::io::RawFd; - -#[cfg(feature = "process")] -use crate::unistd::Pid; - -/// Stores settings for the termios API -/// -/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the -/// standard fields. The only safe way to obtain an instance of this struct is to extract it from -/// an open port using `tcgetattr()`. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Termios { - inner: RefCell<libc::termios>, - /// Input mode flags (see `termios.c_iflag` documentation) - pub input_flags: InputFlags, - /// Output mode flags (see `termios.c_oflag` documentation) - pub output_flags: OutputFlags, - /// Control mode flags (see `termios.c_cflag` documentation) - pub control_flags: ControlFlags, - /// Local mode flags (see `termios.c_lflag` documentation) - pub local_flags: LocalFlags, - /// Control characters (see `termios.c_cc` documentation) - pub control_chars: [libc::cc_t; NCCS], - /// Line discipline (see `termios.c_line` documentation) - #[cfg(any(target_os = "linux", target_os = "android",))] - pub line_discipline: libc::cc_t, - /// Line discipline (see `termios.c_line` documentation) - #[cfg(target_os = "haiku")] - pub line_discipline: libc::c_char, -} - -impl Termios { - /// Exposes an immutable reference to the underlying `libc::termios` data structure. - /// - /// This is not part of `nix`'s public API because it requires additional work to maintain type - /// safety. - pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - termios.c_line = self.line_discipline; - } - } - self.inner.borrow() - } - - /// Exposes the inner `libc::termios` datastore within `Termios`. - /// - /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will - /// not automatically update the safe wrapper type around it. In this case it should also be - /// paired with a call to `update_wrapper()` so that the wrapper-type and internal - /// representation stay consistent. - pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - termios.c_line = self.line_discipline; - } - } - self.inner.as_ptr() - } - - /// Updates the wrapper values from the internal `libc::termios` data structure. - pub(crate) fn update_wrapper(&mut self) { - let termios = *self.inner.borrow_mut(); - self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); - self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); - self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); - self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); - self.control_chars = termios.c_cc; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - self.line_discipline = termios.c_line; - } - } -} - -impl From<libc::termios> for Termios { - fn from(termios: libc::termios) -> Self { - Termios { - inner: RefCell::new(termios), - input_flags: InputFlags::from_bits_truncate(termios.c_iflag), - output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), - control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), - local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), - control_chars: termios.c_cc, - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - line_discipline: termios.c_line, - } - } -} - -impl From<Termios> for libc::termios { - fn from(termios: Termios) -> Self { - termios.inner.into_inner() - } -} - -libc_enum! { - /// Baud rates supported by the system. - /// - /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this - /// enum. - /// - /// B0 is special and will disable the port. - #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] - #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] - #[non_exhaustive] - pub enum BaudRate { - B0, - B50, - B75, - B110, - B134, - B150, - B200, - B300, - B600, - B1200, - B1800, - B2400, - B4800, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B7200, - B9600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B14400, - B19200, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B28800, - B38400, - B57600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B76800, - B115200, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B153600, - B230400, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B307200, - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B460800, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B576000, - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B921600, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1000000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1152000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B2000000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B2500000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B3000000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B3500000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B4000000, - } - impl TryFrom<libc::speed_t> -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -impl From<BaudRate> for u32 { - fn from(b: BaudRate) -> u32 { - b as u32 - } -} - -#[cfg(target_os = "haiku")] -impl From<BaudRate> for u8 { - fn from(b: BaudRate) -> u8 { - b as u8 - } -} - -// TODO: Add TCSASOFT, which will require treating this as a bitfield. -libc_enum! { - /// Specify when a port configuration change should occur. - /// - /// Used as an argument to `tcsetattr()` - #[repr(i32)] - #[non_exhaustive] - pub enum SetArg { - /// The change will occur immediately - TCSANOW, - /// The change occurs after all output has been written - TCSADRAIN, - /// Same as `TCSADRAIN`, but will also flush the input buffer - TCSAFLUSH, - } -} - -libc_enum! { - /// Specify a combination of the input and output buffers to flush - /// - /// Used as an argument to `tcflush()`. - #[repr(i32)] - #[non_exhaustive] - pub enum FlushArg { - /// Flush data that was received but not read - TCIFLUSH, - /// Flush data written but not transmitted - TCOFLUSH, - /// Flush both received data not read and written data not transmitted - TCIOFLUSH, - } -} - -libc_enum! { - /// Specify how transmission flow should be altered - /// - /// Used as an argument to `tcflow()`. - #[repr(i32)] - #[non_exhaustive] - pub enum FlowArg { - /// Suspend transmission - TCOOFF, - /// Resume transmission - TCOON, - /// Transmit a STOP character, which should disable a connected terminal device - TCIOFF, - /// Transmit a START character, which should re-enable a connected terminal device - TCION, - } -} - -// TODO: Make this usable directly as a slice index. -#[cfg(not(target_os = "haiku"))] -libc_enum! { - /// Indices into the `termios.c_cc` array for special characters. - #[repr(usize)] - #[non_exhaustive] - pub enum SpecialCharacterIndices { - VDISCARD, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VDSUSP, - VEOF, - VEOL, - VEOL2, - VERASE, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VERASE2, - VINTR, - VKILL, - VLNEXT, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VMIN, - VQUIT, - VREPRINT, - VSTART, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSTATUS, - VSTOP, - VSUSP, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSWTC, - #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSWTCH, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VTIME, - VWERASE, - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - VCHECKPT, - } -} - -#[cfg(any( - all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", - target_os = "solaris" -))] -impl SpecialCharacterIndices { - pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; - pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; -} - -pub use libc::NCCS; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub use libc::_POSIX_VDISABLE; - -libc_bitflags! { - /// Flags for configuring the input mode of a terminal - pub struct InputFlags: tcflag_t { - IGNBRK; - BRKINT; - IGNPAR; - PARMRK; - INPCK; - ISTRIP; - INLCR; - IGNCR; - ICRNL; - IXON; - IXOFF; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IXANY; - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IMAXBEL; - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IUTF8; - } -} - -libc_bitflags! { - /// Flags for configuring the output mode of a terminal - pub struct OutputFlags: tcflag_t { - OPOST; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "linux", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OLCUC; - ONLCR; - OCRNL as tcflag_t; - ONOCR as tcflag_t; - ONLRET as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OFILL as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OFDEL as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NL0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NL1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR2 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR3 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB2 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB3 as tcflag_t; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - XTABS; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BS0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BS1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VT0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VT1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FF0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FF1 as tcflag_t; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OXTABS; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ONOEOT as tcflag_t; - - // Bitmasks for use with OutputFlags to select specific settings - // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 - // is resolved. - - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TABDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BSDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VTDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FFDLY as tcflag_t; - } -} - -libc_bitflags! { - /// Flags for setting the control mode of a terminal - pub struct ControlFlags: tcflag_t { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CIGNORE; - CS5; - CS6; - CS7; - CS8; - CSTOPB; - CREAD; - PARENB; - PARODD; - HUPCL; - CLOCAL; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRTSCTS; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CBAUD; - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CMSPAR; - #[cfg(any(target_os = "android", - all(target_os = "linux", - not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] - CIBAUD; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CBAUDEX; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MDMBUF; - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CHWFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CCTS_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRTS_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CDTR_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CDSR_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CCAR_OFLOW; - - // Bitmasks for use with ControlFlags to select specific settings - // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 - // is resolved. - - CSIZE; - } -} - -libc_bitflags! { - /// Flags for setting any local modes - pub struct LocalFlags: tcflag_t { - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOKE; - ECHOE; - ECHOK; - ECHO; - ECHONL; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOPRT; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOCTL; - ISIG; - ICANON; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ALTWERASE; - IEXTEN; - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - EXTPROC; - TOSTOP; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FLUSHO; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NOKERNINFO; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PENDIN; - NOFLSH; - } -} - -cfg_if! { - if #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { - /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). - /// - /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn cfgetispeed(termios: &Termios) -> u32 { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) as u32 } - } - - /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). - /// - /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn cfgetospeed(termios: &Termios) -> u32 { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) as u32 } - } - - /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). - /// - /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. - pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). - /// - /// `cfsetospeed()` sets the output baud rate in the given termios structure. - pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set both the input and output baud rates (see - /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). - /// - /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that - /// this is part of the 4.4BSD standard and not part of POSIX. - pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - } else { - use std::convert::TryInto; - - /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). - /// - /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. - pub fn cfgetispeed(termios: &Termios) -> BaudRate { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap() - } - - /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). - /// - /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. - pub fn cfgetospeed(termios: &Termios) -> BaudRate { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap() - } - - /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). - /// - /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. - pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). - /// - /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. - pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set both the input and output baud rates (see - /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). - /// - /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that - /// this is part of the 4.4BSD standard and not part of POSIX. - #[cfg(not(target_os = "haiku"))] - pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - } -} - -/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see -/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)). -/// -/// `cfmakeraw()` configures the termios structure such that input is available character-by- -/// character, echoing is disabled, and all special input and output processing is disabled. Note -/// that this is a non-standard function, but is available on Linux and BSDs. -pub fn cfmakeraw(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - unsafe { - libc::cfmakeraw(inner_termios); - } - termios.update_wrapper(); -} - -/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see -/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)). -/// -/// Note that this is a non-standard function, available on FreeBSD. -#[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn cfmakesane(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - unsafe { - libc::cfmakesane(inner_termios); - } - termios.update_wrapper(); -} - -/// Return the configuration of a port -/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). -/// -/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying -/// this structure *will not* reconfigure the port, instead the modifications should be done to -/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. -pub fn tcgetattr(fd: RawFd) -> Result<Termios> { - let mut termios = mem::MaybeUninit::uninit(); - - let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; - - Errno::result(res)?; - - unsafe { Ok(termios.assume_init().into()) } -} - -/// Set the configuration for a terminal (see -/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). -/// -/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change -/// takes affect at a time specified by `actions`. Note that this function may return success if -/// *any* of the parameters were successfully set, not only if all were set successfully. -pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { - let inner_termios = termios.get_libc_termios(); - Errno::result(unsafe { - libc::tcsetattr(fd, actions as c_int, &*inner_termios) - }) - .map(drop) -} - -/// Block until all output data is written (see -/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). -pub fn tcdrain(fd: RawFd) -> Result<()> { - Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) -} - -/// Suspend or resume the transmission or reception of data (see -/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). -/// -/// `tcflow()` suspends of resumes the transmission or reception of data for the given port -/// depending on the value of `action`. -pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { - Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) -} - -/// Discard data in the output or input queue (see -/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). -/// -/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both -/// depending on the value of `action`. -pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { - Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) -} - -/// Send a break for a specific duration (see -/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). -/// -/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream -/// of zero-valued bits for an implementation-defined duration. -pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { - Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) -} - -feature! { -#![feature = "process"] -/// Get the session controlled by the given terminal (see -/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). -pub fn tcgetsid(fd: RawFd) -> Result<Pid> { - let res = unsafe { libc::tcgetsid(fd) }; - - Errno::result(res).map(Pid::from_raw) -} -} - -#[cfg(test)] -mod test { - use super::*; - use std::convert::TryFrom; - - #[test] - fn try_from() { - assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); - #[cfg(not(target_os = "haiku"))] - BaudRate::try_from(999999999).expect_err("assertion failed"); - #[cfg(target_os = "haiku")] - BaudRate::try_from(99).expect_err("assertion failed"); - } -} diff --git a/vendor/nix/src/sys/time.rs b/vendor/nix/src/sys/time.rs deleted file mode 100644 index 0042c4508..000000000 --- a/vendor/nix/src/sys/time.rs +++ /dev/null @@ -1,811 +0,0 @@ -#[cfg_attr(target_env = "musl", allow(deprecated))] -// https://github.com/rust-lang/libc/issues/1848 -pub use libc::{suseconds_t, time_t}; -use libc::{timespec, timeval}; -use std::convert::From; -use std::time::Duration; -use std::{cmp, fmt, ops}; - -const fn zero_init_timespec() -> timespec { - // `std::mem::MaybeUninit::zeroed()` is not yet a const fn - // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of - // the appropriate size to zero and then transmute it to a timespec value. - unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) } -} - -#[cfg(any( - all(feature = "time", any(target_os = "android", target_os = "linux")), - all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" - ) -))] -pub(crate) mod timer { - use crate::sys::time::{zero_init_timespec, TimeSpec}; - use bitflags::bitflags; - - #[derive(Debug, Clone, Copy)] - pub(crate) struct TimerSpec(libc::itimerspec); - - impl TimerSpec { - pub const fn none() -> Self { - Self(libc::itimerspec { - it_interval: zero_init_timespec(), - it_value: zero_init_timespec(), - }) - } - } - - impl AsMut<libc::itimerspec> for TimerSpec { - fn as_mut(&mut self) -> &mut libc::itimerspec { - &mut self.0 - } - } - - impl AsRef<libc::itimerspec> for TimerSpec { - fn as_ref(&self) -> &libc::itimerspec { - &self.0 - } - } - - impl From<Expiration> for TimerSpec { - fn from(expiration: Expiration) -> TimerSpec { - match expiration { - Expiration::OneShot(t) => TimerSpec(libc::itimerspec { - it_interval: zero_init_timespec(), - it_value: *t.as_ref(), - }), - Expiration::IntervalDelayed(start, interval) => { - TimerSpec(libc::itimerspec { - it_interval: *interval.as_ref(), - it_value: *start.as_ref(), - }) - } - Expiration::Interval(t) => TimerSpec(libc::itimerspec { - it_interval: *t.as_ref(), - it_value: *t.as_ref(), - }), - } - } - } - - /// An enumeration allowing the definition of the expiration time of an alarm, - /// recurring or not. - #[derive(Debug, Clone, Copy, Eq, PartialEq)] - pub enum Expiration { - /// Alarm will trigger once after the time given in `TimeSpec` - OneShot(TimeSpec), - /// Alarm will trigger after a specified delay and then every interval of - /// time. - IntervalDelayed(TimeSpec, TimeSpec), - /// Alarm will trigger every specified interval of time. - Interval(TimeSpec), - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - bitflags! { - /// Flags that are used for arming the timer. - pub struct TimerSetTimeFlags: libc::c_int { - const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; - } - } - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" - ))] - bitflags! { - /// Flags that are used for arming the timer. - pub struct TimerSetTimeFlags: libc::c_int { - const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; - } - } - - impl From<TimerSpec> for Expiration { - fn from(timerspec: TimerSpec) -> Expiration { - match timerspec { - TimerSpec(libc::itimerspec { - it_interval: - libc::timespec { - tv_sec: 0, - tv_nsec: 0, - .. - }, - it_value: ts, - }) => Expiration::OneShot(ts.into()), - TimerSpec(libc::itimerspec { - it_interval: int_ts, - it_value: val_ts, - }) => { - if (int_ts.tv_sec == val_ts.tv_sec) - && (int_ts.tv_nsec == val_ts.tv_nsec) - { - Expiration::Interval(int_ts.into()) - } else { - Expiration::IntervalDelayed( - val_ts.into(), - int_ts.into(), - ) - } - } - } - } - } -} - -pub trait TimeValLike: Sized { - #[inline] - fn zero() -> Self { - Self::seconds(0) - } - - #[inline] - fn hours(hours: i64) -> Self { - let secs = hours - .checked_mul(SECS_PER_HOUR) - .expect("TimeValLike::hours ouf of bounds"); - Self::seconds(secs) - } - - #[inline] - fn minutes(minutes: i64) -> Self { - let secs = minutes - .checked_mul(SECS_PER_MINUTE) - .expect("TimeValLike::minutes out of bounds"); - Self::seconds(secs) - } - - fn seconds(seconds: i64) -> Self; - fn milliseconds(milliseconds: i64) -> Self; - fn microseconds(microseconds: i64) -> Self; - fn nanoseconds(nanoseconds: i64) -> Self; - - #[inline] - fn num_hours(&self) -> i64 { - self.num_seconds() / 3600 - } - - #[inline] - fn num_minutes(&self) -> i64 { - self.num_seconds() / 60 - } - - fn num_seconds(&self) -> i64; - fn num_milliseconds(&self) -> i64; - fn num_microseconds(&self) -> i64; - fn num_nanoseconds(&self) -> i64; -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct TimeSpec(timespec); - -const NANOS_PER_SEC: i64 = 1_000_000_000; -const SECS_PER_MINUTE: i64 = 60; -const SECS_PER_HOUR: i64 = 3600; - -#[cfg(target_pointer_width = "64")] -const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; - -#[cfg(target_pointer_width = "32")] -const TS_MAX_SECONDS: i64 = isize::MAX as i64; - -const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; - -// x32 compatibility -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -type timespec_tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -type timespec_tv_nsec_t = libc::c_long; - -impl From<timespec> for TimeSpec { - fn from(ts: timespec) -> Self { - Self(ts) - } -} - -impl From<Duration> for TimeSpec { - fn from(duration: Duration) -> Self { - Self::from_duration(duration) - } -} - -impl From<TimeSpec> for Duration { - fn from(timespec: TimeSpec) -> Self { - Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) - } -} - -impl AsRef<timespec> for TimeSpec { - fn as_ref(&self) -> ×pec { - &self.0 - } -} - -impl AsMut<timespec> for TimeSpec { - fn as_mut(&mut self) -> &mut timespec { - &mut self.0 - } -} - -impl Ord for TimeSpec { - // The implementation of cmp is simplified by assuming that the struct is - // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) - fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { - if self.tv_sec() == other.tv_sec() { - self.tv_nsec().cmp(&other.tv_nsec()) - } else { - self.tv_sec().cmp(&other.tv_sec()) - } - } -} - -impl PartialOrd for TimeSpec { - fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl TimeValLike for TimeSpec { - #[inline] - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - fn seconds(seconds: i64) -> TimeSpec { - assert!( - (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), - "TimeSpec out of bounds; seconds={}", - seconds - ); - let mut ts = zero_init_timespec(); - ts.tv_sec = seconds as time_t; - TimeSpec(ts) - } - - #[inline] - fn milliseconds(milliseconds: i64) -> TimeSpec { - let nanoseconds = milliseconds - .checked_mul(1_000_000) - .expect("TimeSpec::milliseconds out of bounds"); - - TimeSpec::nanoseconds(nanoseconds) - } - - /// Makes a new `TimeSpec` with given number of microseconds. - #[inline] - fn microseconds(microseconds: i64) -> TimeSpec { - let nanoseconds = microseconds - .checked_mul(1_000) - .expect("TimeSpec::milliseconds out of bounds"); - - TimeSpec::nanoseconds(nanoseconds) - } - - /// Makes a new `TimeSpec` with given number of nanoseconds. - #[inline] - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - fn nanoseconds(nanoseconds: i64) -> TimeSpec { - let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); - assert!( - (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), - "TimeSpec out of bounds" - ); - let mut ts = zero_init_timespec(); - ts.tv_sec = secs as time_t; - ts.tv_nsec = nanos as timespec_tv_nsec_t; - TimeSpec(ts) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_seconds(&self) -> i64 { - if self.tv_sec() < 0 && self.tv_nsec() > 0 { - (self.tv_sec() + 1) as i64 - } else { - self.tv_sec() as i64 - } - } - - fn num_milliseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000_000 - } - - fn num_microseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000 - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_nanoseconds(&self) -> i64 { - let secs = self.num_seconds() * 1_000_000_000; - let nsec = self.nanos_mod_sec(); - secs + nsec as i64 - } -} - -impl TimeSpec { - /// Construct a new `TimeSpec` from its components - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { - let mut ts = zero_init_timespec(); - ts.tv_sec = seconds; - ts.tv_nsec = nanoseconds; - Self(ts) - } - - fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { - if self.tv_sec() < 0 && self.tv_nsec() > 0 { - self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t - } else { - self.tv_nsec() - } - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { - self.0.tv_sec - } - - pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { - self.0.tv_nsec - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - pub const fn from_duration(duration: Duration) -> Self { - let mut ts = zero_init_timespec(); - ts.tv_sec = duration.as_secs() as time_t; - ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; - TimeSpec(ts) - } - - pub const fn from_timespec(timespec: timespec) -> Self { - Self(timespec) - } -} - -impl ops::Neg for TimeSpec { - type Output = TimeSpec; - - fn neg(self) -> TimeSpec { - TimeSpec::nanoseconds(-self.num_nanoseconds()) - } -} - -impl ops::Add for TimeSpec { - type Output = TimeSpec; - - fn add(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) - } -} - -impl ops::Sub for TimeSpec { - type Output = TimeSpec; - - fn sub(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) - } -} - -impl ops::Mul<i32> for TimeSpec { - type Output = TimeSpec; - - fn mul(self, rhs: i32) -> TimeSpec { - let usec = self - .num_nanoseconds() - .checked_mul(i64::from(rhs)) - .expect("TimeSpec multiply out of bounds"); - - TimeSpec::nanoseconds(usec) - } -} - -impl ops::Div<i32> for TimeSpec { - type Output = TimeSpec; - - fn div(self, rhs: i32) -> TimeSpec { - let usec = self.num_nanoseconds() / i64::from(rhs); - TimeSpec::nanoseconds(usec) - } -} - -impl fmt::Display for TimeSpec { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (abs, sign) = if self.tv_sec() < 0 { - (-*self, "-") - } else { - (*self, "") - }; - - let sec = abs.tv_sec(); - - write!(f, "{}", sign)?; - - if abs.tv_nsec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; - } else { - write!(f, "{} seconds", sec)?; - } - } else if abs.tv_nsec() % 1_000_000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; - } else if abs.tv_nsec() % 1_000 == 0 { - write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; - } else { - write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; - } - - Ok(()) - } -} - -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct TimeVal(timeval); - -const MICROS_PER_SEC: i64 = 1_000_000; - -#[cfg(target_pointer_width = "64")] -const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; - -#[cfg(target_pointer_width = "32")] -const TV_MAX_SECONDS: i64 = isize::MAX as i64; - -const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; - -impl AsRef<timeval> for TimeVal { - fn as_ref(&self) -> &timeval { - &self.0 - } -} - -impl AsMut<timeval> for TimeVal { - fn as_mut(&mut self) -> &mut timeval { - &mut self.0 - } -} - -impl Ord for TimeVal { - // The implementation of cmp is simplified by assuming that the struct is - // normalized. That is, tv_usec must always be within [0, 1_000_000) - fn cmp(&self, other: &TimeVal) -> cmp::Ordering { - if self.tv_sec() == other.tv_sec() { - self.tv_usec().cmp(&other.tv_usec()) - } else { - self.tv_sec().cmp(&other.tv_sec()) - } - } -} - -impl PartialOrd for TimeVal { - fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl TimeValLike for TimeVal { - #[inline] - fn seconds(seconds: i64) -> TimeVal { - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), - "TimeVal out of bounds; seconds={}", - seconds - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: seconds as time_t, - tv_usec: 0, - }) - } - - #[inline] - fn milliseconds(milliseconds: i64) -> TimeVal { - let microseconds = milliseconds - .checked_mul(1_000) - .expect("TimeVal::milliseconds out of bounds"); - - TimeVal::microseconds(microseconds) - } - - /// Makes a new `TimeVal` with given number of microseconds. - #[inline] - fn microseconds(microseconds: i64) -> TimeVal { - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds" - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: secs as time_t, - tv_usec: micros as suseconds_t, - }) - } - - /// Makes a new `TimeVal` with given number of nanoseconds. Some precision - /// will be lost - #[inline] - fn nanoseconds(nanoseconds: i64) -> TimeVal { - let microseconds = nanoseconds / 1000; - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds" - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: secs as time_t, - tv_usec: micros as suseconds_t, - }) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_seconds(&self) -> i64 { - if self.tv_sec() < 0 && self.tv_usec() > 0 { - (self.tv_sec() + 1) as i64 - } else { - self.tv_sec() as i64 - } - } - - fn num_milliseconds(&self) -> i64 { - self.num_microseconds() / 1_000 - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_microseconds(&self) -> i64 { - let secs = self.num_seconds() * 1_000_000; - let usec = self.micros_mod_sec(); - secs + usec as i64 - } - - fn num_nanoseconds(&self) -> i64 { - self.num_microseconds() * 1_000 - } -} - -impl TimeVal { - /// Construct a new `TimeVal` from its components - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { - Self(timeval { - tv_sec: seconds, - tv_usec: microseconds, - }) - } - - fn micros_mod_sec(&self) -> suseconds_t { - if self.tv_sec() < 0 && self.tv_usec() > 0 { - self.tv_usec() - MICROS_PER_SEC as suseconds_t - } else { - self.tv_usec() - } - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { - self.0.tv_sec - } - - pub const fn tv_usec(&self) -> suseconds_t { - self.0.tv_usec - } -} - -impl ops::Neg for TimeVal { - type Output = TimeVal; - - fn neg(self) -> TimeVal { - TimeVal::microseconds(-self.num_microseconds()) - } -} - -impl ops::Add for TimeVal { - type Output = TimeVal; - - fn add(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) - } -} - -impl ops::Sub for TimeVal { - type Output = TimeVal; - - fn sub(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) - } -} - -impl ops::Mul<i32> for TimeVal { - type Output = TimeVal; - - fn mul(self, rhs: i32) -> TimeVal { - let usec = self - .num_microseconds() - .checked_mul(i64::from(rhs)) - .expect("TimeVal multiply out of bounds"); - - TimeVal::microseconds(usec) - } -} - -impl ops::Div<i32> for TimeVal { - type Output = TimeVal; - - fn div(self, rhs: i32) -> TimeVal { - let usec = self.num_microseconds() / i64::from(rhs); - TimeVal::microseconds(usec) - } -} - -impl fmt::Display for TimeVal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (abs, sign) = if self.tv_sec() < 0 { - (-*self, "-") - } else { - (*self, "") - }; - - let sec = abs.tv_sec(); - - write!(f, "{}", sign)?; - - if abs.tv_usec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; - } else { - write!(f, "{} seconds", sec)?; - } - } else if abs.tv_usec() % 1000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; - } else { - write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; - } - - Ok(()) - } -} - -impl From<timeval> for TimeVal { - fn from(tv: timeval) -> Self { - TimeVal(tv) - } -} - -#[inline] -fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, - r => r, - } -} - -#[inline] -fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) -} - -#[cfg(test)] -mod test { - use super::{TimeSpec, TimeVal, TimeValLike}; - use std::time::Duration; - - #[test] - pub fn test_timespec() { - assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); - assert_eq!( - TimeSpec::seconds(1) + TimeSpec::seconds(2), - TimeSpec::seconds(3) - ); - assert_eq!( - TimeSpec::minutes(3) + TimeSpec::seconds(2), - TimeSpec::seconds(182) - ); - } - - #[test] - pub fn test_timespec_from() { - let duration = Duration::new(123, 123_456_789); - let timespec = TimeSpec::nanoseconds(123_123_456_789); - - assert_eq!(TimeSpec::from(duration), timespec); - assert_eq!(Duration::from(timespec), duration); - } - - #[test] - pub fn test_timespec_neg() { - let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); - let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timespec_ord() { - assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); - assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); - assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); - assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); - assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); - } - - #[test] - pub fn test_timespec_fmt() { - assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); - assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!( - TimeSpec::nanoseconds(42).to_string(), - "0.000000042 seconds" - ); - assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); - } - - #[test] - pub fn test_timeval() { - assert_ne!(TimeVal::seconds(1), TimeVal::zero()); - assert_eq!( - TimeVal::seconds(1) + TimeVal::seconds(2), - TimeVal::seconds(3) - ); - assert_eq!( - TimeVal::minutes(3) + TimeVal::seconds(2), - TimeVal::seconds(182) - ); - } - - #[test] - pub fn test_timeval_ord() { - assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); - assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); - assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); - assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); - assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); - } - - #[test] - pub fn test_timeval_neg() { - let a = TimeVal::seconds(1) + TimeVal::microseconds(123); - let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timeval_fmt() { - assert_eq!(TimeVal::zero().to_string(), "0 seconds"); - assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); - assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); - } -} diff --git a/vendor/nix/src/sys/timer.rs b/vendor/nix/src/sys/timer.rs deleted file mode 100644 index e1a34051e..000000000 --- a/vendor/nix/src/sys/timer.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Timer API via signals. -//! -//! Timer is a POSIX API to create timers and get expiration notifications -//! through queued Unix signals, for the current process. This is similar to -//! Linux's timerfd mechanism, except that API is specific to Linux and makes -//! use of file polling. -//! -//! For more documentation, please read [timer_create](https://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html). -//! -//! # Examples -//! -//! Create an interval timer that signals SIGALARM every 250 milliseconds. -//! -//! ```no_run -//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal}; -//! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; -//! use nix::time::ClockId; -//! use std::convert::TryFrom; -//! use std::sync::atomic::{AtomicU64, Ordering}; -//! use std::thread::yield_now; -//! use std::time::Duration; -//! -//! const SIG: Signal = Signal::SIGALRM; -//! static ALARMS: AtomicU64 = AtomicU64::new(0); -//! -//! extern "C" fn handle_alarm(signal: libc::c_int) { -//! let signal = Signal::try_from(signal).unwrap(); -//! if signal == SIG { -//! ALARMS.fetch_add(1, Ordering::Relaxed); -//! } -//! } -//! -//! fn main() { -//! let clockid = ClockId::CLOCK_MONOTONIC; -//! let sigevent = SigEvent::new(SigevNotify::SigevSignal { -//! signal: SIG, -//! si_value: 0, -//! }); -//! -//! let mut timer = Timer::new(clockid, sigevent).unwrap(); -//! let expiration = Expiration::Interval(Duration::from_millis(250).into()); -//! let flags = TimerSetTimeFlags::empty(); -//! timer.set(expiration, flags).expect("could not set timer"); -//! -//! let handler = SigHandler::Handler(handle_alarm); -//! unsafe { signal::signal(SIG, handler) }.unwrap(); -//! -//! loop { -//! let alarms = ALARMS.load(Ordering::Relaxed); -//! if alarms >= 10 { -//! println!("total alarms handled: {}", alarms); -//! break; -//! } -//! yield_now() -//! } -//! } -//! ``` -use crate::sys::signal::SigEvent; -use crate::sys::time::timer::TimerSpec; -pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; -use crate::time::ClockId; -use crate::{errno::Errno, Result}; -use core::mem; - -/// A Unix signal per-process timer. -#[derive(Debug)] -#[repr(transparent)] -pub struct Timer(libc::timer_t); - -impl Timer { - /// Creates a new timer based on the clock defined by `clockid`. The details - /// of the signal and its handler are defined by the passed `sigevent`. - #[doc(alias("timer_create"))] - pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result<Self> { - let mut timer_id: mem::MaybeUninit<libc::timer_t> = - mem::MaybeUninit::uninit(); - Errno::result(unsafe { - libc::timer_create( - clockid.as_raw(), - sigevent.as_mut_ptr(), - timer_id.as_mut_ptr(), - ) - }) - .map(|_| { - // SAFETY: libc::timer_create is responsible for initializing - // timer_id. - unsafe { Self(timer_id.assume_init()) } - }) - } - - /// Set a new alarm on the timer. - /// - /// # Types of alarm - /// - /// There are 3 types of alarms you can set: - /// - /// - one shot: the alarm will trigger once after the specified amount of - /// time. - /// Example: I want an alarm to go off in 60s and then disable itself. - /// - /// - interval: the alarm will trigger every specified interval of time. - /// Example: I want an alarm to go off every 60s. The alarm will first - /// go off 60s after I set it and every 60s after that. The alarm will - /// not disable itself. - /// - /// - interval delayed: the alarm will trigger after a certain amount of - /// time and then trigger at a specified interval. - /// Example: I want an alarm to go off every 60s but only start in 1h. - /// The alarm will first trigger 1h after I set it and then every 60s - /// after that. The alarm will not disable itself. - /// - /// # Relative vs absolute alarm - /// - /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass - /// to the `Expiration` you want is relative. If however you want an alarm - /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. - /// Then the one shot TimeSpec and the delay TimeSpec of the delayed - /// interval are going to be interpreted as absolute. - /// - /// # Disabling alarms - /// - /// Note: Only one alarm can be set for any given timer. Setting a new alarm - /// actually removes the previous one. - /// - /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm - /// altogether. - #[doc(alias("timer_settime"))] - pub fn set( - &mut self, - expiration: Expiration, - flags: TimerSetTimeFlags, - ) -> Result<()> { - let timerspec: TimerSpec = expiration.into(); - Errno::result(unsafe { - libc::timer_settime( - self.0, - flags.bits(), - timerspec.as_ref(), - core::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Get the parameters for the alarm currently set, if any. - #[doc(alias("timer_gettime"))] - pub fn get(&self) -> Result<Option<Expiration>> { - let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { - libc::timer_gettime(self.0, timerspec.as_mut()) - }) - .map(|_| { - if timerspec.as_ref().it_interval.tv_sec == 0 - && timerspec.as_ref().it_interval.tv_nsec == 0 - && timerspec.as_ref().it_value.tv_sec == 0 - && timerspec.as_ref().it_value.tv_nsec == 0 - { - None - } else { - Some(timerspec.into()) - } - }) - } - - /// Return the number of timers that have overrun - /// - /// Each timer is able to queue one signal to the process at a time, meaning - /// if the signal is not handled before the next expiration the timer has - /// 'overrun'. This function returns how many times that has happened to - /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum - /// number of overruns have happened the return is capped to the maximum. - #[doc(alias("timer_getoverrun"))] - pub fn overruns(&self) -> i32 { - unsafe { libc::timer_getoverrun(self.0) } - } -} - -impl Drop for Timer { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::timer_delete(self.0) }); - if let Err(Errno::EINVAL) = result { - panic!("close of Timer encountered EINVAL"); - } - } - } -} diff --git a/vendor/nix/src/sys/timerfd.rs b/vendor/nix/src/sys/timerfd.rs deleted file mode 100644 index a35fc927f..000000000 --- a/vendor/nix/src/sys/timerfd.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! Timer API via file descriptors. -//! -//! Timer FD is a Linux-only API to create timers and get expiration -//! notifications through file descriptors. -//! -//! For more documentation, please read [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). -//! -//! # Examples -//! -//! Create a new one-shot timer that expires after 1 second. -//! ``` -//! # use std::os::unix::io::AsRawFd; -//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags, -//! # Expiration}; -//! # use nix::sys::time::{TimeSpec, TimeValLike}; -//! # use nix::unistd::read; -//! # -//! // We create a new monotonic timer. -//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()) -//! .unwrap(); -//! -//! // We set a new one-shot timer in 1 seconds. -//! timer.set( -//! Expiration::OneShot(TimeSpec::seconds(1)), -//! TimerSetTimeFlags::empty() -//! ).unwrap(); -//! -//! // We wait for the timer to expire. -//! timer.wait().unwrap(); -//! ``` -use crate::sys::time::timer::TimerSpec; -pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; -use crate::unistd::read; -use crate::{errno::Errno, Result}; -use libc::c_int; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; - -/// A timerfd instance. This is also a file descriptor, you can feed it to -/// other interfaces consuming file descriptors, epoll for example. -#[derive(Debug)] -pub struct TimerFd { - fd: RawFd, -} - -impl AsRawFd for TimerFd { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl FromRawFd for TimerFd { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - TimerFd { fd } - } -} - -libc_enum! { - /// The type of the clock used to mark the progress of the timer. For more - /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). - #[repr(i32)] - #[non_exhaustive] - pub enum ClockId { - /// A settable system-wide real-time clock. - CLOCK_REALTIME, - /// A non-settable monotonically increasing clock. - /// - /// Does not change after system startup. - /// Does not measure time while the system is suspended. - CLOCK_MONOTONIC, - /// Like `CLOCK_MONOTONIC`, except that `CLOCK_BOOTTIME` includes the time - /// that the system was suspended. - CLOCK_BOOTTIME, - /// Like `CLOCK_REALTIME`, but will wake the system if it is suspended. - CLOCK_REALTIME_ALARM, - /// Like `CLOCK_BOOTTIME`, but will wake the system if it is suspended. - CLOCK_BOOTTIME_ALARM, - } -} - -libc_bitflags! { - /// Additional flags to change the behaviour of the file descriptor at the - /// time of creation. - pub struct TimerFlags: c_int { - /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. - TFD_NONBLOCK; - /// Set the `FD_CLOEXEC` flag on the file descriptor. - TFD_CLOEXEC; - } -} - -impl TimerFd { - /// Creates a new timer based on the clock defined by `clockid`. The - /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, - /// NONBLOCK). The underlying fd will be closed on drop. - #[doc(alias("timerfd_create"))] - pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> { - Errno::result(unsafe { - libc::timerfd_create(clockid as i32, flags.bits()) - }) - .map(|fd| Self { fd }) - } - - /// Sets a new alarm on the timer. - /// - /// # Types of alarm - /// - /// There are 3 types of alarms you can set: - /// - /// - one shot: the alarm will trigger once after the specified amount of - /// time. - /// Example: I want an alarm to go off in 60s and then disable itself. - /// - /// - interval: the alarm will trigger every specified interval of time. - /// Example: I want an alarm to go off every 60s. The alarm will first - /// go off 60s after I set it and every 60s after that. The alarm will - /// not disable itself. - /// - /// - interval delayed: the alarm will trigger after a certain amount of - /// time and then trigger at a specified interval. - /// Example: I want an alarm to go off every 60s but only start in 1h. - /// The alarm will first trigger 1h after I set it and then every 60s - /// after that. The alarm will not disable itself. - /// - /// # Relative vs absolute alarm - /// - /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass - /// to the `Expiration` you want is relative. If however you want an alarm - /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. - /// Then the one shot TimeSpec and the delay TimeSpec of the delayed - /// interval are going to be interpreted as absolute. - /// - /// # Disabling alarms - /// - /// Note: Only one alarm can be set for any given timer. Setting a new alarm - /// actually removes the previous one. - /// - /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm - /// altogether. - #[doc(alias("timerfd_settime"))] - pub fn set( - &self, - expiration: Expiration, - flags: TimerSetTimeFlags, - ) -> Result<()> { - let timerspec: TimerSpec = expiration.into(); - Errno::result(unsafe { - libc::timerfd_settime( - self.fd, - flags.bits(), - timerspec.as_ref(), - std::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Get the parameters for the alarm currently set, if any. - #[doc(alias("timerfd_gettime"))] - pub fn get(&self) -> Result<Option<Expiration>> { - let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { - libc::timerfd_gettime(self.fd, timerspec.as_mut()) - }) - .map(|_| { - if timerspec.as_ref().it_interval.tv_sec == 0 - && timerspec.as_ref().it_interval.tv_nsec == 0 - && timerspec.as_ref().it_value.tv_sec == 0 - && timerspec.as_ref().it_value.tv_nsec == 0 - { - None - } else { - Some(timerspec.into()) - } - }) - } - - /// Remove the alarm if any is set. - #[doc(alias("timerfd_settime"))] - pub fn unset(&self) -> Result<()> { - Errno::result(unsafe { - libc::timerfd_settime( - self.fd, - TimerSetTimeFlags::empty().bits(), - TimerSpec::none().as_ref(), - std::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Wait for the configured alarm to expire. - /// - /// Note: If the alarm is unset, then you will wait forever. - pub fn wait(&self) -> Result<()> { - while let Err(e) = read(self.fd, &mut [0u8; 8]) { - if e != Errno::EINTR { - return Err(e); - } - } - - Ok(()) - } -} - -impl Drop for TimerFd { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::close(self.fd) }); - if let Err(Errno::EBADF) = result { - panic!("close of TimerFd encountered EBADF"); - } - } - } -} diff --git a/vendor/nix/src/sys/uio.rs b/vendor/nix/src/sys/uio.rs deleted file mode 100644 index b31c3068a..000000000 --- a/vendor/nix/src/sys/uio.rs +++ /dev/null @@ -1,291 +0,0 @@ -//! Vectored I/O - -use crate::errno::Errno; -use crate::Result; -use libc::{self, c_int, c_void, off_t, size_t}; -use std::io::{IoSlice, IoSliceMut}; -use std::marker::PhantomData; -use std::os::unix::io::RawFd; - -/// Low-level vectored write to a raw file descriptor -/// -/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) -pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> { - // SAFETY: to quote the documentation for `IoSlice`: - // - // [IoSlice] is semantically a wrapper around a &[u8], but is - // guaranteed to be ABI compatible with the iovec type on Unix - // platforms. - // - // Because it is ABI compatible, a pointer cast here is valid - let res = unsafe { - libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level vectored read from a raw file descriptor -/// -/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) -pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { - // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec - let res = unsafe { - libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Write to `fd` at `offset` from buffers in `iov`. -/// -/// Buffers in `iov` will be written in order until all buffers have been written -/// or an error occurs. The file offset is not changed. -/// -/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> { - #[cfg(target_env = "uclibc")] - let offset = offset as libc::off64_t; // uclibc doesn't use off_t - - // SAFETY: same as in writev() - let res = unsafe { - libc::pwritev( - fd, - iov.as_ptr() as *const libc::iovec, - iov.len() as c_int, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Read from `fd` at `offset` filling buffers in `iov`. -/// -/// Buffers in `iov` will be filled in order until all buffers have been filled, -/// no more bytes are available, or an error occurs. The file offset is not -/// changed. -/// -/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv( - fd: RawFd, - iov: &mut [IoSliceMut<'_>], - offset: off_t, -) -> Result<usize> { - #[cfg(target_env = "uclibc")] - let offset = offset as libc::off64_t; // uclibc doesn't use off_t - - // SAFETY: same as in readv() - let res = unsafe { - libc::preadv( - fd, - iov.as_ptr() as *const libc::iovec, - iov.len() as c_int, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level write to a file, with specified offset. -/// -/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) -// TODO: move to unistd -pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { - let res = unsafe { - libc::pwrite( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level read from a file, with specified offset. -/// -/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) -// TODO: move to unistd -pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> { - let res = unsafe { - libc::pread( - fd, - buf.as_mut_ptr() as *mut c_void, - buf.len() as size_t, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// A slice of memory in a remote process, starting at address `base` -/// and consisting of `len` bytes. -/// -/// This is the same underlying C structure as `IoSlice`, -/// except that it refers to memory in some other process, and is -/// therefore not represented in Rust by an actual slice as `IoSlice` is. It -/// is used with [`process_vm_readv`](fn.process_vm_readv.html) -/// and [`process_vm_writev`](fn.process_vm_writev.html). -#[cfg(any(target_os = "linux", target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct RemoteIoVec { - /// The starting address of this slice (`iov_base`). - pub base: usize, - /// The number of bytes in this slice (`iov_len`). - pub len: usize, -} - -/// A vector of buffers. -/// -/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for -/// both reading and writing. Each `IoVec` specifies the base address and -/// length of an area in memory. -#[deprecated( - since = "0.24.0", - note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" -)] -#[repr(transparent)] -#[allow(renamed_and_removed_lints)] -#[allow(clippy::unknown_clippy_lints)] -// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>); - -#[allow(deprecated)] -impl<T> IoVec<T> { - /// View the `IoVec` as a Rust slice. - #[deprecated( - since = "0.24.0", - note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" - )] - #[inline] - pub fn as_slice(&self) -> &[u8] { - use std::slice; - - unsafe { - slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) - } - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a [u8]> { - /// Create an `IoVec` from a Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] - pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { - IoVec( - libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a mut [u8]> { - /// Create an `IoVec` from a mutable Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] - pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { - IoVec( - libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -// The only reason IoVec isn't automatically Send+Sync is because libc::iovec -// contains raw pointers. -#[allow(deprecated)] -unsafe impl<T> Send for IoVec<T> where T: Send {} -#[allow(deprecated)] -unsafe impl<T> Sync for IoVec<T> where T: Sync {} - -feature! { -#![feature = "process"] - -/// Write data directly to another process's virtual memory -/// (see [`process_vm_writev`(2)]). -/// -/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, -/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the -/// data should be written in the target process. On success, returns the -/// number of bytes written, which will always be a whole -/// number of `remote_iov` chunks. -/// -/// This requires the same permissions as debugging the process using -/// [ptrace]: you must either be a privileged process (with -/// `CAP_SYS_PTRACE`), or you must be running as the same user as the -/// target process and the OS must have unprivileged debugging enabled. -/// -/// This function is only available on Linux and Android(SDK23+). -/// -/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html -/// [ptrace]: ../ptrace/index.html -/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html -/// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] -pub fn process_vm_writev( - pid: crate::unistd::Pid, - local_iov: &[IoSlice<'_>], - remote_iov: &[RemoteIoVec]) -> Result<usize> -{ - let res = unsafe { - libc::process_vm_writev(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Read data directly from another process's virtual memory -/// (see [`process_vm_readv`(2)]). -/// -/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy -/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying -/// where the source data is in the target process. On success, -/// returns the number of bytes written, which will always be a whole -/// number of `remote_iov` chunks. -/// -/// This requires the same permissions as debugging the process using -/// [`ptrace`]: you must either be a privileged process (with -/// `CAP_SYS_PTRACE`), or you must be running as the same user as the -/// target process and the OS must have unprivileged debugging enabled. -/// -/// This function is only available on Linux and Android(SDK23+). -/// -/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html -/// [`ptrace`]: ../ptrace/index.html -/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html -/// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] -pub fn process_vm_readv( - pid: crate::unistd::Pid, - local_iov: &mut [IoSliceMut<'_>], - remote_iov: &[RemoteIoVec]) -> Result<usize> -{ - let res = unsafe { - libc::process_vm_readv(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) - }; - - Errno::result(res).map(|r| r as usize) -} -} diff --git a/vendor/nix/src/sys/utsname.rs b/vendor/nix/src/sys/utsname.rs deleted file mode 100644 index b48ed9f45..000000000 --- a/vendor/nix/src/sys/utsname.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Get system identification -use crate::{Errno, Result}; -use libc::c_char; -use std::ffi::OsStr; -use std::mem; -use std::os::unix::ffi::OsStrExt; - -/// Describes the running system. Return type of [`uname`]. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct UtsName(libc::utsname); - -impl UtsName { - /// Name of the operating system implementation. - pub fn sysname(&self) -> &OsStr { - cast_and_trim(&self.0.sysname) - } - - /// Network name of this machine. - pub fn nodename(&self) -> &OsStr { - cast_and_trim(&self.0.nodename) - } - - /// Release level of the operating system. - pub fn release(&self) -> &OsStr { - cast_and_trim(&self.0.release) - } - - /// Version level of the operating system. - pub fn version(&self) -> &OsStr { - cast_and_trim(&self.0.version) - } - - /// Machine hardware platform. - pub fn machine(&self) -> &OsStr { - cast_and_trim(&self.0.machine) - } - - /// NIS or YP domain name of this machine. - #[cfg(any(target_os = "android", target_os = "linux"))] - pub fn domainname(&self) -> &OsStr { - cast_and_trim(&self.0.domainname) - } -} - -/// Get system identification -pub fn uname() -> Result<UtsName> { - unsafe { - let mut ret = mem::MaybeUninit::zeroed(); - Errno::result(libc::uname(ret.as_mut_ptr()))?; - Ok(UtsName(ret.assume_init())) - } -} - -fn cast_and_trim(slice: &[c_char]) -> &OsStr { - let length = slice - .iter() - .position(|&byte| byte == 0) - .unwrap_or(slice.len()); - let bytes = - unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), length) }; - - OsStr::from_bytes(bytes) -} - -#[cfg(test)] -mod test { - #[cfg(target_os = "linux")] - #[test] - pub fn test_uname_linux() { - assert_eq!(super::uname().unwrap().sysname(), "Linux"); - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - #[test] - pub fn test_uname_darwin() { - assert_eq!(super::uname().unwrap().sysname(), "Darwin"); - } - - #[cfg(target_os = "freebsd")] - #[test] - pub fn test_uname_freebsd() { - assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); - } -} diff --git a/vendor/nix/src/sys/wait.rs b/vendor/nix/src/sys/wait.rs deleted file mode 100644 index b6524e866..000000000 --- a/vendor/nix/src/sys/wait.rs +++ /dev/null @@ -1,388 +0,0 @@ -//! Wait for a process to change status -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int}; -use std::convert::TryFrom; -#[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_env = "uclibc")), -))] -use std::os::unix::io::RawFd; - -libc_bitflags!( - /// Controls the behavior of [`waitpid`]. - pub struct WaitPidFlag: c_int { - /// Do not block when there are no processes wishing to report status. - WNOHANG; - /// Report the status of selected processes which are stopped due to a - /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), - /// [`SIGTTOU`](crate::sys::signal::Signal::SIGTTOU), - /// [`SIGTSTP`](crate::sys::signal::Signal::SIGTSTP), or - /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. - WUNTRACED; - /// Report the status of selected processes which have terminated. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WEXITED; - /// Report the status of selected processes that have continued from a - /// job control stop by receiving a - /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. - WCONTINUED; - /// An alias for WUNTRACED. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WSTOPPED; - /// Don't reap, just poll status. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WNOWAIT; - /// Don't wait on children of other threads in this group - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WNOTHREAD; - /// Wait on all children, regardless of type - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WALL; - /// Wait for "clone" children only. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WCLONE; - } -); - -/// Possible return values from `wait()` or `waitpid()`. -/// -/// Each status (other than `StillAlive`) describes a state transition -/// in a child process `Pid`, such as the process exiting or stopping, -/// plus additional data about the transition if any. -/// -/// Note that there are two Linux-specific enum variants, `PtraceEvent` -/// and `PtraceSyscall`. Portable code should avoid exhaustively -/// matching on `WaitStatus`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum WaitStatus { - /// The process exited normally (as with `exit()` or returning from - /// `main`) with the given exit code. This case matches the C macro - /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`. - Exited(Pid, i32), - /// The process was killed by the given signal. The third field - /// indicates whether the signal generated a core dump. This case - /// matches the C macro `WIFSIGNALED(status)`; the last two fields - /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`. - Signaled(Pid, Signal, bool), - /// The process is alive, but was stopped by the given signal. This - /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This - /// case matches the C macro `WIFSTOPPED(status)`; the second field - /// is `WSTOPSIG(status)`. - Stopped(Pid, Signal), - /// The traced process was stopped by a `PTRACE_EVENT_*` event. See - /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All - /// currently-defined events use `SIGTRAP` as the signal; the third - /// field is the `PTRACE_EVENT_*` value of the event. - /// - /// [`nix::sys::ptrace`]: ../ptrace/index.html - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PtraceEvent(Pid, Signal, c_int), - /// The traced process was stopped by execution of a system call, - /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for - /// more information. - /// - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PtraceSyscall(Pid), - /// The process was previously stopped but has resumed execution - /// after receiving a `SIGCONT` signal. This is only reported if - /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C - /// macro `WIFCONTINUED(status)`. - Continued(Pid), - /// There are currently no state changes to report in any awaited - /// child process. This is only returned if `WaitPidFlag::WNOHANG` - /// was used (otherwise `wait()` or `waitpid()` would block until - /// there was something to report). - StillAlive, -} - -impl WaitStatus { - /// Extracts the PID from the WaitStatus unless it equals StillAlive. - pub fn pid(&self) -> Option<Pid> { - use self::WaitStatus::*; - match *self { - Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => { - Some(p) - } - StillAlive => None, - #[cfg(any(target_os = "android", target_os = "linux"))] - PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), - } - } -} - -fn exited(status: i32) -> bool { - libc::WIFEXITED(status) -} - -fn exit_status(status: i32) -> i32 { - libc::WEXITSTATUS(status) -} - -fn signaled(status: i32) -> bool { - libc::WIFSIGNALED(status) -} - -fn term_signal(status: i32) -> Result<Signal> { - Signal::try_from(libc::WTERMSIG(status)) -} - -fn dumped_core(status: i32) -> bool { - libc::WCOREDUMP(status) -} - -fn stopped(status: i32) -> bool { - libc::WIFSTOPPED(status) -} - -fn stop_signal(status: i32) -> Result<Signal> { - Signal::try_from(libc::WSTOPSIG(status)) -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn syscall_stop(status: i32) -> bool { - // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect - // of delivering SIGTRAP | 0x80 as the signal number for syscall - // stops. This allows easily distinguishing syscall stops from - // genuine SIGTRAP signals. - libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn stop_additional(status: i32) -> c_int { - (status >> 16) as c_int -} - -fn continued(status: i32) -> bool { - libc::WIFCONTINUED(status) -} - -impl WaitStatus { - /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus` - /// - /// # Errors - /// - /// Returns an `Error` corresponding to `EINVAL` for invalid status values. - /// - /// # Examples - /// - /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`: - /// - /// ``` - /// use nix::sys::wait::WaitStatus; - /// use nix::sys::signal::Signal; - /// let pid = nix::unistd::Pid::from_raw(1); - /// let status = WaitStatus::from_raw(pid, 0x0002); - /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); - /// ``` - pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> { - Ok(if exited(status) { - WaitStatus::Exited(pid, exit_status(status)) - } else if signaled(status) { - WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) - } else if stopped(status) { - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { - let status_additional = stop_additional(status); - Ok(if syscall_stop(status) { - WaitStatus::PtraceSyscall(pid) - } else if status_additional == 0 { - WaitStatus::Stopped(pid, stop_signal(status)?) - } else { - WaitStatus::PtraceEvent(pid, stop_signal(status)?, - stop_additional(status)) - }) - } - } else { - fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { - Ok(WaitStatus::Stopped(pid, stop_signal(status)?)) - } - } - } - return decode_stopped(pid, status); - } else { - assert!(continued(status)); - WaitStatus::Continued(pid) - }) - } - - /// Convert a `siginfo_t` as returned by `waitid` to a `WaitStatus` - /// - /// # Errors - /// - /// Returns an `Error` corresponding to `EINVAL` for invalid values. - /// - /// # Safety - /// - /// siginfo_t is actually a union, not all fields may be initialized. - /// The functions si_pid() and si_status() must be valid to call on - /// the passed siginfo_t. - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), - ))] - unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result<WaitStatus> { - let si_pid = siginfo.si_pid(); - if si_pid == 0 { - return Ok(WaitStatus::StillAlive); - } - - assert_eq!(siginfo.si_signo, libc::SIGCHLD); - - let pid = Pid::from_raw(si_pid); - let si_status = siginfo.si_status(); - - let status = match siginfo.si_code { - libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), - libc::CLD_KILLED | libc::CLD_DUMPED => WaitStatus::Signaled( - pid, - Signal::try_from(si_status)?, - siginfo.si_code == libc::CLD_DUMPED, - ), - libc::CLD_STOPPED => { - WaitStatus::Stopped(pid, Signal::try_from(si_status)?) - } - libc::CLD_CONTINUED => WaitStatus::Continued(pid), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::CLD_TRAPPED => { - if si_status == libc::SIGTRAP | 0x80 { - WaitStatus::PtraceSyscall(pid) - } else { - WaitStatus::PtraceEvent( - pid, - Signal::try_from(si_status & 0xff)?, - (si_status >> 8) as c_int, - ) - } - } - _ => return Err(Errno::EINVAL), - }; - - Ok(status) - } -} - -/// Wait for a process to change status -/// -/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) -pub fn waitpid<P: Into<Option<Pid>>>( - pid: P, - options: Option<WaitPidFlag>, -) -> Result<WaitStatus> { - use self::WaitStatus::*; - - let mut status: i32 = 0; - - let option_bits = match options { - Some(bits) => bits.bits(), - None => 0, - }; - - let res = unsafe { - libc::waitpid( - pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(), - &mut status as *mut c_int, - option_bits, - ) - }; - - match Errno::result(res)? { - 0 => Ok(StillAlive), - res => WaitStatus::from_raw(Pid::from_raw(res), status), - } -} - -/// Wait for any child process to change status or a signal is received. -/// -/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) -pub fn wait() -> Result<WaitStatus> { - waitpid(None, None) -} - -/// The ID argument for `waitid` -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Id { - /// Wait for any child - All, - /// Wait for the child whose process ID matches the given PID - Pid(Pid), - /// Wait for the child whose process group ID matches the given PID - /// - /// If the PID is zero, the caller's process group is used since Linux 5.4. - PGid(Pid), - /// Wait for the child referred to by the given PID file descriptor - #[cfg(any(target_os = "android", target_os = "linux"))] - PIDFd(RawFd), -} - -/// Wait for a process to change status -/// -/// See also [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> { - let (idtype, idval) = match id { - Id::All => (libc::P_ALL, 0), - Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), - Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), - #[cfg(any(target_os = "android", target_os = "linux"))] - Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t), - }; - - let siginfo = unsafe { - // Memory is zeroed rather than uninitialized, as not all platforms - // initialize the memory in the StillAlive case - let mut siginfo: libc::siginfo_t = std::mem::zeroed(); - Errno::result(libc::waitid(idtype, idval, &mut siginfo, flags.bits()))?; - siginfo - }; - - unsafe { WaitStatus::from_siginfo(&siginfo) } -} |