Skip to main content

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}