Skip to main content

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