yash_builtin/ulimit.rs
1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2024 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//! Ulimit built-in
18//!
19//! This module implements the [`ulimit` built-in], which sets or shows system
20//! resource limits.
21//!
22//! [`ulimit` built-in]: https://magicant.github.io/yash-rs/builtins/ulimit.html
23//!
24//! # Implementation notes
25//!
26//! See the source code for [`Resource::as_raw_type`] to see which resources are
27//! supported on which platforms.
28
29use crate::common::output;
30use crate::common::report::{report_error, report_simple_failure};
31use yash_env::Env;
32use yash_env::semantics::Field;
33use yash_env::system::resource::{GetRlimit, Limit, Resource, SetRlimit};
34use yash_env::system::{Errno, Fcntl, Isatty, Write};
35
36/// Type of limit to show
37///
38/// See [`Command`].
39#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
40pub enum ShowLimitType {
41 Soft,
42 Hard,
43}
44
45/// Type of limit to set
46///
47/// See [`Command`].
48#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
49pub enum SetLimitType {
50 Soft,
51 Hard,
52 Both,
53}
54
55/// Value of the limit to set
56///
57/// See [`Command`].
58#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59pub enum SetLimitValue {
60 /// Numeric value (not scaled)
61 Number(Limit),
62 /// No limit
63 Unlimited,
64 /// Current soft limit
65 CurrentSoft,
66 /// Current hard limit
67 CurrentHard,
68}
69
70/// Interpretation of command-line arguments that determine the behavior of the
71/// `ulimit` built-in
72#[derive(Clone, Debug, Eq, Hash, PartialEq)]
73pub enum Command {
74 /// Show the current limits for all resources
75 ShowAll(ShowLimitType),
76 /// Show the current limit for a specific resource
77 ShowOne(Resource, ShowLimitType),
78 /// Set the limit for a specific resource
79 Set(Resource, SetLimitType, SetLimitValue),
80}
81
82mod resource;
83pub use resource::ResourceExt;
84
85pub mod set;
86pub mod show;
87pub mod syntax;
88
89/// Error that may occur in [`Command::execute`]
90#[derive(Debug, thiserror::Error)]
91pub enum Error {
92 /// The specified resource is not supported on the current platform.
93 #[error("specified resource not supported on this platform")]
94 UnsupportedResource,
95 /// The specified soft limit is greater than the hard limit.
96 #[error("soft limit exceeds hard limit")]
97 SoftLimitExceedsHardLimit,
98 /// The new hard limit is greater than the current hard limit and the user
99 /// does not have permission to raise the hard limit.
100 #[error("no permission to raise hard limit")]
101 NoPermissionToRaiseHardLimit,
102 /// The specified limit is out of range.
103 #[error("limit out of range")]
104 Overflow,
105 /// Other error
106 #[error("unexpected error: {}", .0)]
107 Unknown(Errno),
108}
109
110impl Command {
111 /// Execute the `ulimit` built-in command.
112 ///
113 /// If successful, returns the string to be printed to the standard output.
114 pub async fn execute<S>(&self, env: &mut Env<S>) -> Result<String, Error>
115 where
116 S: GetRlimit + SetRlimit,
117 {
118 let getrlimit = |resource| env.system.getrlimit(resource);
119 match self {
120 Command::ShowAll(limit_type) => Ok(show::show_all(getrlimit, *limit_type)),
121 Command::ShowOne(resource, limit_type) => {
122 show::show_one(getrlimit, *resource, *limit_type)
123 }
124 Command::Set(resource, limit_type, limit) => {
125 set::set(&mut env.system, *resource, *limit_type, *limit)?;
126 Ok(String::new())
127 }
128 }
129 }
130}
131
132/// Executes the `ulimit` built-in.
133///
134/// This is the main entry point for the `ulimit` built-in.
135pub async fn main<S>(env: &mut Env<S>, args: Vec<Field>) -> crate::Result
136where
137 S: GetRlimit + SetRlimit + Fcntl + Isatty + Write,
138{
139 match syntax::parse(env, args) {
140 Ok(command) => match command.execute(env).await {
141 Ok(result) => output(env, &result).await,
142 Err(e) => report_simple_failure(env, &e.to_string()).await,
143 },
144 Err(e) => report_error(env, &e).await,
145 }
146}