1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
//! `std::process` 模块中对原语的特定于 Unix 的扩展。

#![stable(feature = "rust1", since = "1.0.0")]

use crate::ffi::OsStr;
use crate::io;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::process;
use crate::sealed::Sealed;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

/// [`process::Command`] 构建器的特定于 Unix 的扩展。
///
/// trait 是密封的: 不能在标准库之外实现。
/// 这是为了将来的附加方法不会破坏更改。
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt: Sealed {
    /// 设置子进程的用户 ID。
    /// 这将转换为子进程中的 `setuid` 调用。
    /// `setuid` 调用失败将导致 spawn 失败。
    #[stable(feature = "rust1", since = "1.0.0")]
    fn uid(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] id: u32,
        #[cfg(target_os = "vxworks")] id: u16,
    ) -> &mut process::Command;

    /// 与 `uid` 相似,但是设置子进程的组 ID。
    /// 这具有与 `uid` 字段相同的语义。
    #[stable(feature = "rust1", since = "1.0.0")]
    fn gid(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] id: u32,
        #[cfg(target_os = "vxworks")] id: u16,
    ) -> &mut process::Command;

    /// 设置调用进程的补充组 ID。
    /// 在子进程中转换为 `setgroups` 调用。
    #[unstable(feature = "setgroups", issue = "38527", reason = "")]
    fn groups(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
        #[cfg(target_os = "vxworks")] groups: &[u16],
    ) -> &mut process::Command;

    /// 计划在 `exec` 函数被调用之前运行一个闭包。
    ///
    /// 允许闭包返回 I/O 错误,该错误的 OS 错误代码将被传达回父级,并从请求 spawn 开始作为错误返回。
    ///
    /// 可以注册多个闭包,并且将按照注册顺序对其进行调用。如果闭包返回 `Err`,则不会再调用任何闭包,并且 spawn 操作将立即失败返回。
    ///
    /// # 注意和安全
    ///
    /// `fork` 之后,此闭包将在子进程的上下文中运行。这主要意味着,代表此闭包对内存所做的任何修改对于父进程都是不可见的。
    /// 这通常是一个非常受限制的环境,无法保证正常操作 (如 `malloc`,通过 [`std::env`] 访问环境变量或获取互斥锁) (由于运行 `fork` 时可能仍在运行其他线程)。
    ///
    /// 有关更多详细信息,请参见 [POSIX fork() specification] 和任何目标平台的等效文档,尤其是有关 *async-signal-safety* 的要求。
    ///
    /// 这也意味着所有资源 (例如文件描述符和内存映射的区域) 都被复制了。您有责任通过无效使用这些重复项来确保闭包不违反库不变式。
    ///
    /// 只有当 panic 消息的所有格式参数都可以安全格式化时,闭包中的 panic 才是安全的; 这是因为尽管 `Command` 在调用 pre_exec hook 之前调用了 [`std::panic::always_abort`](crate::panic::always_abort),但 panic 仍会尝试格式化 panic 消息。
    ///
    ///
    /// 运行此闭包时,已成功更改了诸如标准输入输出文件描述符和工作目录之类的内容,因此在预期的位置可能不会显示输出到这些位置。
    ///
    /// [POSIX fork() specification]:
    ///     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
    /// [`std::env`]: mod@crate::env
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    #[stable(feature = "process_pre_exec", since = "1.34.0")]
    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
    where
        F: FnMut() -> io::Result<()> + Send + Sync + 'static;

    /// 计划在 `exec` 函数被调用之前运行一个闭包。
    ///
    ///
    /// 此方法稳定且可用,但不安全。
    /// 为了解决这个问题,它不赞成使用不安全的 [`pre_exec`]。
    ///
    /// [`pre_exec`]: CommandExt::pre_exec
    #[stable(feature = "process_exec", since = "1.15.0")]
    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
    where
        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
    {
        unsafe { self.pre_exec(f) }
    }

    /// 通过此 `Command` 执行所有必需的设置,然后调用 `execvp` syscall。
    ///
    /// 成功后,该函数将不会返回,否则它将返回错误,指示 exec (或 `Command` 的另一部分安装) 失败的原因。
    ///
    /// `exec` 不返回与调用 [`process::exit`] 具有相同的含义 - 当前栈或任何其他线程的栈上都不会运行析构函数。因此,建议仅在不运行任何析构函数的时候调用 `exec`。
    ///
    /// 请注意,`execvp` 系统调用独立保证释放所有内存,并关闭所有带有 `CLOEXEC` 选项的文件描述符 (默认情况下在标准库打开的所有文件描述符上设置)。
    ///
    /// 与 `spawn` 不同,此函数不会使用 `fork` 来创建一个新的子进程。但是,与 spawn 一样,标准输入输出描述符的默认行为将继承自当前进程。
    ///
    /// # Notes
    ///
    /// 如果此函数返回错误,则该进程可能在 "broken state" 中。例如,工作目录,环境变量,信号处理设置,各种 user/group 信息或标准输入输出文件描述符的各个方面可能已更改。
    /// 如果需要 "transactional spawn" 来妥善处理错误,建议改用跨平台 `spawn`。
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    #[stable(feature = "process_exec2", since = "1.9.0")]
    fn exec(&mut self) -> io::Error;

    /// 设置可执行参数
    ///
    /// 将第一个进程参数 `argv[0]` 设置为默认可执行路径以外的其他值。
    ///
    #[stable(feature = "process_set_argv0", since = "1.45.0")]
    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
    where
        S: AsRef<OsStr>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
    fn uid(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] id: u32,
        #[cfg(target_os = "vxworks")] id: u16,
    ) -> &mut process::Command {
        self.as_inner_mut().uid(id);
        self
    }

    fn gid(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] id: u32,
        #[cfg(target_os = "vxworks")] id: u16,
    ) -> &mut process::Command {
        self.as_inner_mut().gid(id);
        self
    }

    fn groups(
        &mut self,
        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
        #[cfg(target_os = "vxworks")] groups: &[u16],
    ) -> &mut process::Command {
        self.as_inner_mut().groups(groups);
        self
    }

    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
    where
        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
    {
        self.as_inner_mut().pre_exec(Box::new(f));
        self
    }

    fn exec(&mut self) -> io::Error {
        // NOTE: 在 `libc::fork` 之后调用此方法可能不是 * 安全的,因为它可能会分配。
        // 在 future 中的某个位置可能值得解决。
        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
    }

    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
    where
        S: AsRef<OsStr>,
    {
        self.as_inner_mut().set_arg_0(arg.as_ref());
        self
    }
}

/// [`process::ExitStatus`] 和 [`ExitStatusError`](process::ExitStatusError) 的 Unix 特定扩展。
///
/// 在 Unix 上,`ExitStatus`**不一定表示退出状态**,它已传递给 `exit` 系统调用或由 [`ExitStatus::code()`](crate::process::ExitStatus::code) 返回。
/// 它表示由 `wait` 系列系统调用之一返回的**任何等待状态**。
///
/// Unix 等待状态 (Rust `ExitStatus`) 可以代表 Unix 退出状态,但也可以代表其他类型的进程事件。
///
/// trait 是密封的: 不能在标准库之外实现。
/// 这是为了将来的附加方法不会破坏更改。
///
///
///
///
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt: Sealed {
    /// 从 `wait` 的原始底层整数状态值创建一个新的 `ExitStatus` 或 `ExitStatusError`
    ///
    ///
    /// 该值应该是等待状态,而不是退出状态。
    ///
    /// # Panics
    ///
    /// 尝试从 `0` 的等待状态生成 `ExitStatusError` 时出现 panic。
    ///
    /// 创建 `ExitStatus` 总是会成功的,并且从不 panics。
    #[stable(feature = "exit_status_from", since = "1.12.0")]
    fn from_raw(raw: i32) -> Self;

    /// 如果进程被一个信号终止,则返回该信号。
    ///
    /// 换句话说,如果为 `WIFSIGNALED`,则返回 `WTERMSIG`。
    #[stable(feature = "rust1", since = "1.0.0")]
    fn signal(&self) -> Option<i32>;

    /// 如果进程被一个信号终止,说明它是否丢弃了 core。
    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
    fn core_dumped(&self) -> bool;

    /// 如果该进程被信号停止,则返回该信号。
    ///
    /// 换句话说,如果为 `WIFSTOPPED`,则返回 `WSTOPSIG`。
    /// 这仅在状态来自 `wait` 系统调用时才可能,该系统调用通过 `WUNTRACED`,然后转换为 `ExitStatus`。
    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
    fn stopped_signal(&self) -> Option<i32>;

    /// 进程是否从停止状态继续。
    ///
    /// Ie, `WIFCONTINUED`.
    /// 这只有在状态来自 `wait` 系统调用时才有可能,该系统调用通过 `WCONTINUED`,然后转换为 `ExitStatus`。
    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
    fn continued(&self) -> bool;

    /// 返回基础的原始 `wait` 状态。
    ///
    /// 返回的整数是等待状态,而不是退出状态。
    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
    fn into_raw(self) -> i32;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
    fn from_raw(raw: i32) -> Self {
        process::ExitStatus::from_inner(From::from(raw))
    }

    fn signal(&self) -> Option<i32> {
        self.as_inner().signal()
    }

    fn core_dumped(&self) -> bool {
        self.as_inner().core_dumped()
    }

    fn stopped_signal(&self) -> Option<i32> {
        self.as_inner().stopped_signal()
    }

    fn continued(&self) -> bool {
        self.as_inner().continued()
    }

    fn into_raw(self) -> i32 {
        self.as_inner().into_raw().into()
    }
}

#[unstable(feature = "exit_status_error", issue = "84908")]
impl ExitStatusExt for process::ExitStatusError {
    fn from_raw(raw: i32) -> Self {
        process::ExitStatus::from_raw(raw)
            .exit_ok()
            .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
    }

    fn signal(&self) -> Option<i32> {
        self.into_status().signal()
    }

    fn core_dumped(&self) -> bool {
        self.into_status().core_dumped()
    }

    fn stopped_signal(&self) -> Option<i32> {
        self.into_status().stopped_signal()
    }

    fn continued(&self) -> bool {
        self.into_status().continued()
    }

    fn into_raw(self) -> i32 {
        self.into_status().into_raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
    #[inline]
    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
        let fd = sys::fd::FileDesc::new(fd);
        let io = sys::process::Stdio::Fd(fd);
        process::Stdio::from_inner(io)
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
    #[inline]
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
    #[inline]
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
    #[inline]
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
    #[inline]
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
    #[inline]
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
    #[inline]
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

/// 返回与此进程的父级关联的操作系统分配的进程标识符。
#[stable(feature = "unix_ppid", since = "1.27.0")]
pub fn parent_id() -> u32 {
    crate::sys::os::getppid()
}