55//! More information: <https://github.com/containers/skopeo/pull/1476>
66
77use anyhow:: { anyhow, Context , Result } ;
8- use futures_util:: { Future , FutureExt , TryFutureExt } ;
8+ use futures_util:: Future ;
99use nix:: sys:: socket:: { self as nixsocket, ControlMessageOwned } ;
1010use nix:: sys:: uio:: IoVec ;
1111use serde:: { Deserialize , Serialize } ;
1212use std:: fs:: File ;
1313use std:: os:: unix:: io:: AsRawFd ;
1414use std:: os:: unix:: prelude:: { FromRawFd , RawFd } ;
1515use std:: pin:: Pin ;
16- use std:: process:: { ExitStatus , Stdio } ;
16+ use std:: process:: Stdio ;
1717use std:: sync:: { Arc , Mutex } ;
1818use tokio:: io:: { AsyncBufRead , AsyncReadExt } ;
1919
@@ -65,13 +65,12 @@ struct Reply {
6565 value : serde_json:: Value ,
6666}
6767
68- type JoinFuture < T > = Pin < Box < dyn Future < Output = Result < Result < T > > > > > ;
68+ type ChildFuture = Pin < Box < dyn Future < Output = std :: io :: Result < std :: process :: Output > > > > ;
6969
7070/// Manage a child process proxy to fetch container images.
7171pub struct ImageProxy {
7272 sockfd : Arc < Mutex < File > > ,
73- stderr : JoinFuture < String > ,
74- procwait : Pin < Box < dyn Future < Output = Result < ExitStatus > > > > ,
73+ childwait : ChildFuture ,
7574}
7675
7776impl std:: fmt:: Debug for ImageProxy {
@@ -117,20 +116,8 @@ impl ImageProxy {
117116 c. stdin ( Stdio :: from ( theirsock) ) ;
118117 let mut c = tokio:: process:: Command :: from ( c) ;
119118 c. kill_on_drop ( true ) ;
120- let mut proc = c. spawn ( ) . context ( "Failed to spawn skopeo" ) ?;
121-
122- // Safety: We passed `Stdio::piped()` above
123- let mut child_stderr = proc. stderr . take ( ) . unwrap ( ) ;
124-
125- let stderr = tokio:: spawn ( async move {
126- let mut buf = String :: new ( ) ;
127- child_stderr. read_to_string ( & mut buf) . await ?;
128- Ok ( buf)
129- } )
130- . map_err ( anyhow:: Error :: msg)
131- . boxed ( ) ;
132-
133- let mut procwait = Box :: pin ( async move { proc. wait ( ) . map_err ( anyhow:: Error :: msg) . await } ) ;
119+ let child = c. spawn ( ) . context ( "Failed to spawn skopeo" ) ?;
120+ let mut childwait = Box :: pin ( child. wait_with_output ( ) ) ;
134121
135122 let sockfd = Arc :: new ( Mutex :: new ( mysock) ) ;
136123
@@ -141,9 +128,10 @@ impl ImageProxy {
141128 r = protoreq => {
142129 r?. 0
143130 }
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) ) ;
131+ r = & mut childwait => {
132+ let r = r?;
133+ let stderr = String :: from_utf8_lossy( & r. stderr) ;
134+ return Err ( anyhow!( "skopeo exited unexpectedly (no support for `experimental-image-proxy`?): {}\n {}" , r. status, stderr) ) ;
147135 }
148136 } ;
149137 let protover = semver:: Version :: parse ( protover. as_str ( ) ) ?;
@@ -156,11 +144,7 @@ impl ImageProxy {
156144 ) ) ;
157145 }
158146
159- let r = Self {
160- stderr,
161- sockfd,
162- procwait,
163- } ;
147+ let r = Self { sockfd, childwait } ;
164148 Ok ( r)
165149 }
166150
@@ -225,8 +209,17 @@ impl ImageProxy {
225209 T : IntoIterator < Item = I > ,
226210 I : Into < serde_json:: Value > ,
227211 {
228- let req = Request :: new ( method, args) ;
229- Self :: impl_request_raw ( Arc :: clone ( & self . sockfd ) , req) . await
212+ let req = Self :: impl_request_raw ( Arc :: clone ( & self . sockfd ) , Request :: new ( method, args) ) ;
213+ tokio:: select! {
214+ r = req => {
215+ Ok ( r?)
216+ }
217+ r = & mut self . childwait => {
218+ let r = r?;
219+ let stderr = String :: from_utf8_lossy( & r. stderr) ;
220+ return Err ( anyhow:: anyhow!( "proxy unexpectedly exited during request method {}: {}\n {}" , method, r. status, stderr) )
221+ }
222+ }
230223 }
231224
232225 async fn finish_pipe ( & mut self , pipeid : u32 ) -> Result < ( ) > {
@@ -293,13 +286,10 @@ impl ImageProxy {
293286 let sockfd = Arc :: try_unwrap ( self . sockfd ) . unwrap ( ) . into_inner ( ) . unwrap ( ) ;
294287 nixsocket:: send ( sockfd. as_raw_fd ( ) , & sendbuf, nixsocket:: MsgFlags :: empty ( ) ) ?;
295288 drop ( sendbuf) ;
296- let status = self . procwait . await ?;
297- if !status. success ( ) {
298- if let Some ( stderr) = self . stderr . await . map ( |v| v. ok ( ) ) . ok ( ) . flatten ( ) {
299- anyhow:: bail!( "proxy failed: {}\n {}" , status, stderr)
300- } else {
301- anyhow:: bail!( "proxy failed: {} (failed to fetch stderr)" , status)
302- }
289+ let output = self . childwait . await ?;
290+ if !output. status . success ( ) {
291+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
292+ anyhow:: bail!( "proxy failed: {}\n {}" , output. status, stderr)
303293 }
304294 Ok ( ( ) )
305295 }
0 commit comments