diff options
-rw-r--r-- | lib/portability.h | 10 | ||||
-rw-r--r-- | toys/posix/ulimit.c | 116 |
2 files changed, 126 insertions, 0 deletions
diff --git a/lib/portability.h b/lib/portability.h index eadd9961..53b08704 100644 --- a/lib/portability.h +++ b/lib/portability.h @@ -247,6 +247,16 @@ static inline void endutxent(void) {;} #define O_PATH 010000000 #endif +// Glibc won't give you linux-kernel constants unless you say "no, a BUD lite" +// even though linux has nothing to do with the FSF and never has. +#ifndef F_SETPIPE_SZ +#define F_SETPIPE_SZ 1031 +#endif + +#ifndef F_GETPIPE_SZ +#define F_GETPIPE_SZ 1032 +#endif + #if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_LONG__) \ && __SIZEOF_DOUBLE__ <= __SIZEOF_LONG__ typedef double FLOAT; diff --git a/toys/posix/ulimit.c b/toys/posix/ulimit.c new file mode 100644 index 00000000..b14cd933 --- /dev/null +++ b/toys/posix/ulimit.c @@ -0,0 +1,116 @@ +/* ulimit.c - Modify resource limits + * + * Copyright 2015 Rob Landley <rob@landley.net> + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ulimit.html + * And man prlimit(2). + * + * Deviations from posix: The units on -f are supposed to be 512 byte + * "blocks" (no other options are specified, and even hard drives don't + * do that anymore). Bash uses 1024 byte blocks, so they don't care either. + * We consistently use bytes everywhere we can. + * + * Deviations from bash: Sizes are in bytes (instead of -p 512 and -f 1024). + * Bash's -p value has been wrong since 2010 (git 35f3d14dbbc5). + * The kernel implementation of RLIMIT_LOCKS (-x) was removed from Linux in + * 2003. Bash never implemented -b (it's in the help but unrecognized at + * runtime). We support -P to affect processes other than us. + +USE_ULIMIT(NEWTOY(ulimit, ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]", TOYFLAG_USR|TOYFLAG_BIN)) + +config ULIMIT + bool "ulimit" + default y + help + usage: ulimit [-P PID] [-SHRacdefilmnpqrstuv] [LIMIT] + + Print or set resource limits for process number PID. If no LIMIT specified + (or read-only -ap selected) display current value (sizes in bytes). + Default is ulimit -P $PPID -Sf" (show soft filesize of your shell). + + -S Set/show soft limit -H Set/show hard (maximum) limit + -a Show all limits -c Core file size + -d Process data segment -e Max scheduling priority + -f Output file size -i Pending signal count + -l Locked memory -m Resident Set Size + -n Number of open files -p Pipe buffer + -q Posix message queue -r Max Real-time priority + -R Realtime latency (usec) -s Stack size + -t Total CPU time (in seconds) -u Maximum processes (under this UID) + -v Virtual memory size -P PID to affect (default $PPID) +*/ + +#define FOR_ulimit +#include "toys.h" + +GLOBALS( + long pid; +) + +// This is a linux kernel syscall added in 2.6.36 (git c022a0acad53) which +// glibc only exports a wrapper prototype for if you #define _FSF_HURD_RULZE. +int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, + struct rlimit *old_limit); + +// I'd like to sort the RLIMIT values 0-15, but mips, alpha and sparc +// override the asm-generic values for 5-9. Also, the kernel implementation +// of RLIMIT_LOCKS (-x) was removed from Linux in 2003. +void ulimit_main(void) +{ + struct rlimit rr; + int i; + // Order is cdefilmnqRrstuv + char map[] = {RLIMIT_CORE, RLIMIT_DATA, RLIMIT_NICE, RLIMIT_FSIZE, + RLIMIT_SIGPENDING, RLIMIT_MEMLOCK, RLIMIT_RSS, RLIMIT_NOFILE, 0, + RLIMIT_MSGQUEUE, RLIMIT_RTTIME, RLIMIT_RTPRIO, RLIMIT_STACK, + RLIMIT_CPU, RLIMIT_NPROC, RLIMIT_AS}; + + if (!(toys.optflags&(FLAG_H-1))) toys.optflags |= FLAG_f; + if ((toys.optflags&(FLAG_a|FLAG_p)) && toys.optc) error_exit("can't set -ap"); + + // Fetch data + if (!(toys.optflags&FLAG_P)) TT.pid = getppid(); + + for (i=0; i<sizeof(map); i++) { + char *flags="cdefilmnpqRrstuv"; + + int get = toys.optflags&(FLAG_a|(1<<i)); + + if (get && prlimit(TT.pid, map[i], 0, &rr)) perror_exit("-%c", flags[i]); + if (!toys.optc) { + if (toys.optflags&FLAG_a) printf("-%c: ", flags[i]); + if (get) { + if ((1<<i)&FLAG_p) { + if (toys.optflags&FLAG_H) + xreadfile("/proc/sys/fs/pipe-max-size", toybuf, sizeof(toybuf)); + else { + int pp[2]; + + xpipe(pp); + sprintf(toybuf, "%d\n", fcntl(*pp, F_GETPIPE_SZ)); + } + printf("%s", toybuf); + } else { + rlim_t rl = (toys.optflags&FLAG_H) ? rr.rlim_max : rr.rlim_cur; + + if (rl == RLIM_INFINITY) printf("unlimited\n"); + else printf("%ld\n", (long)rl); + } + } + } + if (toys.optflags&(1<<i)) break; + } + + if (toys.optflags&(FLAG_a|FLAG_p)) return; + + if (toys.optc) { + rlim_t val; + + if (tolower(**toys.optargs == 'i')) val = RLIM_INFINITY; + else val = atolx_range(*toys.optargs, 0, LONG_MAX); + + if (toys.optflags&FLAG_H) rr.rlim_max = val; + else rr.rlim_cur = val; + if (prlimit(TT.pid, map[i], &rr, 0)) perror_exit(0); + } +} |