1 | //! Unix-specific extensions. |
2 | |
3 | use std::ffi::OsStr; |
4 | use std::io; |
5 | use std::os::unix::process::CommandExt as _; |
6 | |
7 | use crate::Command; |
8 | |
9 | /// Unix-specific extensions to the [`Command`] builder. |
10 | /// |
11 | /// This trait is sealed: it cannot be implemented outside `async-process`. |
12 | /// This is so that future additional methods are not breaking changes. |
13 | pub trait CommandExt: crate::sealed::Sealed { |
14 | /// Sets the child process's user ID. This translates to a |
15 | /// `setuid` call in the child process. Failure in the `setuid` |
16 | /// call will cause the spawn to fail. |
17 | fn uid(&mut self, id: u32) -> &mut Command; |
18 | |
19 | /// Similar to `uid`, but sets the group ID of the child process. This has |
20 | /// the same semantics as the `uid` field. |
21 | fn gid(&mut self, id: u32) -> &mut Command; |
22 | |
23 | /// Performs all the required setup by this `Command`, followed by calling |
24 | /// the `execvp` syscall. |
25 | /// |
26 | /// On success this function will not return, and otherwise it will return |
27 | /// an error indicating why the exec (or another part of the setup of the |
28 | /// `Command`) failed. |
29 | /// |
30 | /// `exec` not returning has the same implications as calling |
31 | /// [`std::process::exit`] – no destructors on the current stack or any other |
32 | /// thread’s stack will be run. Therefore, it is recommended to only call |
33 | /// `exec` at a point where it is fine to not run any destructors. Note, |
34 | /// that the `execvp` syscall independently guarantees that all memory is |
35 | /// freed and all file descriptors with the `CLOEXEC` option (set by default |
36 | /// on all file descriptors opened by the standard library) are closed. |
37 | /// |
38 | /// This function, unlike `spawn`, will **not** `fork` the process to create |
39 | /// a new child. Like spawn, however, the default behavior for the stdio |
40 | /// descriptors will be to inherited from the current process. |
41 | /// |
42 | /// # Notes |
43 | /// |
44 | /// The process may be in a "broken state" if this function returns in |
45 | /// error. For example the working directory, environment variables, signal |
46 | /// handling settings, various user/group information, or aspects of stdio |
47 | /// file descriptors may have changed. If a "transactional spawn" is |
48 | /// required to gracefully handle errors it is recommended to use the |
49 | /// cross-platform `spawn` instead. |
50 | fn exec(&mut self) -> io::Error; |
51 | |
52 | /// Set executable argument |
53 | /// |
54 | /// Set the first process argument, `argv[0]`, to something other than the |
55 | /// default executable path. |
56 | fn arg0<S>(&mut self, arg: S) -> &mut Command |
57 | where |
58 | S: AsRef<OsStr>; |
59 | } |
60 | |
61 | impl crate::sealed::Sealed for Command {} |
62 | impl CommandExt for Command { |
63 | fn uid(&mut self, id: u32) -> &mut Command { |
64 | self.inner.uid(id); |
65 | self |
66 | } |
67 | |
68 | fn gid(&mut self, id: u32) -> &mut Command { |
69 | self.inner.gid(id); |
70 | self |
71 | } |
72 | |
73 | fn exec(&mut self) -> io::Error { |
74 | self.inner.exec() |
75 | } |
76 | |
77 | fn arg0<S>(&mut self, arg: S) -> &mut Command |
78 | where |
79 | S: AsRef<OsStr>, |
80 | { |
81 | self.inner.arg0(arg); |
82 | self |
83 | } |
84 | } |
85 | |