Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  bsd_without_apple.rs   Sprache: unbekannt

 
#[cfg(target_os = "freebsd")]
use crate::Error;
use crate::{Errno, NixPath, Result};
use libc::c_int;
#[cfg(target_os = "freebsd")]
use libc::{c_char, c_uint, c_void};
#[cfg(target_os = "freebsd")]
use std::{
    borrow::Cow,
    ffi::{CStr, CString},
    fmt, io,
    marker::PhantomData,
};

libc_bitflags!(
    /// Used with [`Nmount::nmount`].
    pub struct MntFlags: c_int {
        /// ACL support enabled.
        #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
        MNT_ACLS;
        /// All I/O to the file system should be done asynchronously.
        MNT_ASYNC;
        /// dir should instead be a file system ID encoded as “FSID:val0:val1”.
        #[cfg(target_os = "freebsd")]
        MNT_BYFSID;
        /// Force a read-write mount even if the file system appears to be
        /// unclean.
        MNT_FORCE;
        /// GEOM journal support enabled.
        #[cfg(target_os = "freebsd")]
        MNT_GJOURNAL;
        /// MAC support for objects.
        #[cfg(target_os = "freebsd")]
        MNT_MULTILABEL;
        /// Disable read clustering.
        #[cfg(freebsdlike)]
        MNT_NOCLUSTERR;
        /// Disable write clustering.
        #[cfg(freebsdlike)]
        MNT_NOCLUSTERW;
        /// Enable NFS version 4 ACLs.
        #[cfg(target_os = "freebsd")]
        MNT_NFS4ACLS;
        /// Do not update access times.
        MNT_NOATIME;
        /// Disallow program execution.
        MNT_NOEXEC;
        /// Do not honor setuid or setgid bits on files when executing them.
        MNT_NOSUID;
        /// Do not follow symlinks.
        #[cfg(freebsdlike)]
        MNT_NOSYMFOLLOW;
        /// Mount read-only.
        MNT_RDONLY;
        /// Causes the vfs subsystem to update its data structures pertaining to
        /// the specified already mounted file system.
        MNT_RELOAD;
        /// Create a snapshot of the file system.
        ///
        /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs)
        #[cfg(target_os = "freebsd")]
        MNT_SNAPSHOT;
        /// Using soft updates.
        #[cfg(any(freebsdlike, netbsdlike))]
        MNT_SOFTDEP;
        /// Directories with the SUID bit set chown new files to their own
        /// owner.
        #[cfg(freebsdlike)]
        MNT_SUIDDIR;
        /// All I/O to the file system should be done synchronously.
        MNT_SYNCHRONOUS;
        /// Union with underlying fs.
        #[cfg(any(
                target_os = "freebsd",
                target_os = "netbsd"
        ))]
        MNT_UNION;
        /// Indicates that the mount command is being applied to an already
        /// mounted file system.
        MNT_UPDATE;
        /// Check vnode use counts.
        #[cfg(target_os = "freebsd")]
        MNT_NONBUSY;
    }
);

/// The Error type of [`Nmount::nmount`].
///
/// It wraps an [`Errno`], but also may contain an additional message returned
/// by `nmount(2)`.
#[cfg(target_os = "freebsd")]
#[derive(Debug)]
pub struct NmountError {
    errno: Error,
    errmsg: Option<String>,
}

#[cfg(target_os = "freebsd")]
impl NmountError {
    /// Returns the additional error string sometimes generated by `nmount(2)`.
    pub fn errmsg(&self) -> Option<&str> {
        self.errmsg.as_deref()
    }

    /// Returns the inner [`Error`]
    pub const fn error(&self) -> Error {
        self.errno
    }

    fn new(error: Error, errmsg: Option<&CStr>) -> Self {
        Self {
            errno: error,
            errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned),
        }
    }
}

#[cfg(target_os = "freebsd")]
impl std::error::Error for NmountError {}

#[cfg(target_os = "freebsd")]
impl fmt::Display for NmountError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(errmsg) = &self.errmsg {
            write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc())
        } else {
            write!(f, "{:?}: {}", self.errno, self.errno.desc())
        }
    }
}

#[cfg(target_os = "freebsd")]
impl From<NmountError> for io::Error {
    fn from(err: NmountError) -> Self {
        err.errno.into()
    }
}

/// Result type of [`Nmount::nmount`].
#[cfg(target_os = "freebsd")]
pub type NmountResult = std::result::Result<(), NmountError>;

/// Mount a FreeBSD file system.
///
/// The `nmount(2)` system call works similarly to the `mount(8)` program; it
/// takes its options as a series of name-value pairs.  Most of the values are
/// strings, as are all of the names.  The `Nmount` structure builds up an
/// argument list and then executes the syscall.
///
/// # Examples
///
/// To mount `target` onto `mountpoint` with `nullfs`:
/// ```
/// # use nix::unistd::Uid;
/// # use ::sysctl::{CtlValue, Sysctl};
/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap();
/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() {
/// #     return;
/// # };
/// use nix::mount::{MntFlags, Nmount, unmount};
/// use std::ffi::CString;
/// use tempfile::tempdir;
///
/// let mountpoint = tempdir().unwrap();
/// let target = tempdir().unwrap();
///
/// let fstype = CString::new("fstype").unwrap();
/// let nullfs = CString::new("nullfs").unwrap();
/// Nmount::new()
///     .str_opt(&fstype, &nullfs)
///     .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
///     .str_opt_owned("target", target.path().to_str().unwrap())
///     .nmount(MntFlags::empty()).unwrap();
///
/// unmount(mountpoint.path(), MntFlags::empty()).unwrap();
/// ```
///
/// # See Also
/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount)
/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs)
#[cfg(target_os = "freebsd")]
#[derive(Debug, Default)]
pub struct Nmount<'a> {
    // n.b. notgull: In reality, this is a list that contains
    //               both mutable and immutable pointers.
    //               Be careful using this.
    iov: Vec<libc::iovec>,
    is_owned: Vec<bool>,
    marker: PhantomData<&'a ()>,
}

#[cfg(target_os = "freebsd")]
impl<'a> Nmount<'a> {
    /// Helper function to push a slice onto the `iov` array.
    fn push_slice(&mut self, val: &'a [u8], is_owned: bool) {
        self.iov.push(libc::iovec {
            iov_base: val.as_ptr().cast_mut().cast(),
            iov_len: val.len(),
        });
        self.is_owned.push(is_owned);
    }

    /// Helper function to push a pointer and its length onto the `iov` array.
    fn push_pointer_and_length(
        &mut self,
        val: *const u8,
        len: usize,
        is_owned: bool,
    ) {
        self.iov.push(libc::iovec {
            iov_base: val as *mut _,
            iov_len: len,
        });
        self.is_owned.push(is_owned);
    }

    /// Helper function to push a `nix` path as owned.
    fn push_nix_path<P: ?Sized + NixPath>(&mut self, val: &P) {
        val.with_nix_path(|s| {
            let len = s.to_bytes_with_nul().len();
            let ptr = s.to_owned().into_raw() as *const u8;

            self.push_pointer_and_length(ptr, len, true);
        })
        .unwrap();
    }

    /// Add an opaque mount option.
    ///
    /// Some file systems take binary-valued mount options.  They can be set
    /// with this method.
    ///
    /// # Safety
    ///
    /// Unsafe because it will cause `Nmount::nmount` to dereference a raw
    /// pointer.  The user is responsible for ensuring that `val` is valid and
    /// its lifetime outlives `self`!  An easy way to do that is to give the
    /// value a larger scope than `name`
    ///
    /// # Examples
    /// ```
    /// use libc::c_void;
    /// use nix::mount::Nmount;
    /// use std::ffi::CString;
    /// use std::mem;
    ///
    /// // Note that flags outlives name
    /// let mut flags: u32 = 0xdeadbeef;
    /// let name = CString::new("flags").unwrap();
    /// let p = &mut flags as *mut u32 as *mut c_void;
    /// let len = mem::size_of_val(&flags);
    /// let mut nmount = Nmount::new();
    /// unsafe { nmount.mut_ptr_opt(&name, p, len) };
    /// ```
    pub unsafe fn mut_ptr_opt(
        &mut self,
        name: &'a CStr,
        val: *mut c_void,
        len: usize,
    ) -> &mut Self {
        self.push_slice(name.to_bytes_with_nul(), false);
        self.push_pointer_and_length(val.cast(), len, false);
        self
    }

    /// Add a mount option that does not take a value.
    ///
    /// # Examples
    /// ```
    /// use nix::mount::Nmount;
    /// use std::ffi::CString;
    ///
    /// let read_only = CString::new("ro").unwrap();
    /// Nmount::new()
    ///     .null_opt(&read_only);
    /// ```
    pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self {
        self.push_slice(name.to_bytes_with_nul(), false);
        self.push_slice(&[], false);
        self
    }

    /// Add a mount option that does not take a value, but whose name must be
    /// owned.
    ///
    ///
    /// This has higher runtime cost than [`Nmount::null_opt`], but is useful
    /// when the name's lifetime doesn't outlive the `Nmount`, or it's a
    /// different string type than `CStr`.
    ///
    /// # Examples
    /// ```
    /// use nix::mount::Nmount;
    ///
    /// let read_only = "ro";
    /// let mut nmount: Nmount<'static> = Nmount::new();
    /// nmount.null_opt_owned(read_only);
    /// ```
    pub fn null_opt_owned<P: ?Sized + NixPath>(
        &mut self,
        name: &P,
    ) -> &mut Self {
        self.push_nix_path(name);
        self.push_slice(&[], false);
        self
    }

    /// Add a mount option as a [`CStr`].
    ///
    /// # Examples
    /// ```
    /// use nix::mount::Nmount;
    /// use std::ffi::CString;
    ///
    /// let fstype = CString::new("fstype").unwrap();
    /// let nullfs = CString::new("nullfs").unwrap();
    /// Nmount::new()
    ///     .str_opt(&fstype, &nullfs);
    /// ```
    pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self {
        self.push_slice(name.to_bytes_with_nul(), false);
        self.push_slice(val.to_bytes_with_nul(), false);
        self
    }

    /// Add a mount option as an owned string.
    ///
    /// This has higher runtime cost than [`Nmount::str_opt`], but is useful
    /// when the value's lifetime doesn't outlive the `Nmount`, or it's a
    /// different string type than `CStr`.
    ///
    /// # Examples
    /// ```
    /// use nix::mount::Nmount;
    /// use std::path::Path;
    ///
    /// let mountpoint = Path::new("/mnt");
    /// Nmount::new()
    ///     .str_opt_owned("fspath", mountpoint.to_str().unwrap());
    /// ```
    pub fn str_opt_owned<P1, P2>(&mut self, name: &P1, val: &P2) -> &mut Self
    where
        P1: ?Sized + NixPath,
        P2: ?Sized + NixPath,
    {
        self.push_nix_path(name);
        self.push_nix_path(val);
        self
    }

    /// Create a new `Nmount` struct with no options
    pub fn new() -> Self {
        Self::default()
    }

    /// Actually mount the file system.
    pub fn nmount(&mut self, flags: MntFlags) -> NmountResult {
        const ERRMSG_NAME: &[u8] = b"errmsg\0";
        let mut errmsg = vec![0u8; 255];

        // nmount can return extra error information via a "errmsg" return
        // argument.
        self.push_slice(ERRMSG_NAME, false);

        // SAFETY: we are pushing a mutable iovec here, so we can't use
        //         the above method
        self.iov.push(libc::iovec {
            iov_base: errmsg.as_mut_ptr().cast(),
            iov_len: errmsg.len(),
        });

        let niov = self.iov.len() as c_uint;
        let iovp = self.iov.as_mut_ptr();
        let res = unsafe { libc::nmount(iovp, niov, flags.bits()) };
        match Errno::result(res) {
            Ok(_) => Ok(()),
            Err(error) => {
                let errmsg = if errmsg[0] == 0 {
                    None
                } else {
                    CStr::from_bytes_until_nul(&errmsg[..]).ok()
                };
                Err(NmountError::new(error, errmsg))
            }
        }
    }
}

#[cfg(target_os = "freebsd")]
impl<'a> Drop for Nmount<'a> {
    fn drop(&mut self) {
        for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) {
            if *is_owned {
                // Free the owned string.  Safe because we recorded ownership,
                // and Nmount does not implement Clone.
                unsafe {
                    drop(CString::from_raw(iov.iov_base as *mut c_char));
                }
            }
        }
    }
}

/// Unmount the file system mounted at `mountpoint`.
///
/// Useful flags include
/// * `MNT_FORCE` -     Unmount even if still in use.
#[cfg_attr(
    target_os = "freebsd",
    doc = "
* `MNT_BYFSID` -    `mountpoint` is not a path, but a file system ID
                    encoded as `FSID:val0:val1`, where `val0` and `val1`
                    are the contents of the `fsid_t val[]` array in decimal.
                    The file system that has the specified file system ID
                    will be unmounted.  See
                    [`statfs`](crate::sys::statfs::statfs) to determine the
                    `fsid`.
"
)]
pub fn unmount<P>(mountpoint: &P, flags: MntFlags) -> Result<()>
where
    P: ?Sized + NixPath,
{
    let res = mountpoint.with_nix_path(|cstr| unsafe {
        libc::unmount(cstr.as_ptr(), flags.bits())
    })?;

    Errno::result(res).map(drop)
}

[ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge