@@ -25,6 +25,13 @@ pub struct Acquired {
25
25
byte : u8 ,
26
26
}
27
27
28
+ #[ derive( Debug ) ]
29
+ pub enum ErrFromEnv {
30
+ ParseEnvVar ,
31
+ OpenFile ( String ) ,
32
+ InvalidDescriptor ( i32 , i32 ) ,
33
+ }
34
+
28
35
impl Client {
29
36
pub fn new ( mut limit : usize ) -> io:: Result < Client > {
30
37
let client = unsafe { Client :: mk ( ) ? } ;
@@ -81,61 +88,66 @@ impl Client {
81
88
Ok ( Client :: from_fds ( pipes[ 0 ] , pipes[ 1 ] ) )
82
89
}
83
90
84
- pub unsafe fn open ( s : & str ) -> Option < Client > {
85
- Client :: from_fifo ( s) . or_else ( || Client :: from_pipe ( s) )
91
+ pub unsafe fn open ( s : & str ) -> Result < Client , ErrFromEnv > {
92
+ match ( Self :: from_fifo ( s) , Self :: from_pipe ( s) ) {
93
+ ( Some ( result) , None ) | ( None , Some ( result) ) => result,
94
+ ( None , None ) => Err ( ErrFromEnv :: ParseEnvVar ) ,
95
+ ( Some ( _) , Some ( _) ) => unreachable ! ( ) ,
96
+ }
86
97
}
87
98
88
99
/// `--jobserver-auth=fifo:PATH`
89
- fn from_fifo ( s : & str ) -> Option < Client > {
100
+ fn from_fifo ( s : & str ) -> Option < Result < Client , ErrFromEnv > > {
90
101
let mut parts = s. splitn ( 2 , ':' ) ;
91
102
if parts. next ( ) . unwrap ( ) != "fifo" {
92
103
return None ;
93
104
}
94
105
let path = match parts. next ( ) {
95
106
Some ( p) => Path :: new ( p) ,
96
- None => return None ,
107
+ None => return Some ( Err ( ErrFromEnv :: ParseEnvVar ) ) ,
97
108
} ;
98
109
let file = match OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( path) {
99
110
Ok ( f) => f,
100
- Err ( _ ) => return None ,
111
+ Err ( e ) => return Some ( Err ( ErrFromEnv :: OpenFile ( e . to_string ( ) ) ) ) ,
101
112
} ;
102
- Some ( Client :: Fifo {
113
+ Some ( Ok ( Client :: Fifo {
103
114
file,
104
115
path : path. into ( ) ,
105
- } )
116
+ } ) )
106
117
}
107
118
108
119
/// `--jobserver-auth=R,W`
109
- unsafe fn from_pipe ( s : & str ) -> Option < Client > {
120
+ unsafe fn from_pipe ( s : & str ) -> Option < Result < Client , ErrFromEnv > > {
110
121
let mut parts = s. splitn ( 2 , ',' ) ;
111
122
let read = parts. next ( ) . unwrap ( ) ;
112
123
let write = match parts. next ( ) {
113
124
Some ( s) => s,
114
- None => return None ,
125
+ None => return Some ( Err ( ErrFromEnv :: ParseEnvVar ) ) ,
115
126
} ;
116
127
117
128
let read = match read. parse ( ) {
118
129
Ok ( n) => n,
119
- Err ( _) => return None ,
130
+ Err ( _) => return Some ( Err ( ErrFromEnv :: ParseEnvVar ) ) ,
120
131
} ;
121
132
let write = match write. parse ( ) {
122
133
Ok ( n) => n,
123
- Err ( _) => return None ,
134
+ Err ( _) => return Some ( Err ( ErrFromEnv :: ParseEnvVar ) ) ,
124
135
} ;
125
136
126
137
// Ok so we've got two integers that look like file descriptors, but
127
138
// for extra sanity checking let's see if they actually look like
128
- // instances of a pipe before we return the client.
139
+ // instances of a pipe if feature enabled or valid files otherwise
140
+ // before we return the client.
129
141
//
130
142
// If we're called from `make` *without* the leading + on our rule
131
143
// then we'll have `MAKEFLAGS` env vars but won't actually have
132
144
// access to the file descriptors.
133
- if is_valid_fd ( read) && is_valid_fd ( write) {
145
+ if check_fd ( read) && check_fd ( write) {
134
146
drop ( set_cloexec ( read, true ) ) ;
135
147
drop ( set_cloexec ( write, true ) ) ;
136
- Some ( Client :: from_fds ( read, write) )
148
+ Some ( Ok ( Client :: from_fds ( read, write) ) )
137
149
} else {
138
- None
150
+ Some ( Err ( ErrFromEnv :: InvalidDescriptor ( read , write ) ) )
139
151
}
140
152
}
141
153
@@ -207,7 +219,7 @@ impl Client {
207
219
return Err ( io:: Error :: new (
208
220
io:: ErrorKind :: Other ,
209
221
"early EOF on jobserver pipe" ,
210
- ) )
222
+ ) ) ;
211
223
}
212
224
Err ( e) => match e. kind ( ) {
213
225
io:: ErrorKind :: WouldBlock => { /* fall through to polling */ }
@@ -326,7 +338,7 @@ pub(crate) fn spawn_helper(
326
338
client : client. inner . clone ( ) ,
327
339
data,
328
340
disabled : false ,
329
- } ) )
341
+ } ) ) ;
330
342
}
331
343
Err ( e) => break f ( Err ( e) ) ,
332
344
Ok ( None ) if helper. producer_done ( ) => break ,
@@ -385,8 +397,26 @@ impl Helper {
385
397
}
386
398
}
387
399
388
- fn is_valid_fd ( fd : c_int ) -> bool {
389
- unsafe { libc:: fcntl ( fd, libc:: F_GETFD ) != -1 }
400
+ fn check_fd ( fd : c_int ) -> bool {
401
+ #[ cfg( feature = "check_pipe" ) ]
402
+ unsafe {
403
+ let mut stat = mem:: zeroed ( ) ;
404
+ if libc:: fstat ( fd, & mut stat) == 0 {
405
+ // On android arm and i686 mode_t is u16 and st_mode is u32,
406
+ // this generates a type mismatch when S_IFIFO (declared as mode_t)
407
+ // is used in operations with st_mode, so we use this workaround
408
+ // to get the value of S_IFIFO with the same type of st_mode.
409
+ let mut s_ififo = stat. st_mode ;
410
+ s_ififo = libc:: S_IFIFO as _ ;
411
+ stat. st_mode & s_ififo == s_ififo
412
+ } else {
413
+ false
414
+ }
415
+ }
416
+ #[ cfg( not( feature = "check_pipe" ) ) ]
417
+ unsafe {
418
+ libc:: fcntl ( fd, libc:: F_GETFD ) != -1
419
+ }
390
420
}
391
421
392
422
fn set_cloexec ( fd : c_int , set : bool ) -> io:: Result < ( ) > {
0 commit comments