@@ -81,62 +81,63 @@ impl Client {
8181 Ok ( Client :: from_fds ( pipes[ 0 ] , pipes[ 1 ] ) )
8282 }
8383
84- pub unsafe fn open ( s : & str ) -> Option < Client > {
85- Client :: from_fifo ( s) . or_else ( || Client :: from_pipe ( s) )
84+ pub unsafe fn open ( s : & str , check_pipe : bool ) -> io:: Result < Client > {
85+ if let Some ( client) = Self :: from_fifo ( s) ? {
86+ return Ok ( client) ;
87+ }
88+ if let Some ( client) = Self :: from_pipe ( s, check_pipe) ? {
89+ return Ok ( client) ;
90+ }
91+ Err ( io:: Error :: new (
92+ io:: ErrorKind :: InvalidInput ,
93+ "unrecognized format of environment variable" ,
94+ ) )
8695 }
8796
8897 /// `--jobserver-auth=fifo:PATH`
89- fn from_fifo ( s : & str ) -> Option < Client > {
98+ fn from_fifo ( s : & str ) -> io :: Result < Option < Client > > {
9099 let mut parts = s. splitn ( 2 , ':' ) ;
91100 if parts. next ( ) . unwrap ( ) != "fifo" {
92- return None ;
101+ return Ok ( None ) ;
93102 }
94- let path = match parts. next ( ) {
95- Some ( p) => Path :: new ( p) ,
96- None => return None ,
97- } ;
98- let file = match OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( path) {
99- Ok ( f) => f,
100- Err ( _) => return None ,
101- } ;
102- Some ( Client :: Fifo {
103+ let path = Path :: new ( parts. next ( ) . ok_or_else ( || {
104+ io:: Error :: new ( io:: ErrorKind :: InvalidInput , "expected ':' after `fifo`" )
105+ } ) ?) ;
106+ let file = OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( path) ?;
107+ Ok ( Some ( Client :: Fifo {
103108 file,
104109 path : path. into ( ) ,
105- } )
110+ } ) )
106111 }
107112
108113 /// `--jobserver-auth=R,W`
109- unsafe fn from_pipe ( s : & str ) -> Option < Client > {
114+ unsafe fn from_pipe ( s : & str , check_pipe : bool ) -> io :: Result < Option < Client > > {
110115 let mut parts = s. splitn ( 2 , ',' ) ;
111116 let read = parts. next ( ) . unwrap ( ) ;
112117 let write = match parts. next ( ) {
113- Some ( s) => s,
114- None => return None ,
115- } ;
116-
117- let read = match read. parse ( ) {
118- Ok ( n) => n,
119- Err ( _) => return None ,
120- } ;
121- let write = match write. parse ( ) {
122- Ok ( n) => n,
123- Err ( _) => return None ,
118+ Some ( w) => w,
119+ None => return Ok ( None ) ,
124120 } ;
121+ let read = read
122+ . parse ( )
123+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
124+ let write = write
125+ . parse ( )
126+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
125127
126128 // Ok so we've got two integers that look like file descriptors, but
127129 // for extra sanity checking let's see if they actually look like
128- // instances of a pipe before we return the client.
130+ // instances of a pipe if feature enabled or valid files otherwise
131+ // before we return the client.
129132 //
130133 // If we're called from `make` *without* the leading + on our rule
131134 // then we'll have `MAKEFLAGS` env vars but won't actually have
132135 // access to the file descriptors.
133- if is_valid_fd ( read) && is_valid_fd ( write) {
134- drop ( set_cloexec ( read, true ) ) ;
135- drop ( set_cloexec ( write, true ) ) ;
136- Some ( Client :: from_fds ( read, write) )
137- } else {
138- None
139- }
136+ check_fd ( read, check_pipe) ?;
137+ check_fd ( write, check_pipe) ?;
138+ drop ( set_cloexec ( read, true ) ) ;
139+ drop ( set_cloexec ( write, true ) ) ;
140+ Ok ( Some ( Client :: from_fds ( read, write) ) )
140141 }
141142
142143 unsafe fn from_fds ( read : c_int , write : c_int ) -> Client {
@@ -207,7 +208,7 @@ impl Client {
207208 return Err ( io:: Error :: new (
208209 io:: ErrorKind :: Other ,
209210 "early EOF on jobserver pipe" ,
210- ) )
211+ ) ) ;
211212 }
212213 Err ( e) => match e. kind ( ) {
213214 io:: ErrorKind :: WouldBlock => { /* fall through to polling */ }
@@ -326,7 +327,7 @@ pub(crate) fn spawn_helper(
326327 client : client. inner . clone ( ) ,
327328 data,
328329 disabled : false ,
329- } ) )
330+ } ) ) ;
330331 }
331332 Err ( e) => break f ( Err ( e) ) ,
332333 Ok ( None ) if helper. producer_done ( ) => break ,
@@ -385,8 +386,32 @@ impl Helper {
385386 }
386387}
387388
388- fn is_valid_fd ( fd : c_int ) -> bool {
389- unsafe { libc:: fcntl ( fd, libc:: F_GETFD ) != -1 }
389+ unsafe fn check_fd ( fd : c_int , check_pipe : bool ) -> io:: Result < ( ) > {
390+ if check_pipe {
391+ let mut stat = mem:: zeroed ( ) ;
392+ if libc:: fstat ( fd, & mut stat) == -1 {
393+ Err ( io:: Error :: last_os_error ( ) )
394+ } else {
395+ // On android arm and i686 mode_t is u16 and st_mode is u32,
396+ // this generates a type mismatch when S_IFIFO (declared as mode_t)
397+ // is used in operations with st_mode, so we use this workaround
398+ // to get the value of S_IFIFO with the same type of st_mode.
399+ let mut s_ififo = stat. st_mode ;
400+ s_ififo = libc:: S_IFIFO as _ ;
401+ if stat. st_mode & s_ififo == s_ififo {
402+ return Ok ( ( ) ) ;
403+ }
404+ Err ( io:: Error :: last_os_error ( ) ) //
405+ }
406+ } else {
407+ match libc:: fcntl ( fd, libc:: F_GETFD ) {
408+ r if r == -1 => Err ( io:: Error :: new (
409+ io:: ErrorKind :: InvalidData ,
410+ format ! ( "{fd} is not a pipe" ) ,
411+ ) ) ,
412+ _ => Ok ( ( ) ) ,
413+ }
414+ }
390415}
391416
392417fn set_cloexec ( fd : c_int , set : bool ) -> io:: Result < ( ) > {
0 commit comments