mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
parent
31ecc5e0f9
commit
a64324421f
9 changed files with 646 additions and 474 deletions
|
@ -101,7 +101,6 @@ endif()
|
|||
set(FISH_BUILTIN_SRCS
|
||||
src/builtins/bind.cpp
|
||||
src/builtins/commandline.cpp
|
||||
src/builtins/ulimit.cpp
|
||||
)
|
||||
# List of other sources.
|
||||
set(FISH_SRCS
|
||||
|
|
|
@ -51,7 +51,7 @@ lazy_static = "1.4.0"
|
|||
libc = "0.2.137"
|
||||
lru = "0.10.0"
|
||||
moveit = "0.5.1"
|
||||
nix = { version = "0.25.0", default-features = false, features = ["inotify"] }
|
||||
nix = { version = "0.25.0", default-features = false, features = ["inotify", "resource"] }
|
||||
num-traits = "0.2.15"
|
||||
# to make integer->enum conversion easier
|
||||
num-derive = "0.3.3"
|
||||
|
|
|
@ -1,16 +1,485 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use libc::{c_uint, rlim_t, RLIM_INFINITY};
|
||||
use nix::errno::Errno;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::compat::*;
|
||||
use crate::fallback::{fish_wcswidth, wcscasecmp};
|
||||
use crate::wutil::perror;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
/// Calls getrlimit.
|
||||
fn getrlimit(resource: c_uint) -> Option<(rlim_t, rlim_t)> {
|
||||
let resource: i32 = resource.try_into().unwrap();
|
||||
|
||||
// Resource is #[repr(i32)] so this is ok
|
||||
nix::sys::resource::getrlimit(unsafe { std::mem::transmute(resource) })
|
||||
.map_err(|_| {
|
||||
perror("getrlimit");
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn setrlimit(resource: c_uint, rlim_cur: rlim_t, rlim_max: rlim_t) -> Result<(), Errno> {
|
||||
let resource: i32 = resource.try_into().unwrap();
|
||||
nix::sys::resource::setrlimit(
|
||||
unsafe { std::mem::transmute(resource) }, // Resource is #[repr(i32)] so this is ok
|
||||
rlim_cur,
|
||||
rlim_max,
|
||||
)
|
||||
}
|
||||
|
||||
/// Print the value of the specified resource limit.
|
||||
fn print(resource: c_uint, hard: bool, streams: &mut IoStreams) {
|
||||
let Some(l) = get(resource, hard) else {
|
||||
streams.out.append(wgettext!("error\n"));
|
||||
return;
|
||||
};
|
||||
|
||||
if l == RLIM_INFINITY {
|
||||
streams.out.append(wgettext!("unlimited\n"));
|
||||
} else {
|
||||
streams
|
||||
.out
|
||||
.append(wgettext_fmt!("%lu\n", l / get_multiplier(resource)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Print values of all resource limits.
|
||||
fn print_all(hard: bool, streams: &mut IoStreams) {
|
||||
let mut w = 0;
|
||||
|
||||
for resource in RESOURCE_ARR.iter() {
|
||||
w = w.max(fish_wcswidth(resource.desc));
|
||||
}
|
||||
for resource in RESOURCE_ARR.iter() {
|
||||
let Some((rlim_cur, rlim_max)) = getrlimit(resource.resource) else {
|
||||
continue;
|
||||
};
|
||||
let l = if hard { rlim_max } else { rlim_cur };
|
||||
|
||||
let unit = if resource.resource == RLIMIT_CPU() as c_uint {
|
||||
"(seconds, "
|
||||
} else if get_multiplier(resource.resource) == 1 {
|
||||
"("
|
||||
} else {
|
||||
"(kB, "
|
||||
};
|
||||
streams.out.append(wgettext_fmt!(
|
||||
"%-*ls %10ls-%lc) ",
|
||||
w,
|
||||
resource.desc,
|
||||
unit,
|
||||
resource.switch_char,
|
||||
));
|
||||
|
||||
if l == RLIM_INFINITY {
|
||||
streams.out.append(wgettext!("unlimited\n"));
|
||||
} else {
|
||||
streams.out.append(wgettext_fmt!(
|
||||
"%lu\n",
|
||||
l / get_multiplier(resource.resource)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the description for the specified resource limit.
|
||||
fn get_desc(what: c_uint) -> &'static wstr {
|
||||
for resource in RESOURCE_ARR.iter() {
|
||||
if resource.resource == what {
|
||||
return resource.desc;
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Set the new value of the specified resource limit. This function does _not_ multiply the limit
|
||||
/// value by the multiplier constant used by the commandline ulimit.
|
||||
fn set_limit(
|
||||
resource: c_uint,
|
||||
hard: bool,
|
||||
soft: bool,
|
||||
value: rlim_t,
|
||||
streams: &mut IoStreams,
|
||||
) -> Option<c_int> {
|
||||
let Some((mut rlim_cur, mut rlim_max)) = getrlimit(resource) else {
|
||||
return STATUS_CMD_ERROR;
|
||||
};
|
||||
if hard {
|
||||
rlim_max = value;
|
||||
}
|
||||
if soft {
|
||||
rlim_cur = value;
|
||||
|
||||
// Do not attempt to set the soft limit higher than the hard limit.
|
||||
if (value > rlim_max || value == RLIM_INFINITY) && rlim_max != RLIM_INFINITY {
|
||||
rlim_cur = rlim_max;
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(errno) = setrlimit(resource, rlim_cur, rlim_max) {
|
||||
if errno == Errno::EPERM {
|
||||
streams.err.append(wgettext_fmt!(
|
||||
"ulimit: Permission denied when changing resource of type '%ls'\n",
|
||||
get_desc(resource)
|
||||
));
|
||||
} else {
|
||||
builtin_wperror(L!("ulimit"), streams);
|
||||
}
|
||||
|
||||
STATUS_CMD_ERROR
|
||||
} else {
|
||||
STATUS_CMD_OK
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the implicit multiplication factor for the specified resource limit.
|
||||
fn get_multiplier(what: c_uint) -> rlim_t {
|
||||
for resource in RESOURCE_ARR.iter() {
|
||||
if resource.resource == what {
|
||||
return resource.multiplier as rlim_t;
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn get(resource: c_uint, hard: bool) -> Option<rlim_t> {
|
||||
let (rlim_cur, rlim_max) = getrlimit(resource)?;
|
||||
|
||||
Some(if hard { rlim_max } else { rlim_cur })
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Options {
|
||||
what: c_int,
|
||||
report_all: bool,
|
||||
hard: bool,
|
||||
soft: bool,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Options {
|
||||
what: RLIMIT_FSIZE(),
|
||||
report_all: false,
|
||||
hard: false,
|
||||
soft: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ulimit(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Option<c_int> {
|
||||
run_builtin_ffi(crate::ffi::builtin_ulimit, parser, streams, args)
|
||||
let cmd = args[0];
|
||||
|
||||
const SHORT_OPTS: &wstr = L!(":HSabcdefilmnqrstuvwyKPTh");
|
||||
|
||||
const LONG_OPTS: &[woption] = &[
|
||||
wopt(L!("all"), woption_argument_t::no_argument, 'a'),
|
||||
wopt(L!("hard"), woption_argument_t::no_argument, 'H'),
|
||||
wopt(L!("soft"), woption_argument_t::no_argument, 'S'),
|
||||
wopt(L!("socket-buffers"), woption_argument_t::no_argument, 'b'),
|
||||
wopt(L!("core-size"), woption_argument_t::no_argument, 'c'),
|
||||
wopt(L!("data-size"), woption_argument_t::no_argument, 'd'),
|
||||
wopt(L!("nice"), woption_argument_t::no_argument, 'e'),
|
||||
wopt(L!("file-size"), woption_argument_t::no_argument, 'f'),
|
||||
wopt(L!("pending-signals"), woption_argument_t::no_argument, 'i'),
|
||||
wopt(L!("lock-size"), woption_argument_t::no_argument, 'l'),
|
||||
wopt(
|
||||
L!("resident-set-size"),
|
||||
woption_argument_t::no_argument,
|
||||
'm',
|
||||
),
|
||||
wopt(
|
||||
L!("file-descriptor-count"),
|
||||
woption_argument_t::no_argument,
|
||||
'n',
|
||||
),
|
||||
wopt(L!("queue-size"), woption_argument_t::no_argument, 'q'),
|
||||
wopt(
|
||||
L!("realtime-priority"),
|
||||
woption_argument_t::no_argument,
|
||||
'r',
|
||||
),
|
||||
wopt(L!("stack-size"), woption_argument_t::no_argument, 's'),
|
||||
wopt(L!("cpu-time"), woption_argument_t::no_argument, 't'),
|
||||
wopt(L!("process-count"), woption_argument_t::no_argument, 'u'),
|
||||
wopt(
|
||||
L!("virtual-memory-size"),
|
||||
woption_argument_t::no_argument,
|
||||
'v',
|
||||
),
|
||||
wopt(L!("swap-size"), woption_argument_t::no_argument, 'w'),
|
||||
wopt(L!("realtime-maxtime"), woption_argument_t::no_argument, 'y'),
|
||||
wopt(L!("kernel-queues"), woption_argument_t::no_argument, 'K'),
|
||||
wopt(L!("ptys"), woption_argument_t::no_argument, 'P'),
|
||||
wopt(L!("threads"), woption_argument_t::no_argument, 'T'),
|
||||
wopt(L!("help"), woption_argument_t::no_argument, 'h'),
|
||||
];
|
||||
|
||||
let mut opts = Options::default();
|
||||
|
||||
let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args);
|
||||
|
||||
while let Some(c) = w.wgetopt_long() {
|
||||
match c {
|
||||
'a' => opts.report_all = true,
|
||||
'H' => opts.hard = true,
|
||||
'S' => opts.soft = true,
|
||||
'b' => opts.what = RLIMIT_SBSIZE(),
|
||||
'c' => opts.what = RLIMIT_CORE(),
|
||||
'd' => opts.what = RLIMIT_DATA(),
|
||||
'e' => opts.what = RLIMIT_NICE(),
|
||||
'f' => opts.what = RLIMIT_FSIZE(),
|
||||
'i' => opts.what = RLIMIT_SIGPENDING(),
|
||||
'l' => opts.what = RLIMIT_MEMLOCK(),
|
||||
'm' => opts.what = RLIMIT_RSS(),
|
||||
'n' => opts.what = RLIMIT_NOFILE(),
|
||||
'q' => opts.what = RLIMIT_MSGQUEUE(),
|
||||
'r' => opts.what = RLIMIT_RTPRIO(),
|
||||
's' => opts.what = RLIMIT_STACK(),
|
||||
't' => opts.what = RLIMIT_CPU(),
|
||||
'u' => opts.what = RLIMIT_NPROC(),
|
||||
'v' => opts.what = RLIMIT_AS(),
|
||||
'w' => opts.what = RLIMIT_SWAP(),
|
||||
'y' => opts.what = RLIMIT_RTTIME(),
|
||||
'K' => opts.what = RLIMIT_KQUEUES(),
|
||||
'P' => opts.what = RLIMIT_NPTS(),
|
||||
'T' => opts.what = RLIMIT_NTHR(),
|
||||
'h' => {
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
':' => {
|
||||
builtin_missing_argument(parser, streams, cmd, w.argv[w.woptind - 1], true);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
'?' => {
|
||||
builtin_unknown_option(parser, streams, cmd, w.argv[w.woptind - 1], true);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected retval from wgetopt_long");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.report_all {
|
||||
print_all(opts.hard, streams);
|
||||
}
|
||||
|
||||
if opts.what == -1 {
|
||||
streams.err.append(wgettext_fmt!(
|
||||
"%ls: Resource limit not available on this operating system\n",
|
||||
cmd
|
||||
));
|
||||
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
let what: c_uint = opts.what.try_into().unwrap();
|
||||
|
||||
let argc = w.argv.len();
|
||||
let arg_count = argc - w.woptind;
|
||||
if arg_count == 0 {
|
||||
print(what, opts.hard, streams);
|
||||
return STATUS_CMD_OK;
|
||||
} else if arg_count != 1 {
|
||||
streams
|
||||
.err
|
||||
.append(wgettext_fmt!(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd));
|
||||
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
let mut hard = opts.hard;
|
||||
let mut soft = opts.soft;
|
||||
if !hard && !soft {
|
||||
// Set both hard and soft limits if neither was specified.
|
||||
hard = true;
|
||||
soft = true;
|
||||
}
|
||||
|
||||
let new_limit: rlim_t = if w.woptind == argc {
|
||||
streams.err.append(wgettext_fmt!(
|
||||
"%ls: New limit cannot be an empty string\n",
|
||||
cmd
|
||||
));
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
} else if wcscasecmp(w.argv[w.woptind], L!("unlimited")) == Ordering::Equal {
|
||||
RLIM_INFINITY
|
||||
} else if wcscasecmp(w.argv[w.woptind], L!("hard")) == Ordering::Equal {
|
||||
match get(what, true) {
|
||||
Some(limit) => limit,
|
||||
None => return STATUS_CMD_ERROR,
|
||||
}
|
||||
} else if wcscasecmp(w.argv[w.woptind], L!("soft")) == Ordering::Equal {
|
||||
match get(what, soft) {
|
||||
Some(limit) => limit,
|
||||
None => return STATUS_CMD_ERROR,
|
||||
}
|
||||
} else if let Ok(limit) = fish_wcstol(w.argv[w.woptind]) {
|
||||
limit as rlim_t * get_multiplier(what)
|
||||
} else {
|
||||
streams.err.append(wgettext_fmt!(
|
||||
"%ls: Invalid limit '%ls'\n",
|
||||
cmd,
|
||||
w.argv[w.woptind]
|
||||
));
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
};
|
||||
|
||||
set_limit(what, hard, soft, new_limit, streams)
|
||||
}
|
||||
|
||||
/// Struct describing a resource limit.
|
||||
struct Resource {
|
||||
resource: c_int, // resource ID
|
||||
resource: c_uint, // resource ID
|
||||
desc: &'static wstr, // description of resource
|
||||
switch_char: char, // switch used on commandline to specify resource
|
||||
multiplier: c_int, // the implicit multiplier used when setting getting values
|
||||
multiplier: c_uint, // the implicit multiplier used when setting getting values
|
||||
}
|
||||
|
||||
impl Resource {
|
||||
fn new(
|
||||
resource: c_uint,
|
||||
desc: &'static wstr,
|
||||
switch_char: char,
|
||||
multiplier: c_uint,
|
||||
) -> Resource {
|
||||
Resource {
|
||||
resource,
|
||||
desc,
|
||||
switch_char,
|
||||
multiplier,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Array of resource_t structs, describing all known resource types.
|
||||
const resource_arr: &[Resource] = &[];
|
||||
static RESOURCE_ARR: Lazy<Box<[Resource]>> = Lazy::new(|| {
|
||||
let resources_info = [
|
||||
(
|
||||
RLIMIT_SBSIZE(),
|
||||
L!("Maximum size of socket buffers"),
|
||||
'b',
|
||||
1024,
|
||||
),
|
||||
(
|
||||
RLIMIT_CORE(),
|
||||
L!("Maximum size of core files created"),
|
||||
'c',
|
||||
1024,
|
||||
),
|
||||
(
|
||||
RLIMIT_DATA(),
|
||||
L!("Maximum size of a process’s data segment"),
|
||||
'd',
|
||||
1024,
|
||||
),
|
||||
(
|
||||
RLIMIT_NICE(),
|
||||
L!("Control of maximum nice priority"),
|
||||
'e',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_FSIZE(),
|
||||
L!("Maximum size of files created by the shell"),
|
||||
'f',
|
||||
1024,
|
||||
),
|
||||
(
|
||||
RLIMIT_SIGPENDING(),
|
||||
L!("Maximum number of pending signals"),
|
||||
'i',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_MEMLOCK(),
|
||||
L!("Maximum size that may be locked into memory"),
|
||||
'l',
|
||||
1024,
|
||||
),
|
||||
(RLIMIT_RSS(), L!("Maximum resident set size"), 'm', 1024),
|
||||
(
|
||||
RLIMIT_NOFILE(),
|
||||
L!("Maximum number of open file descriptors"),
|
||||
'n',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_MSGQUEUE(),
|
||||
L!("Maximum bytes in POSIX message queues"),
|
||||
'q',
|
||||
1024,
|
||||
),
|
||||
(
|
||||
RLIMIT_RTPRIO(),
|
||||
L!("Maximum realtime scheduling priority"),
|
||||
'r',
|
||||
1,
|
||||
),
|
||||
(RLIMIT_STACK(), L!("Maximum stack size"), 's', 1024),
|
||||
(
|
||||
RLIMIT_CPU(),
|
||||
L!("Maximum amount of CPU time in seconds"),
|
||||
't',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_NPROC(),
|
||||
L!("Maximum number of processes available to current user"),
|
||||
'u',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_AS(),
|
||||
L!("Maximum amount of virtual memory available to each process"),
|
||||
'v',
|
||||
1024,
|
||||
),
|
||||
(RLIMIT_SWAP(), L!("Maximum swap space"), 'w', 1024),
|
||||
(
|
||||
RLIMIT_RTTIME(),
|
||||
L!("Maximum contiguous realtime CPU time"),
|
||||
'y',
|
||||
1,
|
||||
),
|
||||
(RLIMIT_KQUEUES(), L!("Maximum number of kqueues"), 'K', 1),
|
||||
(
|
||||
RLIMIT_NPTS(),
|
||||
L!("Maximum number of pseudo-terminals"),
|
||||
'P',
|
||||
1,
|
||||
),
|
||||
(
|
||||
RLIMIT_NTHR(),
|
||||
L!("Maximum number of simultaneous threads"),
|
||||
'T',
|
||||
1,
|
||||
),
|
||||
];
|
||||
|
||||
let unknown = -1;
|
||||
|
||||
let mut resources = Vec::new();
|
||||
for resource in resources_info {
|
||||
let (resource, desc, switch_char, multiplier) = resource;
|
||||
if resource != unknown {
|
||||
resources.push(Resource::new(
|
||||
resource as c_uint,
|
||||
desc,
|
||||
switch_char,
|
||||
multiplier,
|
||||
));
|
||||
}
|
||||
}
|
||||
resources.into_boxed_slice()
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <term.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -79,3 +80,122 @@ static const bool uvar_file_set_mtime_hack =
|
|||
#endif
|
||||
#undef UVAR_FILE_SET_MTIME_HACK
|
||||
bool UVAR_FILE_SET_MTIME_HACK() { return uvar_file_set_mtime_hack; }
|
||||
|
||||
int C_RLIMIT_CORE() { return RLIMIT_CORE; }
|
||||
int C_RLIMIT_DATA() { return RLIMIT_DATA; }
|
||||
int C_RLIMIT_FSIZE() { return RLIMIT_FSIZE; }
|
||||
int C_RLIMIT_NOFILE() { return RLIMIT_NOFILE; }
|
||||
int C_RLIMIT_STACK() { return RLIMIT_STACK; }
|
||||
int C_RLIMIT_CPU() { return RLIMIT_CPU; }
|
||||
|
||||
int C_RLIMIT_SBSIZE() {
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
return RLIMIT_SBSIZE;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_NICE() {
|
||||
#ifdef RLIMIT_NICE
|
||||
return RLIMIT_NICE;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_SIGPENDING() {
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
return RLIMIT_SIGPENDING;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_MEMLOCK() {
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
return RLIMIT_MEMLOCK;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_RSS() {
|
||||
#ifdef RLIMIT_RSS
|
||||
return RLIMIT_RSS;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_MSGQUEUE() {
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
return RLIMIT_MSGQUEUE;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_RTPRIO() {
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
return RLIMIT_RTPRIO;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_NPROC() {
|
||||
#ifdef RLIMIT_NPROC
|
||||
return RLIMIT_NPROC;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_AS() {
|
||||
#ifdef RLIMIT_AS
|
||||
return RLIMIT_AS;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_SWAP() {
|
||||
#ifdef RLIMIT_SWAP
|
||||
return RLIMIT_SWAP;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_RTTIME() {
|
||||
#ifdef RLIMIT_RTTIME
|
||||
return RLIMIT_RTTIME;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_KQUEUES() {
|
||||
#ifdef RLIMIT_KQUEUES
|
||||
return RLIMIT_KQUEUES;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_NPTS() {
|
||||
#ifdef RLIMIT_NPTS
|
||||
return RLIMIT_NPTS;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int C_RLIMIT_NTHR() {
|
||||
#ifdef RLIMIT_NTHR
|
||||
return RLIMIT_NTHR;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -51,3 +51,55 @@ extern "C" {
|
|||
pub fn stdout_stream() -> *mut libc::FILE;
|
||||
pub fn UVAR_FILE_SET_MTIME_HACK() -> bool;
|
||||
}
|
||||
|
||||
macro_rules! CVAR {
|
||||
($cfn:ident, $cvar:ident, $type:ident) => {
|
||||
pub fn $cvar() -> $type {
|
||||
unsafe { $cfn() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CVAR!(C_RLIMIT_SBSIZE, RLIMIT_SBSIZE, i32);
|
||||
CVAR!(C_RLIMIT_CORE, RLIMIT_CORE, i32);
|
||||
CVAR!(C_RLIMIT_DATA, RLIMIT_DATA, i32);
|
||||
CVAR!(C_RLIMIT_NICE, RLIMIT_NICE, i32);
|
||||
CVAR!(C_RLIMIT_FSIZE, RLIMIT_FSIZE, i32);
|
||||
CVAR!(C_RLIMIT_SIGPENDING, RLIMIT_SIGPENDING, i32);
|
||||
CVAR!(C_RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, i32);
|
||||
CVAR!(C_RLIMIT_RSS, RLIMIT_RSS, i32);
|
||||
CVAR!(C_RLIMIT_NOFILE, RLIMIT_NOFILE, i32);
|
||||
CVAR!(C_RLIMIT_MSGQUEUE, RLIMIT_MSGQUEUE, i32);
|
||||
CVAR!(C_RLIMIT_RTPRIO, RLIMIT_RTPRIO, i32);
|
||||
CVAR!(C_RLIMIT_STACK, RLIMIT_STACK, i32);
|
||||
CVAR!(C_RLIMIT_CPU, RLIMIT_CPU, i32);
|
||||
CVAR!(C_RLIMIT_NPROC, RLIMIT_NPROC, i32);
|
||||
CVAR!(C_RLIMIT_AS, RLIMIT_AS, i32);
|
||||
CVAR!(C_RLIMIT_SWAP, RLIMIT_SWAP, i32);
|
||||
CVAR!(C_RLIMIT_RTTIME, RLIMIT_RTTIME, i32);
|
||||
CVAR!(C_RLIMIT_KQUEUES, RLIMIT_KQUEUES, i32);
|
||||
CVAR!(C_RLIMIT_NPTS, RLIMIT_NPTS, i32);
|
||||
CVAR!(C_RLIMIT_NTHR, RLIMIT_NTHR, i32);
|
||||
|
||||
extern "C" {
|
||||
fn C_RLIMIT_SBSIZE() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_CORE() -> i32;
|
||||
fn C_RLIMIT_DATA() -> i32;
|
||||
fn C_RLIMIT_NICE() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_FSIZE() -> i32;
|
||||
fn C_RLIMIT_SIGPENDING() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_MEMLOCK() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_RSS() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_NOFILE() -> i32;
|
||||
fn C_RLIMIT_MSGQUEUE() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_RTPRIO() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_STACK() -> i32;
|
||||
fn C_RLIMIT_CPU() -> i32;
|
||||
fn C_RLIMIT_NPROC() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_AS() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_SWAP() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_RTTIME() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_KQUEUES() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_NPTS() -> i32; // ifndef: -1
|
||||
fn C_RLIMIT_NTHR() -> i32; // ifndef: -1
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ include_cpp! {
|
|||
|
||||
#include "builtins/bind.h"
|
||||
#include "builtins/commandline.h"
|
||||
#include "builtins/ulimit.h"
|
||||
|
||||
safety!(unsafe_ffi)
|
||||
|
||||
|
@ -72,7 +71,6 @@ include_cpp! {
|
|||
|
||||
generate!("builtin_bind")
|
||||
generate!("builtin_commandline")
|
||||
generate!("builtin_ulimit")
|
||||
|
||||
generate!("init_input")
|
||||
|
||||
|
|
|
@ -1,451 +0,0 @@
|
|||
// Functions used for implementing the ulimit builtin.
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ulimit.h"
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cwchar>
|
||||
|
||||
#include "../builtin.h"
|
||||
#include "../common.h"
|
||||
#include "../fallback.h" // IWYU pragma: keep
|
||||
#include "../io.h"
|
||||
#include "../maybe.h"
|
||||
#include "../wgetopt.h"
|
||||
#include "../wutil.h" // IWYU pragma: keep
|
||||
#include "builtins/shared.rs.h"
|
||||
#include "builtins/ulimit.h"
|
||||
|
||||
/// Struct describing a resource limit.
|
||||
struct resource_t {
|
||||
int resource; // resource ID
|
||||
const wchar_t *desc; // description of resource
|
||||
wchar_t switch_char; // switch used on commandline to specify resource
|
||||
int multiplier; // the implicit multiplier used when setting getting values
|
||||
};
|
||||
|
||||
/// Array of resource_t structs, describing all known resource types.
|
||||
static const struct resource_t resource_arr[] = {
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
{RLIMIT_SBSIZE, L"Maximum size of socket buffers", L'b', 1024},
|
||||
#endif
|
||||
{RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024},
|
||||
{RLIMIT_DATA, L"Maximum size of a process’s data segment", L'd', 1024},
|
||||
#ifdef RLIMIT_NICE
|
||||
{RLIMIT_NICE, L"Control of maximum nice priority", L'e', 1},
|
||||
#endif
|
||||
{RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024},
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
{RLIMIT_SIGPENDING, L"Maximum number of pending signals", L'i', 1},
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{RLIMIT_MEMLOCK, L"Maximum size that may be locked into memory", L'l', 1024},
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{RLIMIT_RSS, L"Maximum resident set size", L'm', 1024},
|
||||
#endif
|
||||
{RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1},
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
{RLIMIT_MSGQUEUE, L"Maximum bytes in POSIX message queues", L'q', 1024},
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
{RLIMIT_RTPRIO, L"Maximum realtime scheduling priority", L'r', 1},
|
||||
#endif
|
||||
{RLIMIT_STACK, L"Maximum stack size", L's', 1024},
|
||||
{RLIMIT_CPU, L"Maximum amount of CPU time in seconds", L't', 1},
|
||||
#ifdef RLIMIT_NPROC
|
||||
{RLIMIT_NPROC, L"Maximum number of processes available to current user", L'u', 1},
|
||||
#endif
|
||||
#ifdef RLIMIT_AS
|
||||
{RLIMIT_AS, L"Maximum amount of virtual memory available to each process", L'v', 1024},
|
||||
#endif
|
||||
#ifdef RLIMIT_SWAP
|
||||
{RLIMIT_SWAP, L"Maximum swap space", L'w', 1024},
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
{RLIMIT_RTTIME, L"Maximum contiguous realtime CPU time", L'y', 1},
|
||||
#endif
|
||||
#ifdef RLIMIT_KQUEUES
|
||||
{RLIMIT_KQUEUES, L"Maximum number of kqueues", L'K', 1},
|
||||
#endif
|
||||
#ifdef RLIMIT_NPTS
|
||||
{RLIMIT_NPTS, L"Maximum number of pseudo-terminals", L'P', 1},
|
||||
#endif
|
||||
#ifdef RLIMIT_NTHR
|
||||
{RLIMIT_NTHR, L"Maximum number of simultaneous threads", L'T', 1},
|
||||
#endif
|
||||
{0, nullptr, 0, 0}};
|
||||
|
||||
/// This is likely to be the same as RLIMIT_INFINITY, but it shouldn't get used
|
||||
/// in the same context (that is, compared to the result of a getrlimit call).
|
||||
#define RLIMIT_UNKNOWN -1
|
||||
|
||||
/// Get the implicit multiplication factor for the specified resource limit.
|
||||
static int get_multiplier(int what) {
|
||||
for (int i = 0; resource_arr[i].desc; i++) {
|
||||
if (resource_arr[i].resource == what) {
|
||||
return resource_arr[i].multiplier;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Return the value for the specified resource limit. This function does _not_ multiply the limit
|
||||
/// value by the multiplier constant used by the commandline ulimit.
|
||||
static rlim_t get(int resource, int hard) {
|
||||
struct rlimit ls;
|
||||
|
||||
getrlimit(resource, &ls);
|
||||
|
||||
return hard ? ls.rlim_max : ls.rlim_cur;
|
||||
}
|
||||
|
||||
/// Print the value of the specified resource limit.
|
||||
static void print(int resource, int hard, io_streams_t &streams) {
|
||||
rlim_t l = get(resource, hard);
|
||||
|
||||
if (l == RLIM_INFINITY)
|
||||
streams.out()->append(format_string(L"unlimited\n"));
|
||||
else
|
||||
streams.out()->append(format_string(L"%lu\n", l / get_multiplier(resource)));
|
||||
}
|
||||
|
||||
/// Print values of all resource limits.
|
||||
static void print_all(int hard, io_streams_t &streams) {
|
||||
int i;
|
||||
int w = 0;
|
||||
|
||||
for (i = 0; resource_arr[i].desc; i++) {
|
||||
w = std::max(w, fish_wcswidth(resource_arr[i].desc));
|
||||
}
|
||||
|
||||
for (i = 0; resource_arr[i].desc; i++) {
|
||||
struct rlimit ls;
|
||||
rlim_t l;
|
||||
getrlimit(resource_arr[i].resource, &ls);
|
||||
l = hard ? ls.rlim_max : ls.rlim_cur;
|
||||
|
||||
const wchar_t *unit =
|
||||
((resource_arr[i].resource == RLIMIT_CPU)
|
||||
? L"(seconds, "
|
||||
: (get_multiplier(resource_arr[i].resource) == 1 ? L"(" : L"(kB, "));
|
||||
|
||||
streams.out()->append(format_string(L"%-*ls %10ls-%lc) ", w, resource_arr[i].desc, unit,
|
||||
resource_arr[i].switch_char));
|
||||
|
||||
if (l == RLIM_INFINITY) {
|
||||
streams.out()->append(format_string(L"unlimited\n"));
|
||||
} else {
|
||||
streams.out()->append(
|
||||
format_string(L"%lu\n", l / get_multiplier(resource_arr[i].resource)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the description for the specified resource limit.
|
||||
static const wchar_t *get_desc(int what) {
|
||||
int i;
|
||||
|
||||
for (i = 0; resource_arr[i].desc; i++) {
|
||||
if (resource_arr[i].resource == what) {
|
||||
return resource_arr[i].desc;
|
||||
}
|
||||
}
|
||||
return L"Not a resource";
|
||||
}
|
||||
|
||||
/// Set the new value of the specified resource limit. This function does _not_ multiply the limit
|
||||
// value by the multiplier constant used by the commandline ulimit.
|
||||
static int set_limit(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) {
|
||||
struct rlimit ls;
|
||||
|
||||
getrlimit(resource, &ls);
|
||||
if (hard) ls.rlim_max = value;
|
||||
if (soft) {
|
||||
ls.rlim_cur = value;
|
||||
|
||||
// Do not attempt to set the soft limit higher than the hard limit.
|
||||
if ((value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY) ||
|
||||
(value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max)) {
|
||||
ls.rlim_cur = ls.rlim_max;
|
||||
}
|
||||
}
|
||||
|
||||
if (setrlimit(resource, &ls)) {
|
||||
if (errno == EPERM) {
|
||||
streams.err()->append(
|
||||
format_string(L"ulimit: Permission denied when changing resource of type '%ls'\n",
|
||||
get_desc(resource)));
|
||||
} else {
|
||||
builtin_wperror(L"ulimit", streams);
|
||||
}
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
/// The ulimit builtin, used for setting resource limits.
|
||||
int builtin_ulimit(const void *_parser, void *_streams, void *_argv) {
|
||||
const auto &parser = *static_cast<const parser_t *>(_parser);
|
||||
auto &streams = *static_cast<io_streams_t *>(_streams);
|
||||
auto argv = static_cast<const wchar_t **>(_argv);
|
||||
const wchar_t *cmd = argv[0];
|
||||
int argc = builtin_count_args(argv);
|
||||
bool report_all = false;
|
||||
bool hard = false;
|
||||
bool soft = false;
|
||||
int what = RLIMIT_FSIZE;
|
||||
|
||||
static const wchar_t *const short_options = L":HSabcdefilmnqrstuvwyKPTh";
|
||||
static const struct woption long_options[] = {{L"all", no_argument, 'a'},
|
||||
{L"hard", no_argument, 'H'},
|
||||
{L"soft", no_argument, 'S'},
|
||||
{L"socket-buffers", no_argument, 'b'},
|
||||
{L"core-size", no_argument, 'c'},
|
||||
{L"data-size", no_argument, 'd'},
|
||||
{L"nice", no_argument, 'e'},
|
||||
{L"file-size", no_argument, 'f'},
|
||||
{L"pending-signals", no_argument, 'i'},
|
||||
{L"lock-size", no_argument, 'l'},
|
||||
{L"resident-set-size", no_argument, 'm'},
|
||||
{L"file-descriptor-count", no_argument, 'n'},
|
||||
{L"queue-size", no_argument, 'q'},
|
||||
{L"realtime-priority", no_argument, 'r'},
|
||||
{L"stack-size", no_argument, 's'},
|
||||
{L"cpu-time", no_argument, 't'},
|
||||
{L"process-count", no_argument, 'u'},
|
||||
{L"virtual-memory-size", no_argument, 'v'},
|
||||
{L"swap-size", no_argument, 'w'},
|
||||
{L"realtime-maxtime", no_argument, 'y'},
|
||||
{L"kernel-queues", no_argument, 'K'},
|
||||
{L"ptys", no_argument, 'P'},
|
||||
{L"threads", no_argument, 'T'},
|
||||
{L"help", no_argument, 'h'},
|
||||
{}};
|
||||
|
||||
int opt;
|
||||
wgetopter_t w;
|
||||
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, nullptr)) != -1) {
|
||||
switch (opt) {
|
||||
case 'a': {
|
||||
report_all = true;
|
||||
break;
|
||||
}
|
||||
case 'H': {
|
||||
hard = true;
|
||||
break;
|
||||
}
|
||||
case 'S': {
|
||||
soft = true;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
what = RLIMIT_SBSIZE;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
what = RLIMIT_CORE;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
what = RLIMIT_DATA;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
#ifdef RLIMIT_NICE
|
||||
what = RLIMIT_NICE;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
what = RLIMIT_FSIZE;
|
||||
break;
|
||||
}
|
||||
case 'i': {
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
what = RLIMIT_SIGPENDING;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
what = RLIMIT_MEMLOCK;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
#ifdef RLIMIT_RSS
|
||||
what = RLIMIT_RSS;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
what = RLIMIT_NOFILE;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
what = RLIMIT_MSGQUEUE;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'r': {
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
what = RLIMIT_RTPRIO;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
what = RLIMIT_STACK;
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
what = RLIMIT_CPU;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
#ifdef RLIMIT_NPROC
|
||||
what = RLIMIT_NPROC;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
#ifdef RLIMIT_AS
|
||||
what = RLIMIT_AS;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
#ifdef RLIMIT_SWAP
|
||||
what = RLIMIT_SWAP;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'y': {
|
||||
#ifdef RLIMIT_RTTIME
|
||||
what = RLIMIT_RTTIME;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'K': {
|
||||
#ifdef RLIMIT_KQUEUES
|
||||
what = RLIMIT_KQUEUES;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'P': {
|
||||
#ifdef RLIMIT_NPTS
|
||||
what = RLIMIT_NPTS;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'T': {
|
||||
#ifdef RLIMIT_NTHR
|
||||
what = RLIMIT_NTHR;
|
||||
#else
|
||||
what = RLIMIT_UNKNOWN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case ':': {
|
||||
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
case '?': {
|
||||
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], true);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected retval from wgetopt_long");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (report_all) {
|
||||
print_all(hard, streams);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
if (what == RLIMIT_UNKNOWN) {
|
||||
streams.err()->append(
|
||||
format_string(_(L"%ls: Resource limit not available on this operating system\n"), cmd));
|
||||
builtin_print_error_trailer(parser, *streams.err(), cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
int arg_count = argc - w.woptind;
|
||||
if (arg_count == 0) {
|
||||
// Show current limit value.
|
||||
print(what, hard, streams);
|
||||
return STATUS_CMD_OK;
|
||||
} else if (arg_count != 1) {
|
||||
streams.err()->append(format_string(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd));
|
||||
builtin_print_error_trailer(parser, *streams.err(), cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Change current limit value.
|
||||
if (!hard && !soft) {
|
||||
// Set both hard and soft limits if neither was specified.
|
||||
hard = soft = true;
|
||||
}
|
||||
|
||||
rlim_t new_limit;
|
||||
if (*argv[w.woptind] == L'\0') {
|
||||
streams.err()->append(format_string(_(L"%ls: New limit cannot be an empty string\n"), cmd));
|
||||
builtin_print_error_trailer(parser, *streams.err(), cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
} else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
|
||||
new_limit = RLIM_INFINITY;
|
||||
} else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
|
||||
new_limit = get(what, 1);
|
||||
} else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
|
||||
new_limit = get(what, soft);
|
||||
} else {
|
||||
new_limit = fish_wcstol(argv[w.woptind]);
|
||||
if (errno) {
|
||||
streams.err()->append(
|
||||
format_string(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]));
|
||||
builtin_print_error_trailer(parser, *streams.err(), cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
new_limit *= get_multiplier(what);
|
||||
}
|
||||
|
||||
return set_limit(what, hard, soft, new_limit, streams);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// Prototypes for functions for executing builtin_ulimit functions.
|
||||
#ifndef FISH_BUILTIN_ULIMIT_H
|
||||
#define FISH_BUILTIN_ULIMIT_H
|
||||
|
||||
#include "../maybe.h"
|
||||
|
||||
struct Parser;
|
||||
struct IoStreams;
|
||||
using parser_t = Parser;
|
||||
using io_streams_t = IoStreams;
|
||||
|
||||
int builtin_ulimit(const void *parser, void *streams, void *argv);
|
||||
#endif
|
|
@ -1,7 +1,6 @@
|
|||
#include "builtin.h"
|
||||
#include "builtins/bind.h"
|
||||
#include "builtins/commandline.h"
|
||||
#include "builtins/ulimit.h"
|
||||
#include "event.h"
|
||||
#include "fds.h"
|
||||
#include "fish_indent_common.h"
|
||||
|
@ -40,5 +39,4 @@ void mark_as_used(const parser_t& parser, env_stack_t& env_stack) {
|
|||
|
||||
builtin_bind({}, {}, {});
|
||||
builtin_commandline({}, {}, {});
|
||||
builtin_ulimit({}, {}, {});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue