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//! API declarations and implementations for system-managed parts of the environment
18//!
19//! This module defines the [`System`] trait, which provides an interface to
20//! interact with the underlying system. It is a subtrait of various other traits
21//! that define specific functionalities, such as file system operations, process
22//! management, signal handling, and resource limit management. The following
23//! traits are included as subtraits of `System`:
24//!
25//! - [`CaughtSignals`]: Declares the `caught_signals` method for retrieving
26//!   caught signals.
27//! - [`Chdir`]: Declares the `chdir` method for changing the current
28//!   working directory.
29//! - [`Clock`]: Declares the `now` method for getting the current time.
30//! - [`Close`]: Declares the `close` method for closing file descriptors.
31//! - [`Dup`]: Declares the `dup` and `dup2` methods for duplicating file
32//!   descriptors.
33//! - [`Exec`]: Declares the `execve` method for executing new programs.
34//! - [`Exit`]: Declares the `exit` method for terminating the current
35//!   process.
36//! - [`Fcntl`]: Declares the `ofd_access`, `get_and_set_nonblocking`,
37//!   `fcntl_getfd`, and `fcntl_setfd` methods for `fcntl`-related operations.
38//! - [`Fork`]: Declares a method for creating new child processes.
39//! - [`Fstat`]: Declares `fstat` and `fstatat` methods for getting file
40//!   metadata and provides a default implementation of `is_directory`.
41//! - [`GetCwd`]: Declares the `getcwd` method for getting the current
42//!   working directory.
43//! - [`GetPid`]: Declares the `getpid` and other methods for getting process IDs
44//!   and other attributes.
45//! - [`GetPw`]: Declares methods for getting user information.
46//! - [`GetUid`]: Declares the `getuid`, `geteuid`, `getgid`, and
47//!   `getegid` methods for getting user and group IDs.
48//! - [`IsExecutableFile`]: Declares the `is_executable_file` method for checking
49//!   if a file is executable.
50//! - [`Isatty`]: Declares the `isatty` method for testing if a file descriptor is
51//!   associated with a terminal device.
52//! - [`Open`]: Declares the `open` and other methods for opening files.
53//! - [`Pipe`]: Declares the `pipe` method for creating pipes.
54//! - [`Read`]: Declares the `read` method for reading from file descriptors.
55//! - [`Seek`]: Declares the `lseek` method for seeking within file
56//!   descriptors.
57//! - [`Select`]: Declares the `select` method for waiting on multiple file
58//!   descriptors and signals.
59//! - [`SendSignal`]: Declares the `kill` and `raise` methods for sending signals
60//!   to processes.
61//! - [`SetPgid`]: Declares the `setpgid` method for setting process group IDs.
62//! - [`ShellPath`]: Declares the `shell_path` method for getting the path to
63//!   the shell executable.
64//! - [`Sigaction`]: Declares methods for managing signal dispositions.
65//! - [`Sigmask`]: Declares the `sigmask` method for managing signal masks.
66//! - [`Signals`]: Declares the `signal_number_from_name` and
67//!   `validate_signal` methods for converting between signal names and numbers.
68//! - [`TcGetPgrp`]: Declares the `tcgetpgrp` method for getting the
69//!   foreground process group ID of a terminal.
70//! - [`TcSetPgrp`]: Declares the `tcsetpgrp` method for setting the
71//!   foreground process group ID of a terminal.
72//! - [`Times`]: Declares the `times` method for getting CPU times.
73//! - [`Umask`]: Declares the `umask` method for setting the file mode
74//!   creation mask.
75//! - [`Wait`]: Declares the `wait` method for waiting for child processes.
76//! - [`Write`]: Declares the `write` method for writing to file
77//!   descriptors.
78//! - [`resource::GetRlimit`]: Declares the `getrlimit` method for
79//!   retrieving resource limits.
80//! - [`resource::SetRlimit`]: Declares the `setrlimit` method for
81//!   setting resource limits.
82//!
83//! There are two main implementors of the `System` trait:
84//!
85//! - `RealSystem`: An implementation that interacts with the actual
86//!   underlying system (see the [`real`] module).
87//! - `VirtualSystem`: An implementation that simulates system behavior
88//!   for testing purposes (see the [`virtual`] module).
89//!
90//! Additionally, there is the [`SharedSystem`] implementor that wraps
91//! another `System` instance to provide asynchronous methods.
92//!
93//! User code should generally depend only on specific subtraits of `System`
94//! rather than `System` itself. This allows for more modular and testable code.
95//! For example, code that only needs to write to file descriptors can depend
96//! on the `Write` trait alone.
97
98mod errno;
99mod file_system;
100mod future;
101mod io;
102mod process;
103#[cfg(unix)]
104pub mod real;
105pub mod resource;
106mod select;
107mod shared;
108mod signal;
109mod sysconf;
110mod terminal;
111mod time;
112mod user;
113pub mod r#virtual;
114
115pub use self::errno::Errno;
116pub use self::errno::RawErrno;
117pub use self::errno::Result;
118pub use self::file_system::{
119    AT_FDCWD, Chdir, Dir, DirEntry, FileType, Fstat, GetCwd, IsExecutableFile, Mode, OfdAccess,
120    Open, OpenFlag, RawMode, Seek, Stat, Umask,
121};
122pub use self::future::FlexFuture;
123pub use self::io::{Close, Dup, Fcntl, FdFlag, Pipe, Read, Write};
124pub use self::process::{
125    ChildProcessStarter, ChildProcessTask, Exec, Exit, Fork, GetPid, SetPgid, Wait,
126};
127#[cfg(all(doc, unix))]
128use self::real::RealSystem;
129use self::resource::{GetRlimit, LimitPair, Resource, SetRlimit};
130pub use self::select::Select;
131use self::select::SelectSystem;
132use self::select::SignalStatus;
133pub use self::shared::SharedSystem;
134pub use self::signal::{
135    CaughtSignals, Disposition, SendSignal, Sigaction, Sigmask, SigmaskOp, Signals,
136};
137pub use self::sysconf::{ShellPath, Sysconf};
138pub use self::terminal::{Isatty, TcGetPgrp, TcSetPgrp};
139pub use self::time::{Clock, CpuTimes, Times};
140pub use self::user::{GetPw, GetUid, Gid, RawGid, RawUid, Uid};
141#[cfg(doc)]
142use self::r#virtual::VirtualSystem;
143use crate::io::Fd;
144#[cfg(doc)]
145use crate::io::MIN_INTERNAL_FD;
146use crate::job::Pid;
147use crate::path::Path;
148use crate::path::PathBuf;
149use crate::semantics::ExitStatus;
150use crate::str::UnixString;
151#[cfg(doc)]
152use crate::subshell::Subshell;
153use crate::trap::SignalSystem;
154use std::convert::Infallible;
155use std::fmt::Debug;
156
157/// API to the system-managed parts of the environment.
158///
159/// The `System` trait defines a collection of methods to access the underlying
160/// operating system from the shell as an application program. There are two
161/// substantial implementors for this trait: [`RealSystem`] and
162/// [`VirtualSystem`]. Another implementor is [`SharedSystem`], which wraps a
163/// `System` instance to extend the interface with asynchronous methods.
164#[deprecated(
165    note = "use smaller, more specialized traits declared in the `system` module instead",
166    since = "0.11.0"
167)]
168pub trait System:
169    CaughtSignals
170    + Chdir
171    + Clock
172    + Close
173    + Debug
174    + Dup
175    + Exec
176    + Exit
177    + Fcntl
178    + Fork
179    + Fstat
180    + GetCwd
181    + GetPid
182    + GetPw
183    + GetRlimit
184    + GetUid
185    + IsExecutableFile
186    + Isatty
187    + Open
188    + Pipe
189    + Read
190    + Seek
191    + Select
192    + SendSignal
193    + SetPgid
194    + SetRlimit
195    + ShellPath
196    + Sigaction
197    + Sigmask
198    + Signals
199    + Sysconf
200    + TcGetPgrp
201    + TcSetPgrp
202    + Times
203    + Umask
204    + Wait
205    + Write
206{
207}
208
209#[allow(deprecated)]
210impl<T> System for T where
211    T: CaughtSignals
212        + Chdir
213        + Clock
214        + Close
215        + Debug
216        + Dup
217        + Exec
218        + Exit
219        + Fcntl
220        + Fork
221        + Fstat
222        + GetCwd
223        + GetPid
224        + GetPw
225        + GetRlimit
226        + GetUid
227        + IsExecutableFile
228        + Isatty
229        + Open
230        + Pipe
231        + Read
232        + Seek
233        + Select
234        + SendSignal
235        + SetPgid
236        + SetRlimit
237        + ShellPath
238        + Sigaction
239        + Sigmask
240        + Signals
241        + Sysconf
242        + TcGetPgrp
243        + TcSetPgrp
244        + Times
245        + Umask
246        + Wait
247        + Write
248{
249}
250
251/// Extension for [`System`]
252///
253/// This trait provides some extension methods for `System`.
254#[allow(deprecated)]
255#[deprecated(
256    note = "use functions in the `yash-env::io` and `yash-env::job` modules instead",
257    since = "0.11.0"
258)]
259pub trait SystemEx: System {
260    /// Moves a file descriptor to [`MIN_INTERNAL_FD`] or larger.
261    ///
262    /// This function can be used to make sure a file descriptor used by the
263    /// shell does not conflict with file descriptors used by the user.
264    /// [`MIN_INTERNAL_FD`] is the minimum file descriptor number the shell
265    /// uses internally. This function moves the file descriptor to a number
266    /// larger than or equal to [`MIN_INTERNAL_FD`].
267    ///
268    /// If the given file descriptor is less than [`MIN_INTERNAL_FD`], this
269    /// function duplicates the file descriptor with [`Dup::dup`] and closes
270    /// the original one. Otherwise, this function does nothing.
271    ///
272    /// The new file descriptor will have the CLOEXEC flag set when it is
273    /// dupped. Note that, if the original file descriptor has the CLOEXEC flag
274    /// unset and is already larger than or equal to [`MIN_INTERNAL_FD`], this
275    /// function will not set the CLOEXEC flag for the returned file descriptor.
276    ///
277    /// This function returns the new file descriptor on success. On error, it
278    /// closes the original file descriptor and returns the error.
279    #[deprecated(
280        note = "use `yash_env::io::move_fd_internal` instead",
281        since = "0.11.0"
282    )]
283    fn move_fd_internal(&mut self, from: Fd) -> Result<Fd> {
284        crate::io::move_fd_internal(self, from)
285    }
286
287    /// Tests if a file descriptor is a pipe.
288    #[deprecated(
289        note = "use `yash_env::system::Fstat::fd_is_pipe` instead",
290        since = "0.11.0"
291    )]
292    fn fd_is_pipe(&self, fd: Fd) -> bool {
293        self.fstat(fd)
294            .is_ok_and(|stat| stat.r#type == FileType::Fifo)
295    }
296
297    /// Switches the foreground process group with SIGTTOU blocked.
298    ///
299    /// This is a convenience function to change the foreground process group
300    /// safely. If you call [`TcSetPgrp::tcsetpgrp`] from a background process,
301    /// the process is stopped by SIGTTOU by default. To prevent this effect,
302    /// SIGTTOU must be blocked or ignored when `tcsetpgrp` is called.  This
303    /// function uses [`Sigmask::sigmask`] to block SIGTTOU before calling
304    /// `tcsetpgrp` and also to restore the original signal mask after
305    /// `tcsetpgrp`.
306    ///
307    /// Use [`tcsetpgrp_without_block`](Self::tcsetpgrp_without_block) if you
308    /// need to make sure the shell is in the foreground before changing the
309    /// foreground job.
310    #[deprecated(
311        note = "use `yash_env::job::tcsetpgrp_with_block` instead",
312        since = "0.11.0"
313    )]
314    fn tcsetpgrp_with_block(&mut self, fd: Fd, pgid: Pid) -> impl Future<Output = Result<()>> {
315        crate::job::tcsetpgrp_with_block(self, fd, pgid)
316    }
317
318    /// Switches the foreground process group with the default SIGTTOU settings.
319    ///
320    /// This is a convenience function to ensure the shell has been in the
321    /// foreground and optionally change the foreground process group. This
322    /// function calls [`Sigaction::sigaction`] to restore the action for
323    /// SIGTTOU to the default disposition (which is to suspend the shell
324    /// process), [`Sigmask::sigmask`] to unblock SIGTTOU, and
325    /// [`TcSetPgrp::tcsetpgrp`] to modify the foreground job. If the calling
326    /// process is not in the foreground, `tcsetpgrp` will suspend the process
327    /// with SIGTTOU until another job-controlling process resumes it in the
328    /// foreground. After `tcsetpgrp` completes, this function calls `sigmask`
329    /// and `sigaction` to restore the original state.
330    ///
331    /// Note that if `pgid` is the process group ID of the current process, this
332    /// function does not change the foreground job, but the process is still
333    /// subject to suspension if it has not been in the foreground.
334    ///
335    /// Use [`tcsetpgrp_with_block`](Self::tcsetpgrp_with_block) to change the
336    /// job even if the current shell is not in the foreground.
337    #[deprecated(
338        note = "use `yash_env::job::tcsetpgrp_without_block` instead",
339        since = "0.11.0"
340    )]
341    fn tcsetpgrp_without_block(&mut self, fd: Fd, pgid: Pid) -> impl Future<Output = Result<()>> {
342        crate::job::tcsetpgrp_without_block(self, fd, pgid)
343    }
344
345    /// Returns the signal name for the signal number.
346    ///
347    /// This function returns the signal name for the given signal number.
348    ///
349    /// If the signal number is invalid, this function panics. It may occur if
350    /// the number is from a different system or was created without checking
351    /// the validity.
352    #[deprecated(
353        note = "use `yash_env::system::Signals::signal_name_from_number` instead",
354        since = "0.11.0"
355    )]
356    #[must_use]
357    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
358        self.validate_signal(number.as_raw()).unwrap().0
359    }
360
361    /// Terminates the current process with the given exit status, possibly
362    /// sending a signal to kill the process.
363    ///
364    /// If the exit status represents a signal that killed the last executed
365    /// command, this function sends the signal to the current process to
366    /// propagate the signal to the parent process. Otherwise, this function
367    /// terminates the process with the given exit status.
368    #[deprecated(
369        note = "use `yash_env::semantics::exit_or_raise` instead",
370        since = "0.11.0"
371    )]
372    fn exit_or_raise(&mut self, exit_status: ExitStatus) -> impl Future<Output = Infallible> {
373        async move { crate::semantics::exit_or_raise(self, exit_status).await }
374    }
375}
376
377#[allow(deprecated)]
378impl<T: System + ?Sized> SystemEx for T {}