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