@@ -151,6 +151,61 @@ impl Command {
151
151
self
152
152
}
153
153
154
+ /// Set an auxiliary stream passed to the process, besides the stdio streams.
155
+ ///
156
+ /// # Notes
157
+ ///
158
+ /// Use with caution! Ideally, only set one aux fd; if there are multiple, their old `fd` may
159
+ /// overlap with another's `new_fd`, and may break. The caller must make sure this is not the
160
+ /// case. This function is only "safe" because the safety requirements are practically not
161
+ /// possible to uphold.
162
+ #[ cfg( unix) ]
163
+ pub fn set_aux_fd < F : Into < std:: os:: fd:: OwnedFd > > (
164
+ & mut self ,
165
+ new_fd : std:: os:: fd:: RawFd ,
166
+ fd : F ,
167
+ ) -> & mut Self {
168
+ use std:: mem;
169
+ // NOTE: If more than 1 auxiliary file descriptor is needed, this function should be
170
+ // rewritten.
171
+ use std:: os:: fd:: AsRawFd ;
172
+ use std:: os:: unix:: process:: CommandExt ;
173
+
174
+ let cvt = |x| if x == -1 { Err ( std:: io:: Error :: last_os_error ( ) ) } else { Ok ( ( ) ) } ;
175
+
176
+ // Ensure fd stays open until the fork.
177
+ let fd = mem:: ManuallyDrop :: new ( fd. into ( ) ) ;
178
+ let fd = fd. as_raw_fd ( ) ;
179
+
180
+ if fd == new_fd {
181
+ // If the new file descriptor is already the same as fd, just turn off `FD_CLOEXEC`.
182
+ let fd_flags = {
183
+ let ret = unsafe { libc:: fcntl ( fd, libc:: F_GETFD , 0 ) } ;
184
+ if ret < 0 {
185
+ panic ! ( "failed to read fd flags: {}" , std:: io:: Error :: last_os_error( ) ) ;
186
+ }
187
+ ret
188
+ } ;
189
+ // Clear `FD_CLOEXEC`.
190
+ let fd_flags = fd_flags & !libc:: FD_CLOEXEC ;
191
+
192
+ // SAFETY(io-safety): `fd` is already owned.
193
+ cvt ( unsafe { libc:: fcntl ( fd, libc:: F_SETFD , fd_flags as libc:: c_int ) } )
194
+ . expect ( "disabling CLOEXEC failed" ) ;
195
+ }
196
+ let pre_exec = move || {
197
+ if fd. as_raw_fd ( ) != new_fd {
198
+ // SAFETY(io-safety): it's the caller's responsibility that we won't override the
199
+ // target fd.
200
+ cvt ( unsafe { libc:: dup2 ( fd, new_fd) } ) ?;
201
+ }
202
+ Ok ( ( ) )
203
+ } ;
204
+ // SAFETY(pre-exec-safe): `dup2` is pre-exec-safe.
205
+ unsafe { self . cmd . pre_exec ( pre_exec) } ;
206
+ self
207
+ }
208
+
154
209
/// Run the constructed command and assert that it is successfully run.
155
210
///
156
211
/// By default, std{in,out,err} are [`Stdio::piped()`].
0 commit comments