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 {}