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 many traits that declare methods to interact with the
20//! underlying system, such as file system operations, process management,
21//! signal handling, and resource limit management:
22//!
23//! - [`CaughtSignals`]: Declares the `caught_signals` method for retrieving
24//!   caught signals.
25//! - [`Chdir`]: Declares the `chdir` method for changing the current
26//!   working directory.
27//! - [`Clock`]: Declares the `now` method for getting the current time.
28//! - [`Close`]: Declares the `close` method for closing file descriptors.
29//! - [`Dup`]: Declares the `dup` and `dup2` methods for duplicating file
30//!   descriptors.
31//! - [`Exec`]: Declares the `execve` method for executing new programs.
32//! - [`Exit`]: Declares the `exit` method for terminating the current
33//!   process.
34//! - [`Fcntl`]: Declares the `ofd_access`, `get_and_set_nonblocking`,
35//!   `fcntl_getfd`, and `fcntl_setfd` methods for `fcntl`-related operations.
36//! - [`Fork`]: Declares a method for creating new child processes.
37//! - [`Fstat`]: Declares `fstat` and `fstatat` methods for getting file
38//!   metadata and provides a default implementation of `is_directory`.
39//! - [`GetCwd`]: Declares the `getcwd` method for getting the current
40//!   working directory.
41//! - [`GetPid`]: Declares the `getpid` and other methods for getting process IDs
42//!   and other attributes.
43//! - [`GetPw`]: Declares methods for getting user information.
44//! - [`GetSigaction`]: Declares the `get_sigaction` method for querying signal
45//!   dispositions.
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 these traits:
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 for
88//!   testing purposes (see the [`virtual`] module).
89//!
90//! Additionally, [`Concurrent`] is a wrapper that extends the interface with
91//! asynchronous methods for concurrency. (See the [`concurrency`] module.)
92//!
93//! This module has a deprecated trait, [`System`], that combines all the traits
94//! above. To promote interface segregation, user code should generally depend
95//! only on specific traits that declare the methods it needs, rather than
96//! working with `System` directly. For example, code that only needs to write
97//! to file descriptors can depend on the `Write` trait alone.
98//!
99//! Some methods of these traits return [futures](std::future::Future), not
100//! because the underlying system calls are asynchronous, but to allow
101//! `VirtualSystem` to simulate blocking behavior and run virtual processes
102//! concurrently. `RealSystem` implementations return ready futures after the
103//! underlying system calls complete (which may block the current thread).
104
105pub mod concurrency;
106mod errno;
107mod file_system;
108mod future;
109mod io;
110mod process;
111#[cfg(unix)]
112pub mod real;
113pub mod resource;
114mod select;
115mod signal;
116mod sysconf;
117mod terminal;
118mod time;
119mod user;
120pub mod r#virtual;
121
122pub use self::concurrency::{Concurrent, SignalList};
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, reason = "for backward compatible API")]
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, SetRlimit};
139pub use self::select::{FdSet, Select};
140pub use self::signal::{
141    CaughtSignals, Disposition, GetSigaction, SendSignal, Sigaction, Sigmask, SigmaskOp, Signals,
142    Sigset,
143};
144pub use self::sysconf::{ShellPath, Sysconf};
145pub use self::terminal::{Isatty, TcGetPgrp, TcSetPgrp};
146pub use self::time::{Clock, CpuTimes, Times};
147pub use self::user::{GetPw, GetUid, Gid, RawGid, RawUid, Uid};
148#[cfg(doc)]
149use self::r#virtual::VirtualSystem;
150use crate::io::Fd;
151#[cfg(doc)]
152use crate::io::MIN_INTERNAL_FD;
153use crate::job::Pid;
154use crate::semantics::ExitStatus;
155#[cfg(doc)]
156use crate::subshell::Subshell;
157use std::convert::Infallible;
158use std::fmt::Debug;
159
160/// Utility trait that aggregates all the traits in this module
161///
162/// The `System` trait defines a collection of methods to access the underlying
163/// operating system from the shell as an application program. See the
164/// [module-level documentation](self) for more details.
165///
166/// This trait is now deprecated in favor of depending on specific traits that
167/// declare the methods needed by the user code, which promotes interface
168/// segregation.
169#[deprecated(
170    note = "use smaller, more specialized traits declared in the `system` module instead",
171    since = "0.11.0"
172)]
173pub trait System:
174    CaughtSignals
175    + Chdir
176    + Clock
177    + Close
178    + Debug
179    + Dup
180    + Exec
181    + Exit
182    + Fcntl
183    + Fork
184    + Fstat
185    + GetCwd
186    + GetPid
187    + GetPw
188    + GetRlimit
189    + GetUid
190    + IsExecutableFile
191    + Isatty
192    + Open
193    + Pipe
194    + Read
195    + Seek
196    + Select
197    + SendSignal
198    + SetPgid
199    + SetRlimit
200    + ShellPath
201    + Sigaction
202    + Sigmask
203    + Signals
204    + Sysconf
205    + TcGetPgrp
206    + TcSetPgrp
207    + Times
208    + Umask
209    + Wait
210    + Write
211{
212}
213
214#[allow(deprecated, reason = "for backward compatible API")]
215impl<T> System for T where
216    T: CaughtSignals
217        + Chdir
218        + Clock
219        + Close
220        + Debug
221        + Dup
222        + Exec
223        + Exit
224        + Fcntl
225        + Fork
226        + Fstat
227        + GetCwd
228        + GetPid
229        + GetPw
230        + GetRlimit
231        + GetUid
232        + IsExecutableFile
233        + Isatty
234        + Open
235        + Pipe
236        + Read
237        + Seek
238        + Select
239        + SendSignal
240        + SetPgid
241        + SetRlimit
242        + ShellPath
243        + Sigaction
244        + Sigmask
245        + Signals
246        + Sysconf
247        + TcGetPgrp
248        + TcSetPgrp
249        + Times
250        + Umask
251        + Wait
252        + Write
253{
254}
255
256/// Extension for [`System`]
257///
258/// This trait provides some extension methods for `System`.
259#[allow(deprecated, reason = "the caller and callee are both deprecated")]
260#[deprecated(
261    note = "use functions in the `yash-env::io` and `yash-env::job` modules instead",
262    since = "0.11.0"
263)]
264pub trait SystemEx: System {
265    /// Moves a file descriptor to [`MIN_INTERNAL_FD`] or larger.
266    ///
267    /// This function can be used to make sure a file descriptor used by the
268    /// shell does not conflict with file descriptors used by the user.
269    /// [`MIN_INTERNAL_FD`] is the minimum file descriptor number the shell
270    /// uses internally. This function moves the file descriptor to a number
271    /// larger than or equal to [`MIN_INTERNAL_FD`].
272    ///
273    /// If the given file descriptor is less than [`MIN_INTERNAL_FD`], this
274    /// function duplicates the file descriptor with [`Dup::dup`] and closes
275    /// the original one. Otherwise, this function does nothing.
276    ///
277    /// The new file descriptor will have the CLOEXEC flag set when it is
278    /// dupped. Note that, if the original file descriptor has the CLOEXEC flag
279    /// unset and is already larger than or equal to [`MIN_INTERNAL_FD`], this
280    /// function will not set the CLOEXEC flag for the returned file descriptor.
281    ///
282    /// This function returns the new file descriptor on success. On error, it
283    /// closes the original file descriptor and returns the error.
284    #[deprecated(
285        note = "use `yash_env::io::move_fd_internal` instead",
286        since = "0.11.0"
287    )]
288    fn move_fd_internal(&mut self, from: Fd) -> Result<Fd> {
289        crate::io::move_fd_internal(self, from)
290    }
291
292    /// Tests if a file descriptor is a pipe.
293    #[deprecated(
294        note = "use `yash_env::system::Fstat::fd_is_pipe` instead",
295        since = "0.11.0"
296    )]
297    fn fd_is_pipe(&self, fd: Fd) -> bool {
298        crate::system::Fstat::fd_is_pipe(self, fd)
299    }
300
301    /// Switches the foreground process group with SIGTTOU blocked.
302    ///
303    /// This is a convenience function to change the foreground process group
304    /// safely. If you call [`TcSetPgrp::tcsetpgrp`] from a background process,
305    /// the process is stopped by SIGTTOU by default. To prevent this effect,
306    /// SIGTTOU must be blocked or ignored when `tcsetpgrp` is called.  This
307    /// function uses [`Sigmask::sigmask`] to block SIGTTOU before calling
308    /// `tcsetpgrp` and also to restore the original signal mask after
309    /// `tcsetpgrp`.
310    ///
311    /// Use [`tcsetpgrp_without_block`](Self::tcsetpgrp_without_block) if you
312    /// need to make sure the shell is in the foreground before changing the
313    /// foreground job.
314    #[deprecated(
315        note = "use `yash_env::job::tcsetpgrp_with_block` instead",
316        since = "0.11.0"
317    )]
318    fn tcsetpgrp_with_block(&mut self, fd: Fd, pgid: Pid) -> impl Future<Output = Result<()>> {
319        crate::job::tcsetpgrp_with_block(self, fd, pgid)
320    }
321
322    /// Switches the foreground process group with the default SIGTTOU settings.
323    ///
324    /// This is a convenience function to ensure the shell has been in the
325    /// foreground and optionally change the foreground process group. This
326    /// function calls [`Sigaction::sigaction`] to restore the action for
327    /// SIGTTOU to the default disposition (which is to suspend the shell
328    /// process), [`Sigmask::sigmask`] to unblock SIGTTOU, and
329    /// [`TcSetPgrp::tcsetpgrp`] to modify the foreground job. If the calling
330    /// process is not in the foreground, `tcsetpgrp` will suspend the process
331    /// with SIGTTOU until another job-controlling process resumes it in the
332    /// foreground. After `tcsetpgrp` completes, this function calls `sigmask`
333    /// and `sigaction` to restore the original state.
334    ///
335    /// Note that if `pgid` is the process group ID of the current process, this
336    /// function does not change the foreground job, but the process is still
337    /// subject to suspension if it has not been in the foreground.
338    ///
339    /// Use [`tcsetpgrp_with_block`](Self::tcsetpgrp_with_block) to change the
340    /// job even if the current shell is not in the foreground.
341    #[deprecated(
342        note = "use `yash_env::job::tcsetpgrp_without_block` instead",
343        since = "0.11.0"
344    )]
345    fn tcsetpgrp_without_block(&mut self, fd: Fd, pgid: Pid) -> impl Future<Output = Result<()>> {
346        crate::job::tcsetpgrp_without_block(self, fd, pgid)
347    }
348
349    /// Returns the signal name for the signal number.
350    ///
351    /// This function returns the signal name for the given signal number.
352    ///
353    /// If the signal number is invalid, this function panics. It may occur if
354    /// the number is from a different system or was created without checking
355    /// the validity.
356    #[deprecated(
357        note = "use `yash_env::system::Signals::signal_name_from_number` instead",
358        since = "0.11.0"
359    )]
360    #[must_use]
361    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
362        self.validate_signal(number.as_raw()).unwrap().0
363    }
364
365    /// Terminates the current process with the given exit status, possibly
366    /// sending a signal to kill the process.
367    ///
368    /// If the exit status represents a signal that killed the last executed
369    /// command, this function sends the signal to the current process to
370    /// propagate the signal to the parent process. Otherwise, this function
371    /// terminates the process with the given exit status.
372    #[deprecated(
373        note = "use `yash_env::semantics::exit_or_raise` instead",
374        since = "0.11.0"
375    )]
376    fn exit_or_raise(&mut self, exit_status: ExitStatus) -> impl Future<Output = Infallible> {
377        async move { crate::semantics::exit_or_raise(self, exit_status).await }
378    }
379}
380
381#[allow(deprecated, reason = "for backward compatible API")]
382impl<T: System + ?Sized> SystemEx for T {}