2021-06-06 13:33:51 +02:00
|
|
|
//! Utility functionality
|
|
|
|
|
2021-06-12 01:17:53 +02:00
|
|
|
use std::env;
|
2021-03-27 12:08:13 +01:00
|
|
|
use std::ffi::CString;
|
2021-06-05 00:20:02 +02:00
|
|
|
use std::fs;
|
2021-04-10 16:36:41 +02:00
|
|
|
use std::path::{Path, PathBuf};
|
2021-06-05 00:20:02 +02:00
|
|
|
use std::time::Duration;
|
2021-03-27 12:08:13 +01:00
|
|
|
|
2021-06-15 22:38:51 +02:00
|
|
|
use anyhow::Context;
|
2021-04-07 14:07:01 +02:00
|
|
|
use anyhow::{bail, Result};
|
2021-06-12 01:17:53 +02:00
|
|
|
use nix::unistd;
|
2021-03-27 12:08:13 +01:00
|
|
|
|
2021-04-07 14:07:01 +02:00
|
|
|
pub trait PathBufExt {
|
|
|
|
fn as_in_container(&self) -> Result<PathBuf>;
|
2021-04-10 16:36:41 +02:00
|
|
|
fn join_absolute_path(&self, p: &Path) -> Result<PathBuf>;
|
2021-04-07 14:07:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PathBufExt for PathBuf {
|
|
|
|
fn as_in_container(&self) -> Result<PathBuf> {
|
|
|
|
if self.is_relative() {
|
2021-06-06 12:13:22 +02:00
|
|
|
bail!("Relative path cannot be converted to the path in the container.")
|
2021-04-07 14:07:01 +02:00
|
|
|
} else {
|
|
|
|
let path_string = self.to_string_lossy().into_owned();
|
|
|
|
Ok(PathBuf::from(path_string[1..].to_string()))
|
|
|
|
}
|
|
|
|
}
|
2021-04-10 16:36:41 +02:00
|
|
|
|
|
|
|
fn join_absolute_path(&self, p: &Path) -> Result<PathBuf> {
|
|
|
|
if !p.is_absolute() && !p.as_os_str().is_empty() {
|
|
|
|
bail!(
|
2021-06-08 08:34:50 +02:00
|
|
|
"cannot join {:?} because it is not the absolute path.",
|
2021-04-10 16:36:41 +02:00
|
|
|
p.display()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Ok(PathBuf::from(format!("{}{}", self.display(), p.display())))
|
|
|
|
}
|
2021-04-07 14:07:01 +02:00
|
|
|
}
|
|
|
|
|
2021-05-15 08:51:12 +02:00
|
|
|
pub fn do_exec(path: impl AsRef<Path>, args: &[String], envs: &[String]) -> Result<()> {
|
2021-05-05 13:54:11 +02:00
|
|
|
let p = CString::new(path.as_ref().to_string_lossy().to_string())?;
|
2021-03-27 12:08:13 +01:00
|
|
|
let a: Vec<CString> = args
|
|
|
|
.iter()
|
|
|
|
.map(|s| CString::new(s.to_string()).unwrap_or_default())
|
|
|
|
.collect();
|
2021-05-15 08:51:12 +02:00
|
|
|
|
2021-06-12 01:17:53 +02:00
|
|
|
// clear env vars
|
|
|
|
env::vars().for_each(|(key, _value)| std::env::remove_var(key));
|
|
|
|
// set env vars
|
|
|
|
envs.iter().for_each(|e| {
|
2021-06-15 01:48:43 +02:00
|
|
|
let mut split = e.split('=');
|
|
|
|
if let Some(key) = split.next() {
|
|
|
|
let value: String = split.collect::<Vec<&str>>().join("=");
|
|
|
|
env::set_var(key, value)
|
2021-06-12 01:17:53 +02:00
|
|
|
};
|
|
|
|
});
|
2021-03-27 12:08:13 +01:00
|
|
|
|
|
|
|
unistd::execvp(&p, &a)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO implement
|
|
|
|
pub fn set_name(_name: &str) -> Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-04-29 10:34:23 +02:00
|
|
|
|
2021-05-29 10:52:36 +02:00
|
|
|
/// If None, it will generate a default path for cgroups.
|
|
|
|
pub fn get_cgroup_path(cgroups_path: &Option<PathBuf>, container_id: &str) -> PathBuf {
|
|
|
|
match cgroups_path {
|
|
|
|
Some(cpath) => cpath.clone(),
|
|
|
|
None => PathBuf::from(format!("/youki/{}", container_id)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-05 00:20:02 +02:00
|
|
|
pub fn delete_with_retry<P: AsRef<Path>>(path: P) -> Result<()> {
|
|
|
|
let mut attempts = 0;
|
|
|
|
let mut delay = Duration::from_millis(10);
|
|
|
|
let path = path.as_ref();
|
|
|
|
|
|
|
|
while attempts < 5 {
|
|
|
|
if fs::remove_dir(path).is_ok() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::thread::sleep(delay);
|
|
|
|
attempts += attempts;
|
|
|
|
delay *= attempts;
|
|
|
|
}
|
|
|
|
|
|
|
|
bail!("could not delete {:?}", path)
|
|
|
|
}
|
|
|
|
|
2021-06-15 22:38:51 +02:00
|
|
|
pub fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
|
|
|
|
let path = path.as_ref();
|
|
|
|
fs::write(path, contents).with_context(|| format!("failed to write to {:?}", path))?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-29 10:34:23 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_join_absolute_path() {
|
|
|
|
assert_eq!(
|
|
|
|
PathBuf::from("sample/a/")
|
|
|
|
.join_absolute_path(&PathBuf::from("/b"))
|
|
|
|
.unwrap(),
|
|
|
|
PathBuf::from("sample/a/b")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_join_absolute_path_error() {
|
|
|
|
assert_eq!(
|
|
|
|
PathBuf::from("sample/a/")
|
|
|
|
.join_absolute_path(&PathBuf::from("b/c"))
|
|
|
|
.is_err(),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
2021-05-29 10:52:36 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_cgroup_path() {
|
|
|
|
let cid = "sample_container_id";
|
|
|
|
assert_eq!(
|
|
|
|
get_cgroup_path(&None, cid),
|
|
|
|
PathBuf::from("/youki/sample_container_id")
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
get_cgroup_path(&Some(PathBuf::from("/youki")), cid),
|
|
|
|
PathBuf::from("/youki")
|
|
|
|
);
|
|
|
|
}
|
2021-04-29 10:34:23 +02:00
|
|
|
}
|