Skip to content

Commit c2362e1

Browse files
committed
Handle case where skopeo exits unexpectedly
Confusingly, today running `skopeo some-unknown-command` just outputs usage information to stdout, and exits successfully. I'll probably fix that to exit with an error, but either way we need to handle the case where skopeo exits before we get a reply from the socketpair.
1 parent eed699f commit c2362e1

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

src/imageproxy.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::fs::File;
1313
use std::os::unix::io::AsRawFd;
1414
use std::os::unix::prelude::{FromRawFd, RawFd};
1515
use std::pin::Pin;
16-
use std::process::Stdio;
16+
use std::process::{ExitStatus, Stdio};
1717
use std::sync::{Arc, Mutex};
1818
use tokio::io::{AsyncBufRead, AsyncReadExt};
1919

@@ -69,9 +69,9 @@ type JoinFuture<T> = Pin<Box<dyn Future<Output = Result<Result<T>>>>>;
6969

7070
/// Manage a child process proxy to fetch container images.
7171
pub struct ImageProxy {
72-
proc: tokio::process::Child,
7372
sockfd: Arc<Mutex<File>>,
7473
stderr: JoinFuture<String>,
74+
procwait: Pin<Box<dyn Future<Output = Result<ExitStatus>>>>,
7575
}
7676

7777
impl std::fmt::Debug for ImageProxy {
@@ -130,12 +130,22 @@ impl ImageProxy {
130130
.map_err(anyhow::Error::msg)
131131
.boxed();
132132

133+
let mut procwait = Box::pin(async move { proc.wait().map_err(anyhow::Error::msg).await });
134+
133135
let sockfd = Arc::new(Mutex::new(mysock));
134136

135137
// Verify semantic version
136-
let (protover, _) =
137-
Self::impl_request_raw::<String>(Arc::clone(&sockfd), Request::new_bare("Initialize"))
138-
.await?;
138+
let protoreq =
139+
Self::impl_request_raw::<String>(Arc::clone(&sockfd), Request::new_bare("Initialize"));
140+
let protover = tokio::select! {
141+
r = protoreq => {
142+
r?.0
143+
}
144+
r = &mut procwait => {
145+
let errmsg = stderr.await??;
146+
return Err(anyhow!("skopeo exited unexpectedly (no support for `experimental-image-proxy`?): {}\n{}", r?, errmsg));
147+
}
148+
};
139149
let protover = semver::Version::parse(protover.as_str())?;
140150
let supported = &*SUPPORTED_PROTO_VERSION;
141151
if !supported.matches(&protover) {
@@ -147,9 +157,9 @@ impl ImageProxy {
147157
}
148158

149159
let r = Self {
150-
proc,
151160
stderr,
152161
sockfd,
162+
procwait,
153163
};
154164
Ok(r)
155165
}
@@ -276,14 +286,14 @@ impl ImageProxy {
276286
}
277287

278288
/// Close the connection and wait for the child process to exit successfully.
279-
pub async fn finalize(mut self) -> Result<()> {
289+
pub async fn finalize(self) -> Result<()> {
280290
let req = Request::new_bare("Shutdown");
281291
let sendbuf = serde_json::to_vec(&req)?;
282292
// SAFETY: Only panics if a worker thread already panic'd
283293
let sockfd = Arc::try_unwrap(self.sockfd).unwrap().into_inner().unwrap();
284294
nixsocket::send(sockfd.as_raw_fd(), &sendbuf, nixsocket::MsgFlags::empty())?;
285295
drop(sendbuf);
286-
let status = self.proc.wait().await?;
296+
let status = self.procwait.await?;
287297
if !status.success() {
288298
if let Some(stderr) = self.stderr.await.map(|v| v.ok()).ok().flatten() {
289299
anyhow::bail!("proxy failed: {}\n{}", status, stderr)

0 commit comments

Comments
 (0)