mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-16 08:26:16 +00:00
Merge pull request #1032 from devimc/2020-10-21/unitests/container.rs
Improve unit test coverage for rustjail/container.rs
This commit is contained in:
commit
196e8d81cf
74
src/agent/rustjail/src/cgroups/mock.rs
Normal file
74
src/agent/rustjail/src/cgroups/mock.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use protobuf::{CachedSize, SingularPtrField, UnknownFields};
|
||||||
|
|
||||||
|
use crate::cgroups::Manager as CgroupManager;
|
||||||
|
use crate::protocols::agent::{BlkioStats, CgroupStats, CpuStats, MemoryStats, PidsStats};
|
||||||
|
use anyhow::Result;
|
||||||
|
use cgroups::freezer::FreezerState;
|
||||||
|
use libc::{self, pid_t};
|
||||||
|
use oci::LinuxResources;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::string::String;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Manager {
|
||||||
|
pub paths: HashMap<String, String>,
|
||||||
|
pub mounts: HashMap<String, String>,
|
||||||
|
pub cpath: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CgroupManager for Manager {
|
||||||
|
fn apply(&self, _: pid_t) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&self, _: &LinuxResources, _: bool) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stats(&self) -> Result<CgroupStats> {
|
||||||
|
Ok(CgroupStats {
|
||||||
|
cpu_stats: SingularPtrField::some(CpuStats::default()),
|
||||||
|
memory_stats: SingularPtrField::some(MemoryStats::new()),
|
||||||
|
pids_stats: SingularPtrField::some(PidsStats::new()),
|
||||||
|
blkio_stats: SingularPtrField::some(BlkioStats::new()),
|
||||||
|
hugetlb_stats: HashMap::new(),
|
||||||
|
unknown_fields: UnknownFields::default(),
|
||||||
|
cached_size: CachedSize::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freeze(&self, _: FreezerState) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pids(&self) -> Result<Vec<pid_t>> {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Manager {
|
||||||
|
pub fn new(cpath: &str) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
paths: HashMap::new(),
|
||||||
|
mounts: HashMap::new(),
|
||||||
|
cpath: cpath.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_cpuset_path(&self, _: &str) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cg_path(&self, _: &str) -> Option<String> {
|
||||||
|
Some("".to_string())
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ use protocols::agent::CgroupStats;
|
|||||||
use cgroups::freezer::FreezerState;
|
use cgroups::freezer::FreezerState;
|
||||||
|
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod mock;
|
||||||
pub mod notifier;
|
pub mod notifier;
|
||||||
pub mod systemd;
|
pub mod systemd;
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ use std::time::SystemTime;
|
|||||||
use cgroups::freezer::FreezerState;
|
use cgroups::freezer::FreezerState;
|
||||||
|
|
||||||
use crate::capabilities::{self, CAPSMAP};
|
use crate::capabilities::{self, CAPSMAP};
|
||||||
|
#[cfg(not(test))]
|
||||||
use crate::cgroups::fs::Manager as FsManager;
|
use crate::cgroups::fs::Manager as FsManager;
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::cgroups::mock::Manager as FsManager;
|
||||||
use crate::cgroups::Manager;
|
use crate::cgroups::Manager;
|
||||||
use crate::log_child;
|
use crate::log_child;
|
||||||
use crate::process::Process;
|
use crate::process::Process;
|
||||||
@ -694,11 +697,15 @@ impl BaseContainer for LinuxContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> Result<State> {
|
fn state(&self) -> Result<State> {
|
||||||
Err(anyhow!("not suppoerted"))
|
Err(anyhow!("not supported"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oci_state(&self) -> Result<OCIState> {
|
fn oci_state(&self) -> Result<OCIState> {
|
||||||
let oci = self.config.spec.as_ref().unwrap();
|
let oci = match self.config.spec.as_ref() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err(anyhow!("Unable to get OCI state: spec not found")),
|
||||||
|
};
|
||||||
|
|
||||||
let status = self.status();
|
let status = self.status();
|
||||||
let pid = if status != Status::STOPPED {
|
let pid = if status != Status::STOPPED {
|
||||||
self.init_process_pid
|
self.init_process_pid
|
||||||
@ -706,9 +713,17 @@ impl BaseContainer for LinuxContainer {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = oci.root.as_ref().unwrap().path.as_str();
|
let root = match oci.root.as_ref() {
|
||||||
|
Some(s) => s.path.as_str(),
|
||||||
|
None => return Err(anyhow!("Unable to get root path: oci.root is none")),
|
||||||
|
};
|
||||||
|
|
||||||
let path = fs::canonicalize(root)?;
|
let path = fs::canonicalize(root)?;
|
||||||
let bundle = path.parent().unwrap().to_str().unwrap().to_string();
|
let bundle = match path.parent() {
|
||||||
|
Some(s) => s.to_str().unwrap().to_string(),
|
||||||
|
None => return Err(anyhow!("could not get root parent: root path {:?}", path)),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(OCIState {
|
Ok(OCIState {
|
||||||
version: oci.version.clone(),
|
version: oci.version.clone(),
|
||||||
id: self.id(),
|
id: self.id(),
|
||||||
@ -1004,7 +1019,7 @@ impl BaseContainer for LinuxContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.status.transition(Status::STOPPED);
|
self.status.transition(Status::STOPPED);
|
||||||
nix::mount::umount2(
|
mount::umount2(
|
||||||
spec.root.as_ref().unwrap().path.as_str(),
|
spec.root.as_ref().unwrap().path.as_str(),
|
||||||
MntFlags::MNT_DETACH,
|
MntFlags::MNT_DETACH,
|
||||||
)?;
|
)?;
|
||||||
@ -1628,9 +1643,18 @@ fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::process::Process;
|
||||||
use crate::skip_if_not_root;
|
use crate::skip_if_not_root;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
macro_rules! sl {
|
||||||
|
() => {
|
||||||
|
slog_scope::logger()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_status_transtition() {
|
fn test_status_transtition() {
|
||||||
@ -1672,4 +1696,295 @@ mod tests {
|
|||||||
// restore the uid
|
// restore the uid
|
||||||
set_stdio_permissions(old_uid).unwrap();
|
set_stdio_permissions(old_uid).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_status_fmt() {
|
||||||
|
assert_eq!("\"created\"", format!("{:?}", Status::CREATED));
|
||||||
|
assert_eq!("\"running\"", format!("{:?}", Status::RUNNING));
|
||||||
|
assert_eq!("\"paused\"", format!("{:?}", Status::PAUSED));
|
||||||
|
assert_eq!("\"stopped\"", format!("{:?}", Status::STOPPED));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_namespaces() {
|
||||||
|
lazy_static::initialize(&NAMESPACES);
|
||||||
|
assert_eq!(NAMESPACES.len(), 7);
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("user");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("ipc");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("pid");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("network");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("mount");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("uts");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = NAMESPACES.get("cgroup");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_typetoname() {
|
||||||
|
lazy_static::initialize(&TYPETONAME);
|
||||||
|
assert_eq!(TYPETONAME.len(), 7);
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("user");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("ipc");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("pid");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("network");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("mount");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("uts");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
|
||||||
|
let ns = TYPETONAME.get("cgroup");
|
||||||
|
assert!(ns.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_dummy_opts() -> CreateOpts {
|
||||||
|
let mut root = oci::Root::default();
|
||||||
|
root.path = "/tmp".to_string();
|
||||||
|
|
||||||
|
let linux = Linux::default();
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
spec.root = Some(root).into();
|
||||||
|
spec.linux = Some(linux).into();
|
||||||
|
|
||||||
|
CreateOpts {
|
||||||
|
cgroup_name: "".to_string(),
|
||||||
|
use_systemd_cgroup: false,
|
||||||
|
no_pivot_root: false,
|
||||||
|
no_new_keyring: false,
|
||||||
|
spec: Some(spec),
|
||||||
|
rootless_euid: false,
|
||||||
|
rootless_cgroup: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_linux_container<U, F: FnOnce(LinuxContainer) -> Result<U, anyhow::Error>>(
|
||||||
|
op: F,
|
||||||
|
) -> Result<U, anyhow::Error> {
|
||||||
|
// Create a temporal directory
|
||||||
|
tempdir()
|
||||||
|
.map_err(|e| anyhow!(e).context("tempdir failed"))
|
||||||
|
.and_then(|p: tempfile::TempDir| {
|
||||||
|
// Create a new container
|
||||||
|
LinuxContainer::new(
|
||||||
|
"some_id",
|
||||||
|
&p.path().join("rootfs").to_str().unwrap(),
|
||||||
|
create_dummy_opts(),
|
||||||
|
&slog_scope::logger(),
|
||||||
|
)
|
||||||
|
.and_then(op)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_pause_bad_status() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
// Change state to pause, c.pause() should fail
|
||||||
|
c.status.transition(Status::PAUSED);
|
||||||
|
c.pause().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_err(), "Expecting error, Got {:?}", ret);
|
||||||
|
assert!(format!("{:?}", ret).contains("failed to pause container"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_pause_cgroupmgr_is_none() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.cgroup_manager = None;
|
||||||
|
c.pause().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_err(), "Expecting error, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_pause() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.cgroup_manager = FsManager::new("").ok();
|
||||||
|
c.pause().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_resume_bad_status() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
// Change state to created, c.resume() should fail
|
||||||
|
c.status.transition(Status::CREATED);
|
||||||
|
c.resume().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_err(), "Expecting error, Got {:?}", ret);
|
||||||
|
assert!(format!("{:?}", ret).contains("not paused"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_resume_cgroupmgr_is_none() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.status.transition(Status::PAUSED);
|
||||||
|
c.cgroup_manager = None;
|
||||||
|
c.resume().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_err(), "Expecting error, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_resume() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.cgroup_manager = FsManager::new("").ok();
|
||||||
|
// Change status to paused, this way we can resume it
|
||||||
|
c.status.transition(Status::PAUSED);
|
||||||
|
c.resume().map_err(|e| anyhow!(e))
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_state() {
|
||||||
|
let ret = new_linux_container(|c: LinuxContainer| c.state());
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
assert!(
|
||||||
|
format!("{:?}", ret).contains("not supported"),
|
||||||
|
"Got: {:?}",
|
||||||
|
ret
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_oci_state_no_root_parent() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.config.spec.as_mut().unwrap().root.as_mut().unwrap().path = "/".to_string();
|
||||||
|
c.oci_state()
|
||||||
|
});
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
assert!(
|
||||||
|
format!("{:?}", ret).contains("could not get root parent"),
|
||||||
|
"Got: {:?}",
|
||||||
|
ret
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_oci_state() {
|
||||||
|
let ret = new_linux_container(|c: LinuxContainer| c.oci_state());
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_config() {
|
||||||
|
let ret = new_linux_container(|c: LinuxContainer| Ok(c));
|
||||||
|
assert!(ret.is_ok(), "Expecting ok, Got {:?}", ret);
|
||||||
|
assert!(
|
||||||
|
ret.as_ref().unwrap().config().is_ok(),
|
||||||
|
"Expecting ok, Got {:?}",
|
||||||
|
ret
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_processes() {
|
||||||
|
let ret = new_linux_container(|c: LinuxContainer| c.processes());
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_get_process_not_found() {
|
||||||
|
let _ = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
let p = c.get_process("123");
|
||||||
|
assert!(p.is_err(), "Expecting Err, Got {:?}", p);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_get_process() {
|
||||||
|
let _ = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.processes.insert(
|
||||||
|
1,
|
||||||
|
Process::new(&sl!(), &oci::Process::default(), "123", true, 1).unwrap(),
|
||||||
|
);
|
||||||
|
let p = c.get_process("123");
|
||||||
|
assert!(p.is_ok(), "Expecting Ok, Got {:?}", p);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_stats() {
|
||||||
|
let ret = new_linux_container(|c: LinuxContainer| c.stats());
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_set() {
|
||||||
|
let ret =
|
||||||
|
new_linux_container(|mut c: LinuxContainer| c.set(oci::LinuxResources::default()));
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_start() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.start(Process::new(&sl!(), &oci::Process::default(), "123", true, 1).unwrap())
|
||||||
|
});
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_run() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| {
|
||||||
|
c.run(Process::new(&sl!(), &oci::Process::default(), "123", true, 1).unwrap())
|
||||||
|
});
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_destroy() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| c.destroy());
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_signal() {
|
||||||
|
let ret =
|
||||||
|
new_linux_container(|c: LinuxContainer| c.signal(nix::sys::signal::SIGCONT, true));
|
||||||
|
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_exec() {
|
||||||
|
let ret = new_linux_container(|mut c: LinuxContainer| c.exec());
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linuxcontainer_do_init_child() {
|
||||||
|
let ret = do_init_child(std::io::stdin().as_raw_fd());
|
||||||
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,12 @@ lazy_static! {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
|
pub fn mount<
|
||||||
|
P1: ?Sized + NixPath,
|
||||||
|
P2: ?Sized + NixPath,
|
||||||
|
P3: ?Sized + NixPath,
|
||||||
|
P4: ?Sized + NixPath,
|
||||||
|
>(
|
||||||
source: Option<&P1>,
|
source: Option<&P1>,
|
||||||
target: &P2,
|
target: &P2,
|
||||||
fstype: Option<&P3>,
|
fstype: Option<&P3>,
|
||||||
@ -127,7 +132,7 @@ fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn umount2<P: ?Sized + NixPath>(
|
pub fn umount2<P: ?Sized + NixPath>(
|
||||||
target: &P,
|
target: &P,
|
||||||
flags: MntFlags,
|
flags: MntFlags,
|
||||||
) -> std::result::Result<(), nix::Error> {
|
) -> std::result::Result<(), nix::Error> {
|
||||||
|
Loading…
Reference in New Issue
Block a user