10f66f451Sopenharmony_ci/* ulimit.c - Modify resource limits
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2015 Rob Landley <rob@landley.net>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ulimit.html
60f66f451Sopenharmony_ci * And man prlimit(2).
70f66f451Sopenharmony_ci *
80f66f451Sopenharmony_ci * Deviations from posix: The units on -f are supposed to be 512 byte
90f66f451Sopenharmony_ci * "blocks" (no other options are specified, and even hard drives don't
100f66f451Sopenharmony_ci * do that anymore). Bash uses 1024 byte blocks, so they don't care either.
110f66f451Sopenharmony_ci * We consistently use bytes everywhere we can.
120f66f451Sopenharmony_ci *
130f66f451Sopenharmony_ci * Deviations from bash: Sizes are in bytes (instead of -p 512 and -f 1024).
140f66f451Sopenharmony_ci * Bash's -p value has been wrong since 2010 (git 35f3d14dbbc5).
150f66f451Sopenharmony_ci * The kernel implementation of RLIMIT_LOCKS (-x) was removed from Linux in
160f66f451Sopenharmony_ci * 2003. Bash never implemented -b (it's in the help but unrecognized at
170f66f451Sopenharmony_ci * runtime). We support -P to affect processes other than us.
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ciUSE_ULIMIT(NEWTOY(ulimit, ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]", TOYFLAG_USR|TOYFLAG_BIN))
200f66f451Sopenharmony_ciUSE_ULIMIT(OLDTOY(prlimit, ulimit, TOYFLAG_USR|TOYFLAG_BIN))
210f66f451Sopenharmony_ci
220f66f451Sopenharmony_ciconfig ULIMIT
230f66f451Sopenharmony_ci  bool "ulimit"
240f66f451Sopenharmony_ci  default y
250f66f451Sopenharmony_ci  depends on TOYBOX_PRLIMIT
260f66f451Sopenharmony_ci  help
270f66f451Sopenharmony_ci    usage: ulimit [-P PID] [-SHRacdefilmnpqrstuv] [LIMIT]
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci    Print or set resource limits for process number PID. If no LIMIT specified
300f66f451Sopenharmony_ci    (or read-only -ap selected) display current value (sizes in bytes).
310f66f451Sopenharmony_ci    Default is ulimit -P $PPID -Sf" (show soft filesize of your shell).
320f66f451Sopenharmony_ci
330f66f451Sopenharmony_ci    -S  Set/show soft limit          -H  Set/show hard (maximum) limit
340f66f451Sopenharmony_ci    -a  Show all limits              -c  Core file size
350f66f451Sopenharmony_ci    -d  Process data segment         -e  Max scheduling priority
360f66f451Sopenharmony_ci    -f  Output file size             -i  Pending signal count
370f66f451Sopenharmony_ci    -l  Locked memory                -m  Resident Set Size
380f66f451Sopenharmony_ci    -n  Number of open files         -p  Pipe buffer
390f66f451Sopenharmony_ci    -q  Posix message queue          -r  Max Real-time priority
400f66f451Sopenharmony_ci    -R  Realtime latency (usec)      -s  Stack size
410f66f451Sopenharmony_ci    -t  Total CPU time (in seconds)  -u  Maximum processes (under this UID)
420f66f451Sopenharmony_ci    -v  Virtual memory size          -P  PID to affect (default $PPID)
430f66f451Sopenharmony_ci*/
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ci#define FOR_ulimit
460f66f451Sopenharmony_ci#include "toys.h"
470f66f451Sopenharmony_ci
480f66f451Sopenharmony_ciGLOBALS(
490f66f451Sopenharmony_ci  long P;
500f66f451Sopenharmony_ci)
510f66f451Sopenharmony_ci
520f66f451Sopenharmony_ci// This is a linux kernel syscall added in 2.6.36 (git c022a0acad53) which
530f66f451Sopenharmony_ci// glibc only exports a wrapper prototype for if you #define _FSF_HURD_RULZE.
540f66f451Sopenharmony_ciint prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
550f66f451Sopenharmony_ci  struct rlimit *old_limit);
560f66f451Sopenharmony_ci
570f66f451Sopenharmony_ci// I'd like to sort the RLIMIT values 0-15, but mips, alpha and sparc
580f66f451Sopenharmony_ci// override the asm-generic values for 5-9. Also, the kernel implementation
590f66f451Sopenharmony_ci// of RLIMIT_LOCKS (-x) was removed from Linux in 2003.
600f66f451Sopenharmony_civoid ulimit_main(void)
610f66f451Sopenharmony_ci{
620f66f451Sopenharmony_ci  struct rlimit rr;
630f66f451Sopenharmony_ci  int i;
640f66f451Sopenharmony_ci  // Order is cdefilmnqRrstuv
650f66f451Sopenharmony_ci  char map[] = {RLIMIT_CORE, RLIMIT_DATA, RLIMIT_NICE, RLIMIT_FSIZE,
660f66f451Sopenharmony_ci                RLIMIT_SIGPENDING, RLIMIT_MEMLOCK, RLIMIT_RSS, RLIMIT_NOFILE, 0,
670f66f451Sopenharmony_ci                RLIMIT_MSGQUEUE, RLIMIT_RTTIME, RLIMIT_RTPRIO, RLIMIT_STACK,
680f66f451Sopenharmony_ci                RLIMIT_CPU, RLIMIT_NPROC, RLIMIT_AS};
690f66f451Sopenharmony_ci
700f66f451Sopenharmony_ci  if (!(toys.optflags&(FLAG_H-1))) toys.optflags |= FLAG_f;
710f66f451Sopenharmony_ci  if ((FLAG(a)||FLAG(p)) && toys.optc) error_exit("can't set -ap");
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_ci  // Fetch data
740f66f451Sopenharmony_ci  if (!FLAG(P)) TT.P = getppid();
750f66f451Sopenharmony_ci
760f66f451Sopenharmony_ci  for (i=0; i<sizeof(map); i++) {
770f66f451Sopenharmony_ci    char *flags="cdefilmnpqRrstuv";
780f66f451Sopenharmony_ci
790f66f451Sopenharmony_ci    int get = toys.optflags&(FLAG_a|(1<<i));
800f66f451Sopenharmony_ci
810f66f451Sopenharmony_ci    if (get && prlimit(TT.P, map[i], 0, &rr)) perror_exit("-%c", flags[i]);
820f66f451Sopenharmony_ci    if (!toys.optc) {
830f66f451Sopenharmony_ci      if (FLAG(a)) printf("-%c: ", flags[i]);
840f66f451Sopenharmony_ci      if (get) {
850f66f451Sopenharmony_ci        if ((1<<i)&FLAG_p) {
860f66f451Sopenharmony_ci          if (FLAG(H))
870f66f451Sopenharmony_ci            xreadfile("/proc/sys/fs/pipe-max-size", toybuf, sizeof(toybuf));
880f66f451Sopenharmony_ci          else {
890f66f451Sopenharmony_ci            int pp[2];
900f66f451Sopenharmony_ci
910f66f451Sopenharmony_ci            xpipe(pp);
920f66f451Sopenharmony_ci            sprintf(toybuf, "%d\n", fcntl(*pp, F_GETPIPE_SZ));
930f66f451Sopenharmony_ci          }
940f66f451Sopenharmony_ci          printf("%s", toybuf);
950f66f451Sopenharmony_ci        } else {
960f66f451Sopenharmony_ci          rlim_t rl = FLAG(H) ? rr.rlim_max : rr.rlim_cur;
970f66f451Sopenharmony_ci
980f66f451Sopenharmony_ci          if (rl == RLIM_INFINITY) printf("unlimited\n");
990f66f451Sopenharmony_ci          else printf("%ld\n", (long)rl);
1000f66f451Sopenharmony_ci        }
1010f66f451Sopenharmony_ci      }
1020f66f451Sopenharmony_ci    }
1030f66f451Sopenharmony_ci    if (toys.optflags&(1<<i)) break;
1040f66f451Sopenharmony_ci  }
1050f66f451Sopenharmony_ci
1060f66f451Sopenharmony_ci  if (FLAG(a)||FLAG(p)) return;
1070f66f451Sopenharmony_ci
1080f66f451Sopenharmony_ci  if (toys.optc) {
1090f66f451Sopenharmony_ci    rlim_t val;
1100f66f451Sopenharmony_ci
1110f66f451Sopenharmony_ci    if (tolower(**toys.optargs) == 'u') val = RLIM_INFINITY;
1120f66f451Sopenharmony_ci    else val = atolx_range(*toys.optargs, 0, LONG_MAX);
1130f66f451Sopenharmony_ci
1140f66f451Sopenharmony_ci    if (FLAG(H)) rr.rlim_max = val;
1150f66f451Sopenharmony_ci    else rr.rlim_cur = val;
1160f66f451Sopenharmony_ci    if (prlimit(TT.P, map[i], &rr, 0)) perror_exit(0);
1170f66f451Sopenharmony_ci  }
1180f66f451Sopenharmony_ci}
119