yash_env/
system.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2021 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! [System] and its implementors.
18
19mod errno;
20mod fd_flag;
21mod file_system;
22mod id;
23mod open_flag;
24#[cfg(unix)]
25pub mod real;
26pub mod resource;
27mod select;
28mod shared;
29pub mod r#virtual;
30
31pub use self::errno::Errno;
32pub use self::errno::RawErrno;
33pub use self::errno::Result;
34pub use self::fd_flag::FdFlag;
35pub use self::file_system::Dir;
36pub use self::file_system::DirEntry;
37pub use self::file_system::FileType;
38pub use self::file_system::Mode;
39pub use self::file_system::RawMode;
40pub use self::file_system::Stat;
41pub use self::file_system::AT_FDCWD;
42pub use self::id::Gid;
43pub use self::id::RawGid;
44pub use self::id::RawUid;
45pub use self::id::Uid;
46pub use self::open_flag::OfdAccess;
47pub use self::open_flag::OpenFlag;
48#[cfg(doc)]
49use self::r#virtual::VirtualSystem;
50#[cfg(all(doc, unix))]
51use self::real::RealSystem;
52use self::resource::LimitPair;
53use self::resource::Resource;
54use self::select::SelectSystem;
55use self::select::SignalStatus;
56pub use self::shared::SharedSystem;
57use crate::io::Fd;
58use crate::io::MIN_INTERNAL_FD;
59use crate::job::Pid;
60use crate::job::ProcessState;
61use crate::path::Path;
62use crate::path::PathBuf;
63use crate::semantics::ExitStatus;
64use crate::signal;
65use crate::str::UnixString;
66#[cfg(doc)]
67use crate::subshell::Subshell;
68use crate::trap::SignalSystem;
69use crate::Env;
70use enumset::EnumSet;
71use std::convert::Infallible;
72use std::ffi::c_int;
73use std::ffi::CStr;
74use std::ffi::CString;
75use std::fmt::Debug;
76use std::future::Future;
77use std::io::SeekFrom;
78use std::pin::Pin;
79use std::time::Duration;
80use std::time::Instant;
81
82/// API to the system-managed parts of the environment.
83///
84/// The `System` trait defines a collection of methods to access the underlying
85/// operating system from the shell as an application program. There are two
86/// substantial implementors for this trait: [`RealSystem`] and
87/// [`VirtualSystem`]. Another implementor is [`SharedSystem`], which wraps a
88/// `System` instance to extend the interface with asynchronous methods.
89pub trait System: Debug {
90    /// Retrieves metadata of a file.
91    fn fstat(&self, fd: Fd) -> Result<Stat>;
92
93    /// Retrieves metadata of a file.
94    fn fstatat(&self, dir_fd: Fd, path: &CStr, follow_symlinks: bool) -> Result<Stat>;
95
96    /// Whether there is an executable file at the specified path.
97    #[must_use]
98    fn is_executable_file(&self, path: &CStr) -> bool;
99
100    /// Whether there is a directory at the specified path.
101    #[must_use]
102    fn is_directory(&self, path: &CStr) -> bool;
103
104    /// Creates an unnamed pipe.
105    ///
106    /// This is a thin wrapper around the `pipe` system call.
107    /// If successful, returns the reading and writing ends of the pipe.
108    fn pipe(&mut self) -> Result<(Fd, Fd)>;
109
110    /// Duplicates a file descriptor.
111    ///
112    /// This is a thin wrapper around the `fcntl` system call that opens a new
113    /// FD that shares the open file description with `from`. The new FD will be
114    /// the minimum unused FD not less than `to_min`. The `flags` are set to the
115    /// new FD.
116    ///
117    /// If successful, returns `Ok(new_fd)`. On error, returns `Err(_)`.
118    fn dup(&mut self, from: Fd, to_min: Fd, flags: EnumSet<FdFlag>) -> Result<Fd>;
119
120    /// Duplicates a file descriptor.
121    ///
122    /// This is a thin wrapper around the `dup2` system call. If successful,
123    /// returns `Ok(to)`. On error, returns `Err(_)`.
124    fn dup2(&mut self, from: Fd, to: Fd) -> Result<Fd>;
125
126    /// Opens a file descriptor.
127    ///
128    /// This is a thin wrapper around the `open` system call.
129    fn open(
130        &mut self,
131        path: &CStr,
132        access: OfdAccess,
133        flags: EnumSet<OpenFlag>,
134        mode: Mode,
135    ) -> Result<Fd>;
136
137    /// Opens a file descriptor associated with an anonymous temporary file.
138    ///
139    /// This function works similarly to the `O_TMPFILE` flag specified to the
140    /// `open` function.
141    fn open_tmpfile(&mut self, parent_dir: &Path) -> Result<Fd>;
142
143    /// Closes a file descriptor.
144    ///
145    /// This is a thin wrapper around the `close` system call.
146    ///
147    /// This function returns `Ok(())` when the FD is already closed.
148    fn close(&mut self, fd: Fd) -> Result<()>;
149
150    /// Returns the open file description access mode.
151    fn ofd_access(&self, fd: Fd) -> Result<OfdAccess>;
152
153    /// Gets and sets the non-blocking mode for the open file description.
154    ///
155    /// This is a wrapper around the `fcntl` system call.
156    /// This function sets the non-blocking mode to the given value and returns
157    /// the previous mode.
158    fn get_and_set_nonblocking(&mut self, fd: Fd, nonblocking: bool) -> Result<bool>;
159
160    /// Returns the attributes for the file descriptor.
161    ///
162    /// This is a thin wrapper around the `fcntl` system call.
163    fn fcntl_getfd(&self, fd: Fd) -> Result<EnumSet<FdFlag>>;
164
165    /// Sets attributes for the file descriptor.
166    ///
167    /// This is a thin wrapper around the `fcntl` system call.
168    fn fcntl_setfd(&mut self, fd: Fd, flags: EnumSet<FdFlag>) -> Result<()>;
169
170    /// Tests if a file descriptor is associated with a terminal device.
171    ///
172    /// On error, this function simply returns `false` and no detailed error
173    /// information is provided because POSIX does not require the `isatty`
174    /// function to set `errno`.
175    fn isatty(&self, fd: Fd) -> bool;
176
177    /// Reads from the file descriptor.
178    ///
179    /// This is a thin wrapper around the `read` system call.
180    /// If successful, returns the number of bytes read.
181    ///
182    /// This function may perform blocking I/O, especially if the `O_NONBLOCK`
183    /// flag is not set for the FD. Use [`SharedSystem::read_async`] to support
184    /// concurrent I/O in an `async` function context.
185    fn read(&mut self, fd: Fd, buffer: &mut [u8]) -> Result<usize>;
186
187    /// Writes to the file descriptor.
188    ///
189    /// This is a thin wrapper around the `write` system call.
190    /// If successful, returns the number of bytes written.
191    ///
192    /// This function may write only part of the `buffer` and block if the
193    /// `O_NONBLOCK` flag is not set for the FD. Use [`SharedSystem::write_all`]
194    /// to support concurrent I/O in an `async` function context and ensure the
195    /// whole `buffer` is written.
196    fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result<usize>;
197
198    /// Moves the position of the open file description.
199    fn lseek(&mut self, fd: Fd, position: SeekFrom) -> Result<u64>;
200
201    /// Opens a directory for enumerating entries.
202    fn fdopendir(&mut self, fd: Fd) -> Result<Box<dyn Dir>>;
203
204    /// Opens a directory for enumerating entries.
205    fn opendir(&mut self, path: &CStr) -> Result<Box<dyn Dir>>;
206
207    /// Gets and sets the file creation mode mask.
208    ///
209    /// This is a thin wrapper around the `umask` system call. It sets the mask
210    /// to the given value and returns the previous mask.
211    ///
212    /// You cannot tell the current mask without setting a new one. If you only
213    /// want to get the current mask, you need to set it back to the original
214    /// value after getting it.
215    fn umask(&mut self, new_mask: Mode) -> Mode;
216
217    /// Returns the current time.
218    #[must_use]
219    fn now(&self) -> Instant;
220
221    /// Returns consumed CPU times.
222    fn times(&self) -> Result<Times>;
223
224    /// Tests if a signal number is valid.
225    ///
226    /// This function returns `Some((name, number))` if the signal number refers
227    /// to a valid signal supported by the system. Otherwise, it returns `None`.
228    ///
229    /// Note that one signal number can have multiple names, in which case this
230    /// function returns the name that is considered the most common.
231    #[must_use]
232    fn validate_signal(&self, number: signal::RawNumber) -> Option<(signal::Name, signal::Number)>;
233
234    /// Gets the signal number from the signal name.
235    ///
236    /// This function returns the signal number corresponding to the signal name
237    /// in the system. If the signal name is not supported, it returns `None`.
238    #[must_use]
239    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number>;
240
241    /// Gets and/or sets the signal blocking mask.
242    ///
243    /// This is a low-level function used internally by
244    /// [`SharedSystem::set_disposition`]. You should not call this function
245    /// directly, or you will disrupt the behavior of `SharedSystem`. The
246    /// description below applies if you want to do everything yourself without
247    /// depending on `SharedSystem`.
248    ///
249    /// This is a thin wrapper around the `sigprocmask` system call. If `op` is
250    /// `Some`, this function updates the signal blocking mask by applying the
251    /// given `SigmaskOp` and signal set to the current mask. If `op` is `None`,
252    /// this function does not change the mask.
253    /// If `old_mask` is `Some`, this function sets the previous mask to it.
254    fn sigmask(
255        &mut self,
256        op: Option<(SigmaskOp, &[signal::Number])>,
257        old_mask: Option<&mut Vec<signal::Number>>,
258    ) -> Result<()>;
259
260    /// Gets and sets the disposition for a signal.
261    ///
262    /// This is a low-level function used internally by
263    /// [`SharedSystem::set_disposition`]. You should not call this function
264    /// directly, or you will disrupt the behavior of `SharedSystem`. The
265    /// description below applies if you want to do everything yourself without
266    /// depending on `SharedSystem`.
267    ///
268    /// This is an abstract wrapper around the `sigaction` system call. This
269    /// function returns the previous disposition if successful.
270    ///
271    /// When you set the disposition to `Disposition::Catch`, signals sent to
272    /// this process are accumulated in the `System` instance and made available
273    /// from [`caught_signals`](Self::caught_signals).
274    fn sigaction(&mut self, signal: signal::Number, action: Disposition) -> Result<Disposition>;
275
276    /// Returns signals this process has caught, if any.
277    ///
278    /// This is a low-level function used internally by
279    /// [`SharedSystem::select`]. You should not call this function directly, or
280    /// you will disrupt the behavior of `SharedSystem`. The description below
281    /// applies if you want to do everything yourself without depending on
282    /// `SharedSystem`.
283    ///
284    /// To catch a signal, you must firstly install a signal handler by calling
285    /// [`sigaction`](Self::sigaction) with [`Disposition::Catch`]. Once the
286    /// handler is ready, signals sent to the process are accumulated in the
287    /// `System`. You call `caught_signals` to obtain a list of caught signals
288    /// thus far.
289    ///
290    /// This function clears the internal list of caught signals, so a next call
291    /// will return an empty list unless another signal is caught since the
292    /// first call. Because the list size is limited, you should call this
293    /// function periodically before the list gets full, in which case further
294    /// caught signals are silently ignored.
295    ///
296    /// Note that signals become pending if sent while blocked by
297    /// [`sigmask`](Self::sigmask). They must be unblocked so that they are
298    /// caught and made available from this function.
299    fn caught_signals(&mut self) -> Vec<signal::Number>;
300
301    /// Sends a signal.
302    ///
303    /// This is a thin wrapper around the `kill` system call. If `signal` is
304    /// `None`, permission to send a signal is checked, but no signal is sent.
305    ///
306    /// The virtual system version of this function blocks the calling thread if
307    /// the signal stops or terminates the current process, hence returning a
308    /// future. See [`VirtualSystem::kill`] for details.
309    fn kill(
310        &mut self,
311        target: Pid,
312        signal: Option<signal::Number>,
313    ) -> Pin<Box<dyn Future<Output = Result<()>>>>;
314
315    /// Waits for a next event.
316    ///
317    /// This is a low-level function used internally by
318    /// [`SharedSystem::select`]. You should not call this function directly, or
319    /// you will disrupt the behavior of `SharedSystem`. The description below
320    /// applies if you want to do everything yourself without depending on
321    /// `SharedSystem`.
322    ///
323    /// This function blocks the calling thread until one of the following
324    /// condition is met:
325    ///
326    /// - An FD in `readers` becomes ready for reading.
327    /// - An FD in `writers` becomes ready for writing.
328    /// - The specified `timeout` duration has passed.
329    /// - A signal handler catches a signal.
330    ///
331    /// When this function returns an `Ok`, FDs that are not ready for reading
332    /// and writing are removed from `readers` and `writers`, respectively. The
333    /// return value will be the number of FDs left in `readers` and `writers`.
334    ///
335    /// If `readers` and `writers` contain an FD that is not open for reading
336    /// and writing, respectively, this function will fail with `EBADF`. In this
337    /// case, you should remove the FD from `readers` and `writers` and try
338    /// again.
339    ///
340    /// If `signal_mask` is `Some` list of signals, it is used as the signal
341    /// blocking mask while waiting and restored when the function returns.
342    fn select(
343        &mut self,
344        readers: &mut Vec<Fd>,
345        writers: &mut Vec<Fd>,
346        timeout: Option<Duration>,
347        signal_mask: Option<&[signal::Number]>,
348    ) -> Result<c_int>;
349
350    /// Returns the process ID of the current process.
351    #[must_use]
352    fn getpid(&self) -> Pid;
353
354    /// Returns the process ID of the parent process.
355    #[must_use]
356    fn getppid(&self) -> Pid;
357
358    /// Returns the process group ID of the current process.
359    #[must_use]
360    fn getpgrp(&self) -> Pid;
361
362    /// Modifies the process group ID of a process.
363    ///
364    /// This is a thin wrapper around the `setpgid` system call.
365    fn setpgid(&mut self, pid: Pid, pgid: Pid) -> Result<()>;
366
367    /// Returns the current foreground process group ID.
368    ///
369    /// This is a thin wrapper around the `tcgetpgrp` system call.
370    fn tcgetpgrp(&self, fd: Fd) -> Result<Pid>;
371
372    /// Switches the foreground process group.
373    ///
374    /// This is a thin wrapper around the `tcsetpgrp` system call.
375    fn tcsetpgrp(&mut self, fd: Fd, pgid: Pid) -> Result<()>;
376
377    /// Creates a new child process.
378    ///
379    /// This is a thin wrapper around the `fork` system call. Users of `Env`
380    /// should not call it directly. Instead, use [`Subshell`] so that the
381    /// environment can condition the state of the child process before it
382    /// starts running.
383    ///
384    /// Because we need the parent environment to create the child environment,
385    /// this method cannot initiate the child task directly. Instead, it returns
386    /// a [`ChildProcessStarter`] function that takes the parent environment and
387    /// the child task. The caller must call the starter to make sure the parent
388    /// and child processes perform correctly after forking.
389    fn new_child_process(&mut self) -> Result<ChildProcessStarter>;
390
391    /// Reports updated status of a child process.
392    ///
393    /// This is a low-level function used internally by
394    /// [`Env::wait_for_subshell`]. You should not call this function directly,
395    /// or you will disrupt the behavior of `Env`. The description below applies
396    /// if you want to do everything yourself without depending on `Env`.
397    ///
398    /// This function performs
399    /// `waitpid(target, ..., WUNTRACED | WCONTINUED | WNOHANG)`.
400    /// Despite the name, this function does not block: it returns the result
401    /// immediately.
402    ///
403    /// This function returns a pair of the process ID and the process state if
404    /// a process matching `target` is found and its state has changed. If all
405    /// the processes matching `target` have not changed their states, this
406    /// function returns `Ok(None)`. If an error occurs, this function returns
407    /// `Err(_)`.
408    fn wait(&mut self, target: Pid) -> Result<Option<(Pid, ProcessState)>>;
409
410    // TODO Consider passing raw pointers for optimization
411    /// Replaces the current process with an external utility.
412    ///
413    /// This is a thin wrapper around the `execve` system call.
414    fn execve(&mut self, path: &CStr, args: &[CString], envs: &[CString]) -> Result<Infallible>;
415
416    /// Returns the current working directory path.
417    fn getcwd(&self) -> Result<PathBuf>;
418
419    /// Changes the working directory.
420    fn chdir(&mut self, path: &CStr) -> Result<()>;
421
422    /// Returns the real user ID of the current process.
423    fn getuid(&self) -> Uid;
424
425    /// Returns the effective user ID of the current process.
426    fn geteuid(&self) -> Uid;
427
428    /// Returns the real group ID of the current process.
429    fn getgid(&self) -> Gid;
430
431    /// Returns the effective group ID of the current process.
432    fn getegid(&self) -> Gid;
433
434    /// Returns the home directory path of the given user.
435    ///
436    /// Returns `Ok(None)` if the user is not found.
437    fn getpwnam_dir(&self, name: &str) -> Result<Option<PathBuf>>;
438
439    /// Returns the standard `$PATH` value where all standard utilities are
440    /// expected to be found.
441    ///
442    /// This is a thin wrapper around the `confstr(_CS_PATH, …)`.
443    fn confstr_path(&self) -> Result<UnixString>;
444
445    /// Returns the path to the shell executable.
446    ///
447    /// If possible, this function should return the path to the current shell
448    /// executable. Otherwise, it should return the path to the default POSIX
449    /// shell.
450    fn shell_path(&self) -> CString;
451
452    /// Returns the limits for the specified resource.
453    ///
454    /// This function returns a pair of the soft and hard limits for the given
455    /// resource. The soft limit is the current limit, and the hard limit is the
456    /// maximum value that the soft limit can be set to.
457    ///
458    /// When no limit is set, the limit value is [`INFINITY`].
459    ///
460    /// This is a thin wrapper around the `getrlimit` system call.
461    ///
462    /// [`INFINITY`]: self::resource::INFINITY
463    fn getrlimit(&self, resource: Resource) -> Result<LimitPair>;
464
465    /// Sets the limits for the specified resource.
466    ///
467    /// Specify [`INFINITY`] as the limit value to remove the limit.
468    ///
469    /// This is a thin wrapper around the `setrlimit` system call.
470    ///
471    /// [`INFINITY`]: self::resource::INFINITY
472    fn setrlimit(&mut self, resource: Resource, limits: LimitPair) -> Result<()>;
473}
474
475/// Set of consumed CPU time
476///
477/// This structure contains four CPU time values, all in seconds.
478///
479/// This structure is returned by [`System::times`].
480#[derive(Clone, Copy, Debug, Default, PartialEq)]
481pub struct Times {
482    /// User CPU time consumed by the current process
483    pub self_user: f64,
484    /// System CPU time consumed by the current process
485    pub self_system: f64,
486    /// User CPU time consumed by the children of the current process
487    pub children_user: f64,
488    /// System CPU time consumed by the children of the current process
489    pub children_system: f64,
490}
491
492/// Operation applied to the signal blocking mask
493#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
494#[non_exhaustive]
495pub enum SigmaskOp {
496    /// Add signals to the mask (`SIG_BLOCK`)
497    Add,
498    /// Remove signals from the mask (`SIG_UNBLOCK`)
499    Remove,
500    /// Set the mask to the given signals (`SIG_SETMASK`)
501    Set,
502}
503
504/// How the shell process responds to a signal
505#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
506pub enum Disposition {
507    /// Perform the default action for the signal.
508    ///
509    /// The default action depends on the signal. For example, `SIGINT` causes
510    /// the process to terminate, and `SIGTSTP` causes the process to stop.
511    #[default]
512    Default,
513    /// Ignore the signal.
514    Ignore,
515    /// Catch the signal.
516    Catch,
517}
518
519/// Task executed in a child process
520///
521/// This is an argument passed to a [`ChildProcessStarter`]. The task is
522/// executed in a child process initiated by the starter. The environment passed
523/// to the task is a clone of the parent environment, but it has a different
524/// process ID than the parent.
525pub type ChildProcessTask =
526    Box<dyn for<'a> FnOnce(&'a mut Env) -> Pin<Box<dyn Future<Output = ()> + 'a>>>;
527
528/// Abstract function that starts a child process
529///
530/// [`System::new_child_process`] returns a child process starter. You need to
531/// pass the parent environment and a task to the starter to complete the child
532/// process creation. The starter provides a unified interface that hides the
533/// differences between [`RealSystem`] and [`VirtualSystem`].
534///
535/// [`RealSystem::new_child_process`] performs a `fork` system call and returns
536/// a starter in the parent and child processes. When the starter is called in
537/// the parent, it just returns the child process ID. The starter in the child
538/// process runs the task and exits the process with the exit status of the
539/// task.
540///
541/// [`VirtualSystem::new_child_process`] does ont create a real child process.
542/// Instead, the starter runs the task concurrently in the current process using
543/// the executor contained in the system. A new [`Process`](virtual::Process) is
544/// added to the system to represent the child process. The starter returns its
545/// process ID.
546///
547/// This function only starts the child, which continues to run asynchronously
548/// after the function returns its PID. To wait for the child to finish and
549/// obtain its exit status, use [`System::wait`].
550pub type ChildProcessStarter = Box<dyn FnOnce(&mut Env, ChildProcessTask) -> Pid>;
551
552/// Extension for [`System`]
553///
554/// This trait provides some extension methods for `System`.
555pub trait SystemEx: System {
556    /// Moves a file descriptor to [`MIN_INTERNAL_FD`] or larger.
557    ///
558    /// This function can be used to make sure a file descriptor used by the
559    /// shell does not conflict with file descriptors used by the user.
560    /// [`MIN_INTERNAL_FD`] is the minimum file descriptor number the shell
561    /// uses internally. This function moves the file descriptor to a number
562    /// larger than or equal to [`MIN_INTERNAL_FD`].
563    ///
564    /// If the given file descriptor is less than [`MIN_INTERNAL_FD`], this
565    /// function duplicates the file descriptor with [`System::dup`] and closes
566    /// the original one. Otherwise, this function does nothing.
567    ///
568    /// The new file descriptor will have the CLOEXEC flag set when it is
569    /// dupped. Note that, if the original file descriptor has the CLOEXEC flag
570    /// unset and is already larger than or equal to [`MIN_INTERNAL_FD`], this
571    /// function will not set the CLOEXEC flag for the returned file descriptor.
572    ///
573    /// This function returns the new file descriptor on success. On error, it
574    /// closes the original file descriptor and returns the error.
575    fn move_fd_internal(&mut self, from: Fd) -> Result<Fd> {
576        if from >= MIN_INTERNAL_FD {
577            return Ok(from);
578        }
579
580        let new = self.dup(from, MIN_INTERNAL_FD, FdFlag::CloseOnExec.into());
581        self.close(from).ok();
582        new
583    }
584
585    /// Tests if a file descriptor is a pipe.
586    fn fd_is_pipe(&self, fd: Fd) -> bool {
587        self.fstat(fd)
588            .is_ok_and(|stat| stat.r#type == FileType::Fifo)
589    }
590
591    /// Switches the foreground process group with SIGTTOU blocked.
592    ///
593    /// This is a convenience function to change the foreground process group
594    /// safely. If you call [`tcsetpgrp`](System::tcsetpgrp) from a background
595    /// process, the process is stopped by SIGTTOU by default. To prevent this
596    /// effect, SIGTTOU must be blocked or ignored when `tcsetpgrp` is called.
597    /// This function uses [`sigmask`](System::sigmask) to block SIGTTOU before
598    /// calling [`tcsetpgrp`](System::tcsetpgrp) and also to restore the
599    /// original signal mask after `tcsetpgrp`.
600    ///
601    /// Use [`tcsetpgrp_without_block`](Self::tcsetpgrp_without_block) if you
602    /// need to make sure the shell is in the foreground before changing the
603    /// foreground job.
604    fn tcsetpgrp_with_block(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
605        let sigttou = self
606            .signal_number_from_name(signal::Name::Ttou)
607            .ok_or(Errno::EINVAL)?;
608        let mut old_mask = Vec::new();
609
610        self.sigmask(Some((SigmaskOp::Add, &[sigttou])), Some(&mut old_mask))?;
611
612        let result = self.tcsetpgrp(fd, pgid);
613
614        let result_2 = self.sigmask(Some((SigmaskOp::Set, &old_mask)), None);
615
616        result.or(result_2)
617    }
618
619    /// Switches the foreground process group with the default SIGTTOU settings.
620    ///
621    /// This is a convenience function to ensure the shell has been in the
622    /// foreground and optionally change the foreground process group. This
623    /// function calls [`sigaction`](System::sigaction) to restore the action
624    /// for SIGTTOU to the default disposition (which is to suspend the shell
625    /// process), [`sigmask`](System::sigmask) to unblock SIGTTOU, and
626    /// [`tcsetpgrp`](System::tcsetpgrp) to modify the foreground job. If the
627    /// calling process is not in the foreground, `tcsetpgrp` will suspend the
628    /// process with SIGTTOU until another job-controlling process resumes it in
629    /// the foreground. After `tcsetpgrp` completes, this function calls
630    /// `sigmask` and `sigaction` to restore the original state.
631    ///
632    /// Note that if `pgid` is the process group ID of the current process, this
633    /// function does not change the foreground job, but the process is still
634    /// subject to suspension if it has not been in the foreground.
635    ///
636    /// Use [`tcsetpgrp_with_block`](Self::tcsetpgrp_with_block) to change the
637    /// job even if the current shell is not in the foreground.
638    fn tcsetpgrp_without_block(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
639        let sigttou = self
640            .signal_number_from_name(signal::Name::Ttou)
641            .ok_or(Errno::EINVAL)?;
642        match self.sigaction(sigttou, Disposition::Default) {
643            Err(e) => Err(e),
644            Ok(old_handling) => {
645                let mut old_mask = Vec::new();
646                let result = match self
647                    .sigmask(Some((SigmaskOp::Remove, &[sigttou])), Some(&mut old_mask))
648                {
649                    Err(e) => Err(e),
650                    Ok(()) => {
651                        let result = self.tcsetpgrp(fd, pgid);
652
653                        let result_2 = self.sigmask(Some((SigmaskOp::Set, &old_mask)), None);
654
655                        result.or(result_2)
656                    }
657                };
658
659                let result_2 = self.sigaction(sigttou, old_handling).map(drop);
660
661                result.or(result_2)
662            }
663        }
664    }
665
666    /// Returns the signal name for the signal number.
667    ///
668    /// This function returns the signal name for the given signal number.
669    ///
670    /// If the signal number is invalid, this function panics. It may occur if
671    /// the number is from a different system or was created without checking
672    /// the validity.
673    #[must_use]
674    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
675        self.validate_signal(number.as_raw()).unwrap().0
676    }
677
678    /// Returns the signal number that corresponds to the exit status.
679    ///
680    /// This function is basically the inverse of `impl From<signal::Number> for
681    /// ExitStatus`. However, this function supports not only the offset of 384
682    /// but also the offset of 128 and zero to accept exit statuses returned
683    /// from other processes.
684    #[must_use]
685    fn signal_number_from_exit_status(&self, status: ExitStatus) -> Option<signal::Number> {
686        [0x180, 0x80, 0].into_iter().find_map(|offset| {
687            let raw_number = status.0.checked_sub(offset)?;
688            self.validate_signal(raw_number).map(|(_, number)| number)
689        })
690    }
691}
692
693impl<T: System + ?Sized> SystemEx for T {}