@@ -151,6 +151,53 @@ impl Command {
151151 self
152152 }
153153
154+ /// Set an auxiliary stream passed to the process, besides the stdio streams.
155+ ///
156+ /// # Safety
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.
161+ #[ cfg( unix) ]
162+ pub unsafe fn set_aux_fd < F : Into < std:: os:: fd:: OwnedFd > > (
163+ & mut self ,
164+ new_fd : std:: os:: fd:: RawFd ,
165+ fd : F ,
166+ ) -> & mut Self {
167+ // NOTE: If more than 1 auxiliary file descriptor is needed, this function should be
168+ // rewritten.
169+
170+ use std:: os:: fd:: AsRawFd ;
171+ use std:: os:: unix:: process:: CommandExt ;
172+
173+ let cvt = |x| if x == -1 { Err ( std:: io:: Error :: last_os_error ( ) ) } else { Ok ( ( ) ) } ;
174+
175+ let fd = fd. into ( ) ;
176+ if fd. as_raw_fd ( ) == new_fd {
177+ // If the new file descriptor is already the same as fd, just turn off `FD_CLOEXEC`.
178+
179+ // SAFETY(io-safety): `fd` is already owned.
180+ cvt ( unsafe { libc:: fcntl ( fd. as_raw_fd ( ) , libc:: F_SETFD , 0 ) } )
181+ . expect ( "disabling CLOEXEC failed" ) ;
182+ // The `pre_exec` function should be unconditionally set, since it captures `fd`, and
183+ // this ensures that it stays open until the fork.
184+ }
185+ let pre_exec = move || {
186+ if fd. as_raw_fd ( ) != new_fd {
187+ // SAFETY(io-safety): `new_fd` is not necessarily an unused fd. However, we're
188+ // ensuring that `new_fd` will now refer to the same file descriptor as `fd`, which
189+ // is safe as long as we manage the lifecycle of both descriptors correctly. This
190+ // operation will replace the file descriptor referred to by `new_fd` with the one
191+ // from `fd`, allowing for shared access to the same underlying file or resource.
192+ cvt ( unsafe { libc:: dup2 ( fd. as_raw_fd ( ) , new_fd) } ) ?;
193+ }
194+ Ok ( ( ) )
195+ } ;
196+ // SAFETY(pre-exec-safe): `dup2` is pre-exec-safe.
197+ unsafe { self . cmd . pre_exec ( pre_exec) } ;
198+ self
199+ }
200+
154201 /// Run the constructed command and assert that it is successfully run.
155202 ///
156203 /// By default, std{in,out,err} are [`Stdio::piped()`].
0 commit comments