aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-02-09 17:23:31 -0600
committerRob Landley <rob@landley.net>2016-02-09 17:23:31 -0600
commit2f3f26ea1ec581cd24a0778323eb0844f03fd6a3 (patch)
treef7ba43fcbe762a1eb95bc5bfefa8450fe36b56a6
parenta7a869c2d5f9398a6348dbeacbfec115a5b7d34e (diff)
downloadtoybox-2f3f26ea1ec581cd24a0778323eb0844f03fd6a3.tar.gz
Add ulimit.
This isn't a shell builtin, it uses prlimit to target any pid (without -P it defaults to $PPID, so acts like historical ulimit by default).
-rw-r--r--lib/portability.h10
-rw-r--r--toys/posix/ulimit.c116
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);
+ }
+}