@@ -81,62 +81,63 @@ impl Client {
81
81
Ok ( Client :: from_fds ( pipes[ 0 ] , pipes[ 1 ] ) )
82
82
}
83
83
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
+ ) )
86
95
}
87
96
88
97
/// `--jobserver-auth=fifo:PATH`
89
- fn from_fifo ( s : & str ) -> Option < Client > {
98
+ fn from_fifo ( s : & str ) -> io :: Result < Option < Client > > {
90
99
let mut parts = s. splitn ( 2 , ':' ) ;
91
100
if parts. next ( ) . unwrap ( ) != "fifo" {
92
- return None ;
101
+ return Ok ( None ) ;
93
102
}
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 {
103
108
file,
104
109
path : path. into ( ) ,
105
- } )
110
+ } ) )
106
111
}
107
112
108
113
/// `--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 > > {
110
115
let mut parts = s. splitn ( 2 , ',' ) ;
111
116
let read = parts. next ( ) . unwrap ( ) ;
112
117
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 ) ,
124
120
} ;
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) ) ?;
125
127
126
128
// Ok so we've got two integers that look like file descriptors, but
127
129
// 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.
129
132
//
130
133
// If we're called from `make` *without* the leading + on our rule
131
134
// then we'll have `MAKEFLAGS` env vars but won't actually have
132
135
// 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) ) )
140
141
}
141
142
142
143
unsafe fn from_fds ( read : c_int , write : c_int ) -> Client {
@@ -207,7 +208,7 @@ impl Client {
207
208
return Err ( io:: Error :: new (
208
209
io:: ErrorKind :: Other ,
209
210
"early EOF on jobserver pipe" ,
210
- ) )
211
+ ) ) ;
211
212
}
212
213
Err ( e) => match e. kind ( ) {
213
214
io:: ErrorKind :: WouldBlock => { /* fall through to polling */ }
@@ -326,7 +327,7 @@ pub(crate) fn spawn_helper(
326
327
client : client. inner . clone ( ) ,
327
328
data,
328
329
disabled : false ,
329
- } ) )
330
+ } ) ) ;
330
331
}
331
332
Err ( e) => break f ( Err ( e) ) ,
332
333
Ok ( None ) if helper. producer_done ( ) => break ,
@@ -385,8 +386,32 @@ impl Helper {
385
386
}
386
387
}
387
388
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
+ }
390
415
}
391
416
392
417
fn set_cloexec ( fd : c_int , set : bool ) -> io:: Result < ( ) > {
0 commit comments