Skip to content

Commit

Permalink
Execute mknod and symlink as root and chown
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed Mar 19, 2024
1 parent d66ed3e commit e8fa517
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 11 deletions.
44 changes: 34 additions & 10 deletions src/docker/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ use super::{IoStream, IoStreamSource};

#[derive(Clone)]
pub struct Container {
id: String,
docker: bollard::Docker,
id: String,
user: String,
remove_event: Shared<BoxFuture<'static, Option<EventMessage>>>,
cgroup_device_filter: Arc<Mutex<Option<Box<dyn DeviceAccessController + Send>>>>,
}

impl Container {
pub(super) fn new(id: &str, docker: &bollard::Docker) -> Result<Self> {
pub(super) fn new(docker: &bollard::Docker, id: String, user: String) -> Result<Self> {
let mut remove_events = docker.events(Some(bollard::system::EventsOptions {
filters: [
("container".to_owned(), vec![id.to_owned()]),
Expand All @@ -43,9 +44,9 @@ impl Container {
.shared();

let cgroup_device_filter: Box<dyn DeviceAccessController + Send> =
match DeviceAccessControllerV2::new(id) {
match DeviceAccessControllerV2::new(&id) {
Ok(v) => Box::new(v),
Err(err2) => match DeviceAccessControllerV1::new(id) {
Err(err2) => match DeviceAccessControllerV1::new(&id) {
Ok(v) => Box::new(v),
Err(err1) => {
log::error!("neither cgroup v1 and cgroup v2 works");
Expand All @@ -57,8 +58,14 @@ impl Container {
};

Ok(Self {
id: id.to_owned(),
docker: docker.clone(),
id,
user: if user.is_empty() {
// If user is not specified, use root.
"root".to_owned()
} else {
user
},
remove_event: remove_evevnt,
cgroup_device_filter: Arc::new(Mutex::new(Some(cgroup_device_filter))),
})
Expand Down Expand Up @@ -114,7 +121,7 @@ impl Container {
Ok(())
}

pub async fn exec<T: ToString>(&self, cmd: &[T]) -> Result<IoStream> {
pub async fn exec_as_root<T: ToString>(&self, cmd: &[T]) -> Result<IoStream> {
let cmd = cmd.iter().map(|s| s.to_string()).collect();
let options = bollard::exec::CreateExecOptions {
cmd: Some(cmd),
Expand All @@ -123,6 +130,7 @@ impl Container {
attach_stderr: Some(true),
tty: Some(true),
detach_keys: Some("ctrl-c".to_string()),
user: Some("root".to_string()),
..Default::default()
};
let response = self.docker.create_exec::<String>(&self.id, options).await?;
Expand Down Expand Up @@ -206,9 +214,20 @@ impl Container {
}
}

pub async fn chown_to_user(&self, path: &str) -> Result<()> {
self.exec_as_root(&["chown", &format!("{}:", self.user), path])
.await?
.collect()
.await?;
Ok(())
}

// Note: we use `&str` here instead of `Path` because docker API expects string instead `OsStr`.
pub async fn mkdir(&self, path: &str) -> Result<()> {
self.exec(&["mkdir", "-p", path]).await?.collect().await?;
self.exec_as_root(&["mkdir", "-p", path])
.await?
.collect()
.await?;
Ok(())
}

Expand All @@ -222,24 +241,29 @@ impl Container {
pub async fn mknod(&self, node: &str, (major, minor): (u32, u32)) -> Result<()> {
self.rm(node).await?;
self.mkdir_for(node).await?;
self.exec(&["mknod", node, "c", &major.to_string(), &minor.to_string()])
self.exec_as_root(&["mknod", node, "c", &major.to_string(), &minor.to_string()])
.await?
.collect()
.await?;
self.chown_to_user(node).await?;
Ok(())
}

pub async fn symlink(&self, source: &str, link: &str) -> Result<()> {
self.mkdir_for(link).await?;
self.exec(&["ln", "-sf", source, link])
self.exec_as_root(&["ln", "-sf", source, link])
.await?
.collect()
.await?;
self.chown_to_user(link).await?;
Ok(())
}

pub async fn rm(&self, node: &str) -> Result<()> {
self.exec(&["rm", "-f", node]).await?.collect().await?;
self.exec_as_root(&["rm", "-f", node])
.await?
.collect()
.await?;
Ok(())
}

Expand Down
6 changes: 5 additions & 1 deletion src/docker/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ impl Docker {
pub async fn get<T: AsRef<str>>(&self, name: T) -> Result<Container> {
let response = self.0.inspect_container(name.as_ref(), None).await?;
let id = response.id.context("Failed to obtain container ID")?;
Container::new(&id, &self.0)
let config = response
.config
.context("Failed to obtain container config")?;
let user = config.user.context("Failed to obtain container user")?;
Container::new(&self.0, id, user)
}

pub async fn run<U: AsRef<str>, T: AsRef<[U]>>(&self, args: T) -> Result<Container> {
Expand Down

0 comments on commit e8fa517

Please sign in to comment.