diff -r 000000000000 -r 2e3d3ce01487 openenvutils/commandshell/shell/src/builtins/rlimits.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openenvutils/commandshell/shell/src/builtins/rlimits.c Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,912 @@ +//rlimits.c - resource limit builtins +// +// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. +// +/* + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ +#include "rlimits.mdh" +#include "rlimits.pro" + +#ifdef __SYMBIAN32__ +#include "dummy.h" +#endif //__SYMBIAN32__ + +#ifdef __SYMBIAN32__ +#ifdef __WINSCW__ +#pragma warn_unusedarg off +#endif//__WINSCW__ +#endif//__SYMBIAN32__ + +#if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY) + +enum { + ZLIMTYPE_MEMORY, + ZLIMTYPE_NUMBER, + ZLIMTYPE_TIME, + ZLIMTYPE_UNKNOWN +}; + +/* Generated rec array containing limits required for the limit builtin. * + * They must appear in this array in numerical order of the RLIMIT_* macros. */ + +# include "rlimits.h" + +static rlim_t +zstrtorlimt(const char *s, char **t, int base) +{ + rlim_t ret = 0; + + if (strcmp(s, "unlimited") == 0) { + if (t) + *t = (char *) s + 9; + return RLIM_INFINITY; + } +# if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED) + if (!base) { + if (*s != '0') + base = 10; + else if (*++s == 'x' || *s == 'X') + base = 16, s++; + else + base = 8; + } + if (base <= 10) + for (; *s >= '0' && *s < ('0' + base); s++) + ret = ret * base + *s - '0'; + else + for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) + || (*s >= 'A' && *s < ('A' + base - 10)); s++) + ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); + if (t) + *t = (char *)s; +# else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */ + ret = zstrtol(s, t, base); +# endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */ + return ret; +} + +/**/ +static void +showlimitvalue(int lim, rlim_t val) +{ + /* display limit for resource number lim */ + if (lim < ZSH_NLIMITS) + printf("%-16s", recs[lim]); + else + { + /* Unknown limit, hence unknown units. */ + printf("%-16d", lim); + } + if (val == RLIM_INFINITY) + printf("unlimited\n"); + else if (lim >= ZSH_NLIMITS) + { +# ifdef RLIM_T_IS_QUAD_T + printf("%qd\n", val); +# else +# ifdef RLIM_T_IS_LONG_LONG + printf("%lld\n", val); +# else +# ifdef RLIM_T_IS_UNSIGNED + printf("%lu\n", val); +# else + printf("%ld\n", val); +# endif /* RLIM_T_IS_UNSIGNED */ +# endif /* RLIM_T_IS_LONG_LONG */ +# endif /* RLIM_T_IS_QUAD_T */ + } + else if (limtype[lim] == ZLIMTYPE_TIME) { + /* time-type resource -- display as hours, minutes and + seconds. */ + printf("%d:%02d:%02d\n", (int)(val / 3600), + (int)(val / 60) % 60, (int)(val % 60)); + } else if (limtype[lim] == ZLIMTYPE_NUMBER || + limtype[lim] == ZLIMTYPE_UNKNOWN) { + /* pure numeric resource */ + printf("%d\n", (int)val); + } else if (val >= 1024L * 1024L) + /* memory resource -- display with `K' or `M' modifier */ +# ifdef RLIM_T_IS_QUAD_T + printf("%qdMB\n", val / (1024L * 1024L)); + else + printf("%qdkB\n", val / 1024L); +# else +# ifdef RLIM_T_IS_LONG_LONG + printf("%lldMB\n", val / (1024L * 1024L)); + else + printf("%lldkB\n", val / 1024L); +# else +# ifdef RLIM_T_IS_UNSIGNED + printf("%luMB\n", val / (1024L * 1024L)); + else + printf("%lukB\n", val / 1024L); +# else + printf("%ldMB\n", val / (1024L * 1024L)); + else + printf("%ldkB\n", val / 1024L); +# endif /* RLIM_T_IS_UNSIGNED */ +# endif /* RLIM_T_IS_LONG_LONG */ +# endif /* RLIM_T_IS_QUAD_T */ +} + +/* Display resource limits. hard indicates whether `hard' or `soft' * + * limits should be displayed. lim specifies the limit, or may be -1 * + * to show all. */ + +/**/ +static int +showlimits(char *nam, int hard, int lim) +{ + int rt; + + if (lim >= ZSH_NLIMITS) + { + /* + * Not configured into the shell. Ask the OS + * explicitly for this limit. + */ + struct rlimit vals; + if (getrlimit(lim, &vals) < 0) + { + zwarnnam(nam, "can't read limit: %e", NULL, errno); + return 1; + } + showlimitvalue(lim, hard ? vals.rlim_max : vals.rlim_cur); + } + else if (lim != -1) + { + showlimitvalue(lim, hard ? limits[lim].rlim_max : + limits[lim].rlim_cur); + } + else + { + /* main loop over resource types */ + for (rt = 0; rt != ZSH_NLIMITS; rt++) + showlimitvalue(rt, (hard) ? limits[rt].rlim_max : + limits[rt].rlim_cur); + } + + return 0; +} + +/* Display a resource limit, in ulimit style. lim specifies which * + * limit should be displayed, and hard indicates whether the hard or * + * soft limit should be displayed. */ + +/**/ +static int +printulimit(char *nam, int lim, int hard, int head) +{ + rlim_t limit; + + /* get the limit in question */ + if (lim >= ZSH_NLIMITS) + { + struct rlimit vals; + + if (getrlimit(lim, &vals) < 0) + { + zwarnnam(nam, "can't read limit: %e", NULL, errno); + return 1; + } + limit = (hard) ? vals.rlim_max : vals.rlim_cur; + } + else + limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur; + /* display the appropriate heading */ + switch (lim) { + case RLIMIT_CORE: + if (head) + printf("-c: core file size (blocks) "); + if (limit != RLIM_INFINITY) + limit /= 512; + break; + case RLIMIT_DATA: + if (head) + printf("-d: data seg size (kbytes) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; + case RLIMIT_FSIZE: + if (head) + printf("-f: file size (blocks) "); + if (limit != RLIM_INFINITY) + limit /= 512; + break; +# ifdef HAVE_RLIMIT_SIGPENDING + case RLIMIT_SIGPENDING: + if (head) + printf("-i: pending signals "); + break; +# endif +# ifdef HAVE_RLIMIT_MEMLOCK + case RLIMIT_MEMLOCK: + if (head) + printf("-l: locked-in-memory size (kb) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_MEMLOCK */ +/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid * + * duplicate case statement. Observed on QNX Neutrino 6.1.0. */ +# if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS) && !defined(RLIMIT_RSS_IS_AS) + case RLIMIT_RSS: + if (head) + printf("-m: resident set size (kbytes) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_RSS */ +# if defined(HAVE_RLIMIT_VMEM) && defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS) + case RLIMIT_VMEM: + if (head) + printf("-m: memory size (kb) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_VMEM */ +# ifdef HAVE_RLIMIT_NOFILE + case RLIMIT_NOFILE: + if (head) + printf("-n: file descriptors "); + break; +# endif /* HAVE_RLIMIT_NOFILE */ +# ifdef HAVE_RLIMIT_MSGQUEUE + case RLIMIT_MSGQUEUE: + if (head) + printf("-q: bytes in POSIX msg queues "); + break; +# endif + case RLIMIT_STACK: + if (head) + printf("-s: stack size (kbytes) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; + case RLIMIT_CPU: + if (head) + printf("-t: cpu time (seconds) "); + break; +# ifdef HAVE_RLIMIT_NPROC + case RLIMIT_NPROC: + if (head) + printf("-u: processes "); + break; +# endif /* HAVE_RLIMIT_NPROC */ +# if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS)) + case RLIMIT_VMEM: + if (head) + printf("-v: virtual memory size (kb) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_VMEM */ +# if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS) + case RLIMIT_AS: + if (head) + printf("-v: address space (kb) "); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_AS */ +# ifdef HAVE_RLIMIT_LOCKS + case RLIMIT_LOCKS: + if (head) + printf("-x: file locks "); + break; +# endif /* HAVE_RLIMIT_LOCKS */ +# ifdef HAVE_RLIMIT_AIO_MEM + case RLIMIT_AIO_MEM: + if (head) + printf("-N %2d: AIO locked-in-memory (kb) ", RLIMIT_AIO_MEM); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_AIO_MEM */ +# ifdef HAVE_RLIMIT_AIO_OPS + case RLIMIT_AIO_OPS: + if (head) + printf("-N %2d: AIO operations ", RLIMIT_AIO_OPS); + break; +# endif /* HAVE_RLIMIT_AIO_OPS */ +# ifdef HAVE_RLIMIT_TCACHE + case RLIMIT_TCACHE: + if (head) + printf("-N %2d: cached threads ", RLIMIT_TCACHE); + break; +# endif /* HAVE_RLIMIT_TCACHE */ +# ifdef HAVE_RLIMIT_SBSIZE + case RLIMIT_SBSIZE: + if (head) + printf("-N %2d: socket buffer size (kb) ", RLIMIT_SBSIZE); + if (limit != RLIM_INFINITY) + limit /= 1024; + break; +# endif /* HAVE_RLIMIT_SBSIZE */ +# ifdef HAVE_RLIMIT_PTHREAD + case RLIMIT_PTHREAD: + if (head) + printf("-N %2d: threads per process ", RLIMIT_PTHREAD); + break; +# endif /* HAVE_RLIMIT_PTHREAD */ + default: + if (head) + printf("-N %2d: ", lim); + break; + } + /* display the limit */ + if (limit == RLIM_INFINITY) + printf("unlimited\n"); + else { +# ifdef RLIM_T_IS_QUAD_T + printf("%qd\n", limit); +# else +# ifdef RLIM_T_IS_LONG_LONG + printf("%lld\n", limit); +# else +# ifdef RLIM_T_IS_UNSIGNED + printf("%lu\n", limit); +# else + printf("%ld\n", limit); +# endif /* RLIM_T_IS_UNSIGNED */ +# endif /* RLIM_T_IS_LONG_LONG */ +# endif /* RLIM_T_IS_QUAD_T */ + } + + return 0; +} + +/**/ +static int +do_limit(char *nam, int lim, rlim_t val, int hard, int soft, int set) +{ + if (lim >= ZSH_NLIMITS) { + struct rlimit vals; + if (getrlimit(lim, &vals) < 0) + { + /* best guess about error */ + zwarnnam(nam, "can't read limit: %e", NULL, errno); + return 1; + } + if (hard) + { + if (val > vals.rlim_max && geteuid()) { + zwarnnam(nam, "can't raise hard limits", NULL, 0); + return 1; + } + vals.rlim_max = val; + /* + * not show if all systems will do this silently, but + * best be safe... + */ + if (val < vals.rlim_cur) + vals.rlim_cur = val; + } + if (soft || !hard) { + if (val > vals.rlim_max) { + zwarnnam(nam, "limit exceeds hard limit", NULL, 0); + return 1; + } + else + vals.rlim_cur = val; + } + if (!set) + { + zwarnnam(nam, + "warning: unrecognised limit %d, use -s to set", + NULL, lim); + return 1; + } + else if (setrlimit(lim, &vals) < 0) + { + zwarnnam(nam, "setrlimit failed: %e", NULL, errno); + return 1; + } + } else { + /* new limit is valid and has been interpreted; apply it to the + specified resource */ + if (hard) { + /* can only raise hard limits if running as root */ + if (val > current_limits[lim].rlim_max && geteuid()) { + zwarnnam(nam, "can't raise hard limits", NULL, 0); + return 1; + } else { + limits[lim].rlim_max = val; + if (val < limits[lim].rlim_cur) + limits[lim].rlim_cur = val; + } + } + if (soft || !hard) { + if (val > limits[lim].rlim_max) { + /* no idea about this difference, don't intend to worry */ + if (*nam == 'u') + { + /* ulimit does this */ + if (val > current_limits[lim].rlim_max && geteuid()) { + zwarnnam(nam, "value exceeds hard limit", NULL, 0); + return 1; + } + limits[lim].rlim_max = limits[lim].rlim_cur = val; + } else { + /* but limit does this */ + zwarnnam(nam, "limit exceeds hard limit", NULL, 0); + return 1; + } + } else + limits[lim].rlim_cur = val; + if (set && zsetlimit(lim, "limit")) + return 1; + } + } + return 0; +} + +/* limit: set or show resource limits. The variable hard indicates * + * whether `hard' or `soft' resource limits are being set/shown. */ + +/**/ +static int +bin_limit(char *nam, char **argv, Options ops, UNUSED(int func)) +{ + char *s; + int hard, limnum, lim; + rlim_t val; + int ret = 0; + + hard = OPT_ISSET(ops,'h'); + if (OPT_ISSET(ops,'s') && !*argv) + return setlimits(NULL); + /* without arguments, display limits */ + if (!*argv) + return showlimits(nam, hard, -1); + while ((s = *argv++)) { + /* Search for the appropriate resource name. When a name matches (i.e. * + * starts with) the argument, the lim variable changes from -1 to the * + * number of the resource. If another match is found, lim goes to -2. */ + if (idigit(*s)) + { + lim = (int)zstrtol(s, NULL, 10); + } + else + for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++) + if (!strncmp(recs[limnum], s, strlen(s))) { + if (lim != -1) + lim = -2; + else + lim = limnum; + } + /* lim==-1 indicates that no matches were found. * + * lim==-2 indicates that multiple matches were found. */ + if (lim < 0) { + zwarnnam(nam, + (lim == -2) ? "ambiguous resource specification: %s" + : "no such resource: %s", s, 0); + return 1; + } + /* without value for limit, display the current limit */ + if (!(s = *argv++)) + return showlimits(nam, hard, lim); + if (lim >= ZSH_NLIMITS) + { + val = zstrtorlimt(s, &s, 10); + if (*s) + { + /* unknown limit, no idea how to scale */ + zwarnnam(nam, "unknown scaling factor: %s", s, 0); + return 1; + } + } + else if (limtype[lim] == ZLIMTYPE_TIME) { + /* time-type resource -- may be specified as seconds, or minutes or * + * hours with the `m' and `h' modifiers, and `:' may be used to add * + * together more than one of these. It's easier to understand from * + * the code: */ + val = zstrtorlimt(s, &s, 10); + if (*s) { + if ((*s == 'h' || *s == 'H') && !s[1]) + val *= 3600L; + else if ((*s == 'm' || *s == 'M') && !s[1]) + val *= 60L; + else if (*s == ':') + val = val * 60 + zstrtorlimt(s + 1, &s, 10); + else { + zwarnnam(nam, "unknown scaling factor: %s", s, 0); + return 1; + } + } + } else if (limtype[lim] == ZLIMTYPE_NUMBER || limtype[lim] == ZLIMTYPE_UNKNOWN) { + /* pure numeric resource -- only a straight decimal number is + permitted. */ + char *t = s; + val = zstrtorlimt(t, &s, 10); + if (s == t) { + zwarnnam(nam, "limit must be a number", NULL, 0); + return 1; + } + } else { + /* memory-type resource -- `k' and `M' modifiers are permitted, + meaning (respectively) 2^10 and 2^20. */ + val = zstrtorlimt(s, &s, 10); + if (!*s || ((*s == 'k' || *s == 'K') && !s[1])) { + if (val != RLIM_INFINITY) + val *= 1024L; + } else if ((*s == 'M' || *s == 'm') && !s[1]) + val *= 1024L * 1024; + else { + zwarnnam(nam, "unknown scaling factor: %s", s, 0); + return 1; + } + } + if (do_limit(nam, lim, val, hard, !hard, OPT_ISSET(ops, 's'))) + ret++; + } + return ret; +} + +/**/ +static int +do_unlimit(char *nam, int lim, int hard, int soft, int set, int euid) +{ + /* remove specified limit */ + if (lim >= ZSH_NLIMITS) { + struct rlimit vals; + if (getrlimit(lim, &vals) < 0) + { + zwarnnam(nam, "can't read limit: %e", NULL, errno); + return 1; + } + if (hard) { + if (euid && vals.rlim_max != RLIM_INFINITY) { + zwarnnam(nam, "can't remove hard limits", NULL, 0); + return 1; + } else + vals.rlim_max = RLIM_INFINITY; + } + if (!hard || soft) + vals.rlim_cur = vals.rlim_max; + if (!set) { + zwarnnam(nam, + "warning: unrecognised limit %d, use -s to set", + NULL, lim); + return 1; + } else if (setrlimit(lim, &vals) < 0) { + zwarnnam(nam, "setrlimit failed: %e", NULL, errno); + return 1; + } + } else { + if (hard) { + if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) { + zwarnnam(nam, "can't remove hard limits", NULL, 0); + return 1; + } else + limits[lim].rlim_max = RLIM_INFINITY; + } + if (!hard || soft) + limits[lim].rlim_cur = limits[lim].rlim_max; + if (set && zsetlimit(lim, nam)) + return 1; + } + return 0; +} + +/* unlimit: remove resource limits. Much of this code is the same as * + * that in bin_limit(). */ + +/**/ +static int +bin_unlimit(char *nam, char **argv, Options ops, UNUSED(int func)) +{ + int hard, limnum, lim; + int ret = 0; + uid_t euid = geteuid(); + + hard = OPT_ISSET(ops,'h'); + /* Without arguments, remove all limits. */ + if (!*argv) { + for (limnum = 0; limnum != RLIM_NLIMITS; limnum++) { + if (hard) { + if (euid && current_limits[limnum].rlim_max != RLIM_INFINITY) + ret++; + else + limits[limnum].rlim_max = RLIM_INFINITY; + } else + limits[limnum].rlim_cur = limits[limnum].rlim_max; + } + if (OPT_ISSET(ops,'s')) + ret += setlimits(nam); + if (ret) + zwarnnam(nam, "can't remove hard limits", NULL, 0); + } else { + for (; *argv; argv++) { + /* Search for the appropriate resource name. When a name * + * matches (i.e. starts with) the argument, the lim variable * + * changes from -1 to the number of the resource. If another * + * match is found, lim goes to -2. */ + if (idigit(**argv)) { + lim = (int)zstrtol(*argv, NULL, 10); + } else { + for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++) + if (!strncmp(recs[limnum], *argv, strlen(*argv))) { + if (lim != -1) + lim = -2; + else + lim = limnum; + } + } + /* lim==-1 indicates that no matches were found. * + * lim==-2 indicates that multiple matches were found. */ + if (lim < 0) { + zwarnnam(nam, + (lim == -2) ? "ambiguous resource specification: %s" + : "no such resource: %s", *argv, 0); + return 1; + } + else if (do_unlimit(nam, lim, hard, !hard, OPT_ISSET(ops, 's'), + euid)) + ret++; + } + } + return ret; +} + +/* ulimit: set or display resource limits */ + +/**/ +static int +bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) +{ + int res, resmask = 0, hard = 0, soft = 0, nres = 0, all = 0, ret = 0; + char *options; + + do { + options = *argv; + if (options && *options == '-' && !options[1]) { + zwarnnam(name, "missing option letter", NULL, 0); + return 1; + } + res = -1; + if (options && *options == '-') { + argv++; + while (*++options) { + if(*options == Meta) + *++options ^= 32; + res = -1; + switch (*options) { + case 'H': + hard = 1; + continue; + case 'S': + soft = 1; + continue; + case 'N': + if (options[1]) { + res = (int)zstrtol(options+1, NULL, 10); + } else if (*argv) { + res = (int)zstrtol(*argv++, NULL, 10); + } else { + zwarnnam(name, "number required after -N", + NULL, 0); + return 1; + } + /* + * fake it so it looks like we just finished an option... + */ + while (options[1]) + options++; + break; + case 'a': + if (resmask) { + zwarnnam(name, "no limits allowed with -a", + NULL, 0); + return 1; + } + all = 1; + resmask = (1 << RLIM_NLIMITS) - 1; + nres = RLIM_NLIMITS; + continue; + case 't': + res = RLIMIT_CPU; + break; + case 'f': + res = RLIMIT_FSIZE; + break; + case 'd': + res = RLIMIT_DATA; + break; + case 's': + res = RLIMIT_STACK; + break; + case 'c': + res = RLIMIT_CORE; + break; +# ifdef HAVE_RLIMIT_RSS + case 'm': + res = RLIMIT_RSS; + break; +# endif /* HAVE_RLIMIT_RSS */ +# ifdef HAVE_RLIMIT_MEMLOCK + case 'l': + res = RLIMIT_MEMLOCK; + break; +# endif /* HAVE_RLIMIT_MEMLOCK */ +# ifdef HAVE_RLIMIT_NOFILE + case 'n': + res = RLIMIT_NOFILE; + break; +# endif /* HAVE_RLIMIT_NOFILE */ +# ifdef HAVE_RLIMIT_NPROC + case 'u': + res = RLIMIT_NPROC; + break; +# endif /* HAVE_RLIMIT_NPROC */ +# if defined(HAVE_RLIMIT_VMEM) || defined(HAVE_RLIMIT_AS) + case 'v': +# ifdef HAVE_RLIMIT_VMEM + res = RLIMIT_VMEM; +# else + res = RLIMIT_AS; +# endif + break; +# endif /* HAVE_RLIMIT_VMEM */ +# ifdef HAVE_RLIMIT_LOCKS + case 'x': + res = RLIMIT_LOCKS; + break; +# endif +# ifdef HAVE_RLIMIT_SIGPENDING + case 'i': + res = RLIMIT_SIGPENDING; + break; +# endif +# ifdef HAVE_RLIMIT_MSGQUEUE + case 'q': + res = RLIMIT_MSGQUEUE; + break; +# endif + default: + /* unrecognised limit */ + zwarnnam(name, "bad option: -%c", NULL, *options); + return 1; + } + if (options[1]) { + resmask |= 1 << res; + nres++; + } + if (all && res != -1) { + zwarnnam(name, "no limits allowed with -a", + NULL, 0); + return 1; + } + } + } + if (!*argv || **argv == '-') { + if (res < 0) { + if (*argv || nres) + continue; + else + res = RLIMIT_FSIZE; + } + resmask |= 1 << res; + nres++; + continue; + } + if (all) { + zwarnnam(name, "no arguments allowed after -a", NULL, 0); + return 1; + } + if (res < 0) + res = RLIMIT_FSIZE; + if (strcmp(*argv, "unlimited")) { + /* set limit to specified value */ + rlim_t limit; + + limit = zstrtorlimt(*argv, NULL, 10); + /* scale appropriately */ + switch (res) { + case RLIMIT_FSIZE: + case RLIMIT_CORE: + limit *= 512; + break; + case RLIMIT_DATA: + case RLIMIT_STACK: +# ifdef HAVE_RLIMIT_RSS + case RLIMIT_RSS: +# endif /* HAVE_RLIMIT_RSS */ +# ifdef HAVE_RLIMIT_MEMLOCK + case RLIMIT_MEMLOCK: +# endif /* HAVE_RLIMIT_MEMLOCK */ +/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid * + * duplicate case statement. Observed on QNX Neutrino 6.1.0. */ +# if defined(HAVE_RLIMIT_VMEM) && !defined(RLIMIT_VMEM_IS_RSS) + case RLIMIT_VMEM: +# endif /* HAVE_RLIMIT_VMEM */ +/* ditto RLIMIT_VMEM and RLIMIT_AS */ +# if defined(HAVE_RLIMIT_AS) && !defined(RLIMIT_VMEM_IS_AS) && !defined(RLIMIT_RSS_IS_AS) + case RLIMIT_AS: +# endif /* HAVE_RLIMIT_AS */ +# ifdef HAVE_RLIMIT_AIO_MEM + case RLIMIT_AIO_MEM: +# endif /* HAVE_RLIMIT_AIO_MEM */ + limit *= 1024; + break; + } + if (do_limit(name, res, limit, hard, soft, 1)) + ret++; + } else { + if (do_unlimit(name, res, hard, soft, 1, geteuid())) + ret++; + } + argv++; + } while (*argv); + for (res = 0; resmask; res++, resmask >>= 1) + if ((resmask & 1) && printulimit(name, res, hard, nres > 1)) + ret++; + return ret; +} + +#else /* !HAVE_GETRLIMIT || !RLIM_INFINITY */ + +# define bin_limit bin_notavail +# define bin_ulimit bin_notavail +# define bin_unlimit bin_notavail + +#endif /* !HAVE_GETRLIMIT || !RLIM_INFINITY */ + +static struct builtin bintab[] = { + BUILTIN("limit", 0, bin_limit, 0, -1, 0, "sh", NULL), + BUILTIN("ulimit", 0, bin_ulimit, 0, -1, 0, NULL, NULL), + BUILTIN("unlimit", 0, bin_unlimit, 0, -1, 0, "hs", NULL), +}; + +/**/ +int +setup_(UNUSED(Module m)) +{ + return 0; +} + +/**/ +int +boot_(Module m) +{ + return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); +} + +/**/ +int +cleanup_(Module m) +{ + deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; +} + +/**/ +int +finish_(UNUSED(Module m)) +{ + return 0; +}