summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2008-03-21 12:51:20 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2008-03-21 12:51:20 +0000
commit25878968814c23048bc7e55a93aa79bae794f20c (patch)
tree05805791dcb1fb428fd2e746d4a4a7dfcee27a9a
parent78097a4aa1e1b2da48f871664c79f9d1aef8009e (diff)
Make ulimit able to get and set multiple limits in a single invocation
like bash and zsh do. Requested by espie@, OK deraadt@
-rw-r--r--bin/ksh/c_ulimit.c224
-rw-r--r--bin/ksh/ksh.119
-rw-r--r--bin/ksh/misc.c16
-rw-r--r--bin/ksh/sh.119
4 files changed, 148 insertions, 130 deletions
diff --git a/bin/ksh/c_ulimit.c b/bin/ksh/c_ulimit.c
index 8c81dc14d83..bf580772a9c 100644
--- a/bin/ksh/c_ulimit.c
+++ b/bin/ksh/c_ulimit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_ulimit.c,v 1.16 2006/11/20 21:53:39 miod Exp $ */
+/* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */
/*
ulimit -- handle "ulimit" builtin
@@ -24,51 +24,52 @@
#define SOFT 0x1
#define HARD 0x2
+struct limits {
+ const char *name;
+ int resource; /* resource to get/set */
+ int factor; /* multiply by to get rlim_{cur,max} values */
+ char option; /* option character (-d, -f, ...) */
+};
+
+static void print_ulimit(const struct limits *, int);
+static int set_ulimit(const struct limits *, const char *, int);
+
int
c_ulimit(char **wp)
{
- static const struct limits {
- const char *name;
- enum { RLIMIT, ULIMIT } which;
- int gcmd; /* get command */
- int scmd; /* set command (or -1, if no set command) */
- int factor; /* multiply by to get rlim_{cur,max} values */
- char option;
- } limits[] = {
- /* Do not use options -H, -S or -a */
- { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
- { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
- { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
- { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
- { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
- { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK,
- 1024, 'l' },
- { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
- { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE,
- 1, 'n' },
- { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
- #ifdef RLIMIT_VMEM
- { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
- #endif /* RLIMIT_VMEM */
+ static const struct limits limits[] = {
+ /* Do not use options -H, -S or -a or change the order. */
+ { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
+ { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
+ { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
+ { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
+ { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
+ { "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
+ { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
+ { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
+ { "processes", RLIMIT_NPROC, 1, 'p' },
+#ifdef RLIMIT_VMEM
+ { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
+#endif /* RLIMIT_VMEM */
{ (char *) 0 }
};
- static char options[3 + NELEM(limits)];
- rlim_t val = 0;
+ static char options[4 + NELEM(limits) * 2];
int how = SOFT | HARD;
const struct limits *l;
- int set, all = 0;
- int optc, what;
- struct rlimit limit;
+ int optc, all = 0;
+
if (!options[0]) {
/* build options string on first call - yuck */
char *p = options;
*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
- for (l = limits; l->name; l++)
+ for (l = limits; l->name; l++) {
*p++ = l->option;
+ *p++ = '#';
+ }
*p = '\0';
}
- what = 'f';
+ /* First check for -a, -H and -S. */
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
switch (optc) {
case 'H':
@@ -83,92 +84,117 @@ c_ulimit(char **wp)
case '?':
return 1;
default:
- what = optc;
+ break;
}
- for (l = limits; l->name && l->option != what; l++)
- ;
- if (!l->name) {
- internal_errorf(0, "ulimit: %c", what);
+ if (wp[builtin_opt.optind] != NULL) {
+ bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
return 1;
}
- wp += builtin_opt.optind;
- set = *wp ? 1 : 0;
- if (set) {
- if (all || wp[1]) {
- bi_errorf("too many arguments");
+ /* Then parse and act on the actual limits, one at a time */
+ ksh_getopt_reset(&builtin_opt, GF_ERROR);
+ while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
+ switch (optc) {
+ case 'a':
+ case 'H':
+ case 'S':
+ break;
+ case '?':
return 1;
- }
- if (strcmp(wp[0], "unlimited") == 0)
- val = RLIM_INFINITY;
- else {
- long rval;
-
- if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR, false))
- return 1;
- /* Avoid problems caused by typos that
- * evaluate misses due to evaluating unset
- * parameters to 0...
- * If this causes problems, will have to
- * add parameter to evaluate() to control
- * if unset params are 0 or an error.
- */
- if (!rval && !digit(wp[0][0])) {
- bi_errorf("invalid limit: %s", wp[0]);
+ default:
+ for (l = limits; l->name && l->option != optc; l++)
+ ;
+ if (!l->name) {
+ internal_errorf(0, "ulimit: %c", optc);
return 1;
}
- val = (rlim_t)rval * l->factor;
+ if (builtin_opt.optarg) {
+ if (set_ulimit(l, builtin_opt.optarg, how))
+ return 1;
+ } else
+ print_ulimit(l, how);
+ break;
}
- }
+
+ wp += builtin_opt.optind;
+
if (all) {
for (l = limits; l->name; l++) {
- if (l->which == RLIMIT) {
- getrlimit(l->gcmd, &limit);
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
- }
shprintf("%-20s ", l->name);
- if (val == RLIM_INFINITY)
- shprintf("unlimited\n");
- else {
- val /= l->factor;
- shprintf("%ld\n", (long) val);
- }
+ print_ulimit(l, how);
}
- return 0;
- }
- if (l->which == RLIMIT) {
- getrlimit(l->gcmd, &limit);
- if (set) {
- if (how & SOFT)
- limit.rlim_cur = val;
- if (how & HARD)
- limit.rlim_max = val;
- if (setrlimit(l->scmd, &limit) < 0) {
- if (errno == EPERM)
- bi_errorf("exceeds allowable limit");
- else
- bi_errorf("bad limit: %s",
- strerror(errno));
+ } else if (builtin_opt.optind == 1) {
+ /* No limit specified, use file size */
+ l = &limits[1];
+ if (wp[0] != NULL) {
+ if (set_ulimit(l, wp[0], how))
return 1;
- }
+ wp++;
} else {
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
+ print_ulimit(l, how);
}
}
- if (!set) {
- if (val == RLIM_INFINITY)
- shprintf("unlimited\n");
- else {
- val /= l->factor;
- shprintf("%ld\n", (long) val);
+
+ return 0;
+}
+
+static int
+set_ulimit(const struct limits *l, const char *v, int how)
+{
+ rlim_t val = 0;
+ struct rlimit limit;
+
+ if (strcmp(v, "unlimited") == 0)
+ val = RLIM_INFINITY;
+ else {
+ long rval;
+
+ if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
+ return 1;
+ /*
+ * Avoid problems caused by typos that evaluate misses due
+ * to evaluating unset parameters to 0...
+ * If this causes problems, will have to add parameter to
+ * evaluate() to control if unset params are 0 or an error.
+ */
+ if (!rval && !digit(v[0])) {
+ bi_errorf("invalid limit: %s", v);
+ return 1;
}
+ val = (rlim_t)rval * l->factor;
+ }
+
+ getrlimit(l->resource, &limit);
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (setrlimit(l->resource, &limit) < 0) {
+ if (errno == EPERM)
+ bi_errorf("exceeds allowable limit");
+ else
+ bi_errorf("bad limit: %s", strerror(errno));
+ return 1;
}
return 0;
}
+
+static void
+print_ulimit(const struct limits *l, int how)
+{
+ rlim_t val = 0;
+ struct rlimit limit;
+
+ getrlimit(l->resource, &limit);
+ if (how & SOFT)
+ val = limit.rlim_cur;
+ else if (how & HARD)
+ val = limit.rlim_max;
+ if (val == RLIM_INFINITY)
+ shprintf("unlimited\n");
+ else {
+ val /= l->factor;
+ shprintf("%ld\n", (long) val);
+ }
+}
diff --git a/bin/ksh/ksh.1 b/bin/ksh/ksh.1
index 47bfc5e5185..9331becda47 100644
--- a/bin/ksh/ksh.1
+++ b/bin/ksh/ksh.1
@@ -1,8 +1,8 @@
-.\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $
+.\" $OpenBSD: ksh.1,v 1.121 2008/03/21 12:51:19 millert Exp $
.\"
.\" Public Domain
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: March 21 2008 $
.Dt KSH 1
.Os
.Sh NAME
@@ -4256,24 +4256,19 @@ except zero padding is used instead of space padding.
.Pp
.It Xo
.Ic ulimit
-.Op Fl acdfHlmnpSst
-.Op Ar value
+.Op Fl acdfHlmnpSst Op Ar value
+.Ar ...
.Xc
Display or set process limits.
If no options are used, the file size limit
.Pq Fl f
is assumed.
.Ar value ,
-if specified, may be either an arithmetic expression or the word
+if specified, may be either an arithmetic expression starting with a
+number or the word
.Dq unlimited .
The limits affect the shell and any processes created by the shell after a
-limit is imposed.
-Note that some systems may not allow limits to be increased
-once they are set.
-Also note that the types of limits available are system
-dependent \- some systems have only the
-.Fl f
-limit.
+limit is imposed; limits may not be increased once they are set.
.Bl -tag -width 5n
.It Fl a
Display all limits; unless
diff --git a/bin/ksh/misc.c b/bin/ksh/misc.c
index 24844c013e0..3418242da7b 100644
--- a/bin/ksh/misc.c
+++ b/bin/ksh/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.32 2007/08/02 11:05:54 fgsch Exp $ */
+/* $OpenBSD: misc.c,v 1.33 2008/03/21 12:51:19 millert Exp $ */
/*
* Miscellaneous functions
@@ -891,10 +891,10 @@ ksh_getopt_reset(Getopt *go, int flags)
* the option is missing).
* Used for 'read -u2', 'print -u2' and fc -40.
* - '#' is like ':' in options, expect that the argument is optional
- * and must start with a digit. If the argument doesn't start with a
- * digit, it is assumed to be missing and normal option processing
- * continues (optarg is set to 0 if the option is missing).
- * Used for 'typeset -LZ4'.
+ * and must start with a digit or be the string "unlimited". If the
+ * argument doesn't match, it is assumed to be missing and normal option
+ * processing continues (optarg is set to 0 if the option is missing).
+ * Used for 'typeset -LZ4' and 'ulimit -adunlimited'.
* - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
* option starting with + is accepted, the GI_PLUS flag will be set
* in go->info.
@@ -977,13 +977,15 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
* argument is missing.
*/
if (argv[go->optind - 1][go->p]) {
- if (digit(argv[go->optind - 1][go->p])) {
+ if (digit(argv[go->optind - 1][go->p]) ||
+ !strcmp(&argv[go->optind - 1][go->p], "unlimited")) {
go->optarg = argv[go->optind - 1] + go->p;
go->p = 0;
} else
go->optarg = (char *) 0;
} else {
- if (argv[go->optind] && digit(argv[go->optind][0])) {
+ if (argv[go->optind] && (digit(argv[go->optind][0]) ||
+ !strcmp(argv[go->optind], "unlimited"))) {
go->optarg = argv[go->optind++];
go->p = 0;
} else
diff --git a/bin/ksh/sh.1 b/bin/ksh/sh.1
index 675773490b8..f87f0b22b8f 100644
--- a/bin/ksh/sh.1
+++ b/bin/ksh/sh.1
@@ -1,8 +1,8 @@
-.\" $OpenBSD: sh.1,v 1.75 2007/05/31 20:47:44 otto Exp $
+.\" $OpenBSD: sh.1,v 1.76 2008/03/21 12:51:19 millert Exp $
.\"
.\" Public Domain
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: March 21 2008 $
.Dt SH 1
.Os
.Sh NAME
@@ -3375,24 +3375,19 @@ except zero padding is used instead of space padding.
.Pp
.It Xo
.Ic ulimit
-.Op Fl acdfHlmnpSst
-.Op Ar value
+.Op Fl acdfHlmnpSst Op Ar value
+.Ar ...
.Xc
Display or set process limits.
If no options are used, the file size limit
.Pq Fl f
is assumed.
.Ar value ,
-if specified, may be either an arithmetic expression or the word
+if specified, may be either an arithmetic expression starting with a
+number or the word
.Dq unlimited .
The limits affect the shell and any processes created by the shell after a
-limit is imposed.
-Note that some systems may not allow limits to be increased
-once they are set.
-Also note that the types of limits available are system
-dependent \- some systems have only the
-.Fl f
-limit.
+limit is imposed; limits may not be increased once they are set.
.Bl -tag -width 5n
.It Fl a
Display all limits; unless