Skip to content

Commit 7ca5bef

Browse files
committed
Docker API requires strings; make this explicit and error if not UTF-8
1 parent da26e5d commit 7ca5bef

File tree

2 files changed

+52
-78
lines changed

2 files changed

+52
-78
lines changed

src/docker/container.rs

+40-71
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl Container {
5353
// Since we passed "--rm" flag, docker will automatically start removing the container.
5454
// Ignore any error for manual removal.
5555
let _: Result<()> = async {
56-
self.rename(format!("removing-{}", self.id)).await?;
56+
self.rename(&format!("removing-{}", self.id)).await?;
5757
let options = bollard::container::RemoveContainerOptions {
5858
force: true,
5959
..Default::default()
@@ -78,18 +78,16 @@ impl Container {
7878
Ok(())
7979
}
8080

81-
pub async fn rename<U: AsRef<str>>(&self, name: U) -> Result<()> {
82-
let required = bollard::container::RenameContainerOptions {
83-
name: name.as_ref(),
84-
};
81+
pub async fn rename(&self, name: &str) -> Result<()> {
82+
let required = bollard::container::RenameContainerOptions { name };
8583
self.docker.rename_container(&self.id, required).await?;
8684
Ok(())
8785
}
8886

89-
pub async fn exec<U: AsRef<str>, T: AsRef<[U]>>(&self, cmd: T) -> Result<IoStream> {
90-
let iter = cmd.as_ref().iter().map(|s| s.as_ref().into());
87+
pub async fn exec<T: ToString>(&self, cmd: &[T]) -> Result<IoStream> {
88+
let cmd = cmd.iter().map(|s| s.to_string()).collect();
9189
let options = bollard::exec::CreateExecOptions {
92-
cmd: Some(iter.collect()),
90+
cmd: Some(cmd),
9391
attach_stdin: Some(true),
9492
attach_stdout: Some(true),
9593
attach_stderr: Some(true),
@@ -105,17 +103,16 @@ impl Container {
105103
..Default::default()
106104
};
107105
let response = self.docker.start_exec(&id, Some(options)).await?;
106+
let bollard::exec::StartExecResults::Attached { input, output } = response else {
107+
unreachable!("we asked for attached IO streams");
108+
};
108109

109-
if let bollard::exec::StartExecResults::Attached { input, output } = response {
110-
return Ok(IoStream {
111-
output,
112-
input,
113-
source: IoStreamSource::Exec(id),
114-
docker: self.docker.clone(),
115-
});
116-
}
117-
118-
unreachable!();
110+
Ok(IoStream {
111+
output,
112+
input,
113+
source: IoStreamSource::Exec(id),
114+
docker: self.docker.clone(),
115+
})
119116
}
120117

121118
pub async fn attach(&self) -> Result<IoStream> {
@@ -141,15 +138,11 @@ impl Container {
141138
})
142139
}
143140

144-
async fn inspect(&self) -> Result<bollard::models::ContainerInspectResponse> {
145-
Ok(self
141+
pub async fn name(&self) -> Result<String> {
142+
let inspect = self
146143
.docker
147144
.inspect_container(self.id.as_ref(), None)
148-
.await?)
149-
}
150-
151-
pub async fn name(&self) -> Result<String> {
152-
let inspect = self.inspect().await?;
145+
.await?;
153146
let name = inspect.name.context("Failed to obtain container name")?;
154147
Ok(name)
155148
}
@@ -183,67 +176,43 @@ impl Container {
183176
}
184177
}
185178

186-
pub async fn mkdir<T: AsRef<std::path::Path>>(&self, path: T) -> Result<()> {
187-
self.exec(["mkdir", "-p", &path.as_ref().to_string_lossy()])
188-
.await?
189-
.collect()
190-
.await?;
179+
// Note: we use `&str` here instead of `Path` because docker API expects string instead `OsStr`.
180+
pub async fn mkdir(&self, path: &str) -> Result<()> {
181+
self.exec(&["mkdir", "-p", path]).await?.collect().await?;
191182
Ok(())
192183
}
193184

194-
pub async fn mkdir_for<T: AsRef<std::path::Path>>(&self, path: T) -> Result<()> {
195-
if let Some(path) = path.as_ref().parent() {
196-
self.mkdir(path).await?;
185+
pub async fn mkdir_for(&self, path: &str) -> Result<()> {
186+
if let Some(path) = std::path::Path::new(path).parent() {
187+
self.mkdir(path.to_str().unwrap()).await?;
197188
}
198189
Ok(())
199190
}
200191

201-
pub async fn mknod<T: AsRef<std::path::Path>>(
202-
&self,
203-
node: T,
204-
(major, minor): (u32, u32),
205-
) -> Result<()> {
206-
self.rm(&node).await?;
207-
self.mkdir_for(&node).await?;
208-
self.exec([
209-
"mknod",
210-
&node.as_ref().to_string_lossy(),
211-
"c",
212-
&major.to_string(),
213-
&minor.to_string(),
214-
])
215-
.await?
216-
.collect()
217-
.await?;
218-
Ok(())
219-
}
220-
221-
pub async fn symlink<T: AsRef<std::path::Path>, U: AsRef<std::path::Path>>(
222-
&self,
223-
source: T,
224-
link: U,
225-
) -> Result<()> {
226-
self.mkdir_for(&link).await?;
227-
self.exec([
228-
"ln",
229-
"-sf",
230-
&source.as_ref().to_string_lossy(),
231-
&link.as_ref().to_string_lossy(),
232-
])
233-
.await?
234-
.collect()
235-
.await?;
192+
pub async fn mknod(&self, node: &str, (major, minor): (u32, u32)) -> Result<()> {
193+
self.rm(node).await?;
194+
self.mkdir_for(node).await?;
195+
self.exec(&["mknod", node, "c", &major.to_string(), &minor.to_string()])
196+
.await?
197+
.collect()
198+
.await?;
236199
Ok(())
237200
}
238201

239-
pub async fn rm<T: AsRef<std::path::Path>>(&self, node: T) -> Result<()> {
240-
self.exec(["rm", "-f", &node.as_ref().to_string_lossy()])
202+
pub async fn symlink(&self, source: &str, link: &str) -> Result<()> {
203+
self.mkdir_for(link).await?;
204+
self.exec(&["ln", "-sf", source, link])
241205
.await?
242206
.collect()
243207
.await?;
244208
Ok(())
245209
}
246210

211+
pub async fn rm(&self, node: &str) -> Result<()> {
212+
self.exec(&["rm", "-f", node]).await?.collect().await?;
213+
Ok(())
214+
}
215+
247216
pub async fn device(
248217
&self,
249218
(major, minor): (u32, u32),
@@ -328,7 +297,7 @@ fn signal_stream(kind: SignalKind) -> impl tokio_stream::Stream<Item = Result<Si
328297
async_stream::try_stream! {
329298
let sig_kind = SignalKind::hangup();
330299
let mut sig_stream = signal(kind)?;
331-
while let Some(_) = sig_stream.recv().await {
300+
while sig_stream.recv().await.is_some() {
332301
yield sig_kind;
333302
}
334303
}

src/hotplug/mod.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::docker::Container;
77

88
use async_stream::try_stream;
99

10-
use anyhow::Result;
10+
use anyhow::{Context, Result};
1111
use futures::stream::LocalBoxStream;
1212

1313
use std::collections::HashMap;
@@ -110,11 +110,12 @@ impl HotPlug {
110110
self.container
111111
.device(device.devnum(), (true, true, true))
112112
.await?;
113-
self.container
114-
.mknod(device.devnode(), device.devnum())
115-
.await?;
113+
let devnode = device.devnode().to_str().context("devnode is not UTF-8")?;
114+
self.container.mknod(devnode, device.devnum()).await?;
116115
if let Some(symlink) = device.symlink() {
117-
self.container.symlink(device.devnode(), symlink).await?;
116+
self.container
117+
.symlink(devnode, symlink.to_str().context("symlink is not UTF-8")?)
118+
.await?;
118119
}
119120
let syspath = device.syspath().to_owned();
120121
self.devices.insert(syspath, device.clone());
@@ -127,9 +128,13 @@ impl HotPlug {
127128
self.container
128129
.device(device.devnum(), (false, false, false))
129130
.await?;
130-
self.container.rm(device.devnode()).await?;
131+
self.container
132+
.rm(device.devnode().to_str().context("devnode is not UTF-8")?)
133+
.await?;
131134
if let Some(symlink) = device.symlink() {
132-
self.container.rm(symlink).await?;
135+
self.container
136+
.rm(symlink.to_str().context("devnode is not UTF-8")?)
137+
.await?;
133138
}
134139
Ok(Some(device))
135140
} else {

0 commit comments

Comments
 (0)