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}