]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Unix-specific extensions to primitives in the `std::process` module. | |
12 | ||
13 | #![stable(feature = "rust1", since = "1.0.0")] | |
14 | ||
7453a54e SL |
15 | use prelude::v1::*; |
16 | ||
17 | use io; | |
c1a9b12d | 18 | use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; |
d9579d0f AL |
19 | use process; |
20 | use sys; | |
c1a9b12d | 21 | use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; |
d9579d0f AL |
22 | |
23 | /// Unix-specific extensions to the `std::process::Command` builder | |
24 | #[stable(feature = "rust1", since = "1.0.0")] | |
25 | pub trait CommandExt { | |
26 | /// Sets the child process's user id. This translates to a | |
27 | /// `setuid` call in the child process. Failure in the `setuid` | |
28 | /// call will cause the spawn to fail. | |
29 | #[stable(feature = "rust1", since = "1.0.0")] | |
7453a54e | 30 | fn uid(&mut self, id: u32) -> &mut process::Command; |
d9579d0f AL |
31 | |
32 | /// Similar to `uid`, but sets the group id of the child process. This has | |
33 | /// the same semantics as the `uid` field. | |
34 | #[stable(feature = "rust1", since = "1.0.0")] | |
7453a54e | 35 | fn gid(&mut self, id: u32) -> &mut process::Command; |
e9174d1e SL |
36 | |
37 | /// Create a new session (cf. `setsid(2)`) for the child process. This means | |
38 | /// that the child is the leader of a new process group. The parent process | |
39 | /// remains the child reaper of the new process. | |
40 | /// | |
41 | /// This is not enough to create a daemon process. The *init* process should | |
42 | /// be the child reaper of a daemon. This can be achieved if the parent | |
43 | /// process exit. Moreover, a daemon should not have a controlling terminal. | |
b039eaaf | 44 | /// To achieve this, a session leader (the child) must spawn another process |
e9174d1e SL |
45 | /// (the daemon) in the same session. |
46 | #[unstable(feature = "process_session_leader", reason = "recently added", | |
47 | issue = "27811")] | |
54a0048b SL |
48 | #[rustc_deprecated(reason = "use `before_exec` instead", |
49 | since = "1.9.0")] | |
e9174d1e | 50 | fn session_leader(&mut self, on: bool) -> &mut process::Command; |
7453a54e SL |
51 | |
52 | /// Schedules a closure to be run just before the `exec` function is | |
53 | /// invoked. | |
54 | /// | |
55 | /// The closure is allowed to return an I/O error whose OS error code will | |
56 | /// be communicated back to the parent and returned as an error from when | |
57 | /// the spawn was requested. | |
58 | /// | |
59 | /// Multiple closures can be registered and they will be called in order of | |
60 | /// their registration. If a closure returns `Err` then no further closures | |
61 | /// will be called and the spawn operation will immediately return with a | |
62 | /// failure. | |
63 | /// | |
64 | /// # Notes | |
65 | /// | |
66 | /// This closure will be run in the context of the child process after a | |
67 | /// `fork`. This primarily means that any modificatons made to memory on | |
68 | /// behalf of this closure will **not** be visible to the parent process. | |
69 | /// This is often a very constrained environment where normal operations | |
70 | /// like `malloc` or acquiring a mutex are not guaranteed to work (due to | |
71 | /// other threads perhaps still running when the `fork` was run). | |
72 | /// | |
73 | /// When this closure is run, aspects such as the stdio file descriptors and | |
74 | /// working directory have successfully been changed, so output to these | |
75 | /// locations may not appear where intended. | |
76 | #[unstable(feature = "process_exec", issue = "31398")] | |
77 | fn before_exec<F>(&mut self, f: F) -> &mut process::Command | |
78 | where F: FnMut() -> io::Result<()> + Send + Sync + 'static; | |
79 | ||
80 | /// Performs all the required setup by this `Command`, followed by calling | |
81 | /// the `execvp` syscall. | |
82 | /// | |
83 | /// On success this function will not return, and otherwise it will return | |
84 | /// an error indicating why the exec (or another part of the setup of the | |
85 | /// `Command`) failed. | |
86 | /// | |
87 | /// This function, unlike `spawn`, will **not** `fork` the process to create | |
88 | /// a new child. Like spawn, however, the default behavior for the stdio | |
89 | /// descriptors will be to inherited from the current process. | |
90 | /// | |
91 | /// # Notes | |
92 | /// | |
93 | /// The process may be in a "broken state" if this function returns in | |
94 | /// error. For example the working directory, environment variables, signal | |
95 | /// handling settings, various user/group information, or aspects of stdio | |
96 | /// file descriptors may have changed. If a "transactional spawn" is | |
97 | /// required to gracefully handle errors it is recommended to use the | |
98 | /// cross-platform `spawn` instead. | |
54a0048b | 99 | #[stable(feature = "process_exec2", since = "1.9.0")] |
7453a54e | 100 | fn exec(&mut self) -> io::Error; |
d9579d0f AL |
101 | } |
102 | ||
103 | #[stable(feature = "rust1", since = "1.0.0")] | |
104 | impl CommandExt for process::Command { | |
7453a54e SL |
105 | fn uid(&mut self, id: u32) -> &mut process::Command { |
106 | self.as_inner_mut().uid(id); | |
d9579d0f AL |
107 | self |
108 | } | |
109 | ||
7453a54e SL |
110 | fn gid(&mut self, id: u32) -> &mut process::Command { |
111 | self.as_inner_mut().gid(id); | |
d9579d0f AL |
112 | self |
113 | } | |
e9174d1e SL |
114 | |
115 | fn session_leader(&mut self, on: bool) -> &mut process::Command { | |
7453a54e SL |
116 | self.as_inner_mut().session_leader(on); |
117 | self | |
118 | } | |
119 | ||
120 | fn before_exec<F>(&mut self, f: F) -> &mut process::Command | |
121 | where F: FnMut() -> io::Result<()> + Send + Sync + 'static | |
122 | { | |
123 | self.as_inner_mut().before_exec(Box::new(f)); | |
e9174d1e SL |
124 | self |
125 | } | |
7453a54e SL |
126 | |
127 | fn exec(&mut self) -> io::Error { | |
128 | self.as_inner_mut().exec(sys::process::Stdio::Inherit) | |
129 | } | |
d9579d0f AL |
130 | } |
131 | ||
132 | /// Unix-specific extensions to `std::process::ExitStatus` | |
133 | #[stable(feature = "rust1", since = "1.0.0")] | |
134 | pub trait ExitStatusExt { | |
135 | /// If the process was terminated by a signal, returns that signal. | |
136 | #[stable(feature = "rust1", since = "1.0.0")] | |
137 | fn signal(&self) -> Option<i32>; | |
138 | } | |
139 | ||
140 | #[stable(feature = "rust1", since = "1.0.0")] | |
141 | impl ExitStatusExt for process::ExitStatus { | |
142 | fn signal(&self) -> Option<i32> { | |
92a42be0 | 143 | self.as_inner().signal() |
d9579d0f AL |
144 | } |
145 | } | |
62682a34 SL |
146 | |
147 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
148 | impl FromRawFd for process::Stdio { | |
149 | unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { | |
7453a54e SL |
150 | let fd = sys::fd::FileDesc::new(fd); |
151 | let io = sys::process::Stdio::Fd(fd); | |
152 | process::Stdio::from_inner(io) | |
62682a34 SL |
153 | } |
154 | } | |
155 | ||
156 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
157 | impl AsRawFd for process::ChildStdin { | |
158 | fn as_raw_fd(&self) -> RawFd { | |
159 | self.as_inner().fd().raw() | |
160 | } | |
161 | } | |
162 | ||
163 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
164 | impl AsRawFd for process::ChildStdout { | |
165 | fn as_raw_fd(&self) -> RawFd { | |
166 | self.as_inner().fd().raw() | |
167 | } | |
168 | } | |
169 | ||
170 | #[stable(feature = "process_extensions", since = "1.2.0")] | |
171 | impl AsRawFd for process::ChildStderr { | |
172 | fn as_raw_fd(&self) -> RawFd { | |
173 | self.as_inner().fd().raw() | |
174 | } | |
175 | } | |
c1a9b12d | 176 | |
92a42be0 | 177 | #[stable(feature = "process_extensions", since = "1.2.0")] |
c1a9b12d SL |
178 | impl IntoRawFd for process::ChildStdin { |
179 | fn into_raw_fd(self) -> RawFd { | |
180 | self.into_inner().into_fd().into_raw() | |
181 | } | |
182 | } | |
183 | ||
92a42be0 | 184 | #[stable(feature = "process_extensions", since = "1.2.0")] |
c1a9b12d SL |
185 | impl IntoRawFd for process::ChildStdout { |
186 | fn into_raw_fd(self) -> RawFd { | |
187 | self.into_inner().into_fd().into_raw() | |
188 | } | |
189 | } | |
190 | ||
92a42be0 | 191 | #[stable(feature = "process_extensions", since = "1.2.0")] |
c1a9b12d SL |
192 | impl IntoRawFd for process::ChildStderr { |
193 | fn into_raw_fd(self) -> RawFd { | |
194 | self.into_inner().into_fd().into_raw() | |
195 | } | |
196 | } |