shell/
platform.rs

1mod unix;
2
3use crate::command_data::{CommandWithArgs, Run};
4use crate::jobs::{Job, Jobs};
5pub use crate::platform::unix::*;
6use std::ffi::OsString;
7use std::io;
8
9/// Abstraction for a "platform" (for instance Unix or Windows).
10pub trait Platform {
11    type Pid;
12    type FileDesc;
13    type TermSettings;
14
15    /// If terminal is a terminal then get it's term settings.
16    fn get_term_settings(terminal: FileDesc) -> Result<TermSettings, io::Error>;
17    /// Restore terminal settings and put the shell back into the foreground.
18    fn restore_terminal(term_settings: &TermSettings, shell_pid: Pid) -> Result<(), io::Error>;
19    /// Put terminal in the foreground, loop until this succeeds.
20    /// Used during shell startup.
21    fn terminal_foreground(terminal: FileDesc);
22    /// Puts the running process into its own process group.
23    /// Do this during shell initialization.
24    fn set_self_pgroup() -> Result<(), io::Error>;
25    /// Grab control of terminal.
26    /// Used for shell startup.
27    fn grab_terminal(terminal: FileDesc) -> Result<(), io::Error>;
28    /// Return the input and output file descriptors for an anonymous pipe.
29    fn anon_pipe() -> Result<(FileDesc, FileDesc), io::Error>;
30    /// Close a raw file descriptor.
31    fn close_fd(fd: FileDesc) -> Result<(), io::Error>;
32
33    fn fork_run(run: &Run, job: &mut Job, jobs: &mut Jobs) -> Result<(), io::Error>;
34    fn fork_exec(
35        command: &CommandWithArgs,
36        job: &mut Job,
37        jobs: &mut Jobs,
38    ) -> Result<(), io::Error>;
39    fn try_wait_pid(pid: Pid, job: &mut Job) -> (bool, Option<i32>);
40    fn wait_job(job: &mut Job) -> Option<i32>;
41    /// Move the job for job_num to te foreground.
42    fn foreground_job(job: &mut Job, term_settings: &Option<TermSettings>)
43    -> Result<(), io::Error>;
44    /// Move the job for job_num to te background and running (start a stopped job in the background).
45    fn background_job(job: &mut Job) -> Result<(), io::Error>;
46    /// Duplicate a raw file descriptor to another file descriptor.
47    fn dup2_fd(src_fd: FileDesc, dst_fd: FileDesc) -> Result<FileDesc, io::Error>;
48    /// Get the current PID.
49    fn getpid() -> Pid;
50    /// Get the current machines hostname if available.
51    fn gethostname() -> Option<OsString>;
52    /// Get current UID of the process.
53    fn current_uid() -> u32;
54    /// Get effective UID of the process.
55    fn effective_uid() -> u32;
56    fn is_tty(terminal: FileDesc) -> bool;
57
58    fn set_rlimit(rlimit: RLimit, values: RLimitVals) -> Result<(), io::Error>;
59    fn get_rlimit(rlimit: RLimit) -> Result<RLimitVals, io::Error>;
60
61    // umask operations, these can be NoOps if platform does not have umasks.
62    /// If mask_string is a mode string then merge it with umask and set the current umask.
63    /// If mask_string is an int then treat it as a umask and set the current umask (no merge)).
64    fn merge_and_set_umask(current_umask: mode_t, mask_string: &str) -> Result<mode_t, io::Error>;
65    /// Clears the current umask and returns the previous umask.
66    fn get_and_clear_umask() -> mode_t;
67    /// Set current umask to umask.
68    fn set_umask(umask: mode_t) -> Result<(), io::Error>;
69    /// Convert mode to the octal string umask format.
70    fn to_octal_string(mode: mode_t) -> Result<String, io::Error> {
71        let mut octal = format!("{:o}", mode);
72        if octal.len() < 4 {
73            while octal.len() < 4 {
74                octal = "0".to_owned() + &octal;
75            }
76            Ok(octal)
77        } else {
78            let msg = format!("encountered invalid umask {octal}.");
79            Err(io::Error::other(msg))
80        }
81    }
82}
83
84pub type Pid = <Sys as Platform>::Pid;
85pub type FileDesc = <Sys as Platform>::FileDesc;
86pub type TermSettings = <Sys as Platform>::TermSettings;
87
88/// Trait to turn a UnixFileDesc into another object (like File).
89pub trait FromFileDesc {
90    /// Constructs a new instance of Self from the given UnixFileDesc.
91    /// # Safety
92    /// The fd passed in must be a valid and open file descriptor.
93    unsafe fn from_file_desc(fd: FileDesc) -> Self;
94}
95
96/// Holder for setting or getting rlimits (get/setrlimit).
97#[derive(Copy, Clone, Debug)]
98pub struct RLimitVals {
99    pub current: u64,
100    pub max: u64,
101}
102
103/// Abstraction over the various rlimits.
104pub enum RLimit {
105    ///-b: The maximum socket buffer size. RLIMIT_SBSIZE (freebsd, dragonfly)
106    SocketBufferSize,
107    /// -c; The maximum size of core files created. RLIMIT_CORE
108    /// The maximum size core file that this process can create. If the process terminates and would
109    /// dump a core file larger than this, then no core file is created. So setting this limit to zero
110    /// prevents core files from ever being created.
111    CoreSize,
112    /// -d: The maximum size of a process’s data segment. RLIMIT_DATA
113    /// The maximum size of data memory for the process. If the process tries to allocate data memory
114    /// beyond this amount, the allocation function fails.
115    DataSize,
116    /// -e: The maximum scheduling priority ("nice"). RLIMIT_NICE
117    /// Specifies a ceiling to which the process's nice value can be raised using setpriority(2) or
118    /// nice(2). The actual ceiling for the nice value is calculated as 20 - rlim_cur. (This
119    /// strangeness occurs because negative numbers cannot be specified as resource limit values,
120    /// since they typically have special meanings. For example, RLIM_INFINITY typically is the
121    /// same as -1.)
122    Nice,
123    /// -f: The maximum size of files written by the shell and its children. RLIMIT_FSIZE
124    /// The maximum size of file the process can create. Trying to write a larger file causes a signal: SIGXFSZ.
125    FileSize,
126    /// -i: The maximum number of pending signals.RLIMIT_SIGPENDING
127    /// Specifies the limit on the number of signals that may be queued for the real user ID of the
128    /// calling process. Both standard and real-time signals are counted for the purpose of checking
129    /// this limit. However, the limit is only enforced for sigqueue(3); it is always possible to use
130    /// kill(2) to queue one instance of any of the signals that are not already queued to the process.
131    SigPending,
132    /// -k: The maximum number of kqueues that may be allocated. RLIMIT_KQUEUES (freebsd)
133    KQueues,
134    /// -l: The maximum size that may be locked into memory. RLIMIT_MEMLOCK,
135    /// The maximum size (in bytes) which a process may lock into memory
136    /// using the mlock(2) system call.
137    MemLock,
138    /// -m: The maximum resident set size (many systems do not honor this limit). RLIMIT_RSS
139    /// When there is memory pressure and swap is available, prioritize
140    /// eviction of a process' resident pages beyond this amount (in bytes).
141    RSS,
142    /// -n: The maximum number of open file descriptors (most systems do not allow this value to be set). RLIMIT_NOFILE
143    MaxFiles,
144    // -p: The pipe buffer size.
145    //PipeBufferSize,
146    /// -q: The maximum number of bytes in POSIX message queues. RLIMIT_MSGQUEUE
147    /// A limit on the number of bytes that can be allocated for POSIX
148    /// message queues  for  the  real  user  ID  of  the  calling process.
149    MessageQueueByte,
150    /// -r: The maximum real-time scheduling priority. RLIMIT_RTPRIO
151    RealTimePriority,
152    /// -s: The maximum stack size. RLIMIT_STACK
153    StackSize,
154    /// -t: The maximum amount of cpu time in seconds. RLIMIT_CPU
155    CpuTime,
156    /// -u: The maximum number of processes available to a single user. RLIMIT_NPROC
157    MaxProcs,
158    /// -v: The maximum amount of virtual memory available to the shell, and, on some systems, to its children. RLIMIT_AS
159    MaxMemory,
160    /// -x: The maximum number of file locks. RLIMIT_LOCKS
161    MaxFileLocks,
162    /// -P: The maximum number of pseudoterminals. RLIMIT_NPTS
163    MaxPtty,
164    /// -R: The maximum time a real-time process can run before blocking, in microseconds. RLIMIT_RTTIME
165    MaxRealTime,
166    /// -T: The maximum number of threads. RLIMIT_NPROC (Same as MaxProcs- Linux)
167    MaxThreads,
168}