_careful_ (feature) sync with oksh:

(3 weeks, 5 days ago) by millert
Make ulimit able to get and set multiple limits in a single invocation
like bash and zsh do.  Requested by espie@, OK deraadt@
This commit is contained in:
tg 2008-04-16 21:56:03 +00:00
parent 92eb2aee78
commit 6c6be2a87e
5 changed files with 185 additions and 164 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.174 2008/04/11 19:55:23 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.175 2008/04/16 21:56:00 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -7,7 +7,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R33 2008/04/11 @(#)MIRBSD KSH R33 2008/04/16
description: description:
Check version of shell. Check version of shell.
category: pdksh category: pdksh

265
funcs.c
View File

@ -1,11 +1,11 @@
/* $OpenBSD: c_ksh.c,v 1.30 2007/08/02 10:50:25 fgsch Exp $ */ /* $OpenBSD: c_ksh.c,v 1.30 2007/08/02 10:50:25 fgsch Exp $ */
/* $OpenBSD: c_sh.c,v 1.37 2007/09/03 13:54:23 otto Exp $ */ /* $OpenBSD: c_sh.c,v 1.37 2007/09/03 13:54:23 otto Exp $ */
/* $OpenBSD: c_test.c,v 1.17 2005/03/30 17:16:37 deraadt Exp $ */ /* $OpenBSD: c_test.c,v 1.17 2005/03/30 17:16:37 deraadt Exp $ */
/* $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 $ */
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.75 2008/04/01 22:20:19 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.76 2008/04/16 21:56:01 tg Exp $");
/* A leading = means assignments before command are kept; /* A leading = means assignments before command are kept;
* a leading * means a POSIX special builtin; * a leading * means a POSIX special builtin;
@ -2853,89 +2853,79 @@ ptest_error(Test_env *te, int ofs, const char *msg)
#define SOFT 0x1 #define SOFT 0x1
#define HARD 0x2 #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;
};
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
int int
c_ulimit(const char **wp) c_ulimit(const char **wp)
{ {
static const struct limits { static const struct limits limits[] = {
const char *name; /* do not use options -H, -S or -a or change the order */
enum { RLIMIT, ULIMIT } which; #ifdef RLIMIT_CPU
int gcmd; /* get command */ { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
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 */
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE,
512, 'c' },
#endif
#ifdef RLIMIT_DATA
{ "data(KiB)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA,
1024, 'd' },
#endif #endif
#ifdef RLIMIT_FSIZE #ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
512, 'f' },
#endif #endif
#ifdef RLIMIT_LOCKS #ifdef RLIMIT_CORE
{ "flocks", RLIMIT, RLIMIT_LOCKS, RLIMIT_LOCKS, { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
-1, 'L' },
#endif #endif
#ifdef RLIMIT_MEMLOCK #ifdef RLIMIT_DATA
{ "lockedmem(KiB)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, { "data(KiB)", RLIMIT_DATA, 1024, 'd' },
1024, 'l' },
#endif
#ifdef RLIMIT_RSS
{ "memory(KiB)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS,
1024, 'm' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE,
1, 'n' },
#endif
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC,
1, 'p' },
#endif #endif
#ifdef RLIMIT_STACK #ifdef RLIMIT_STACK
{ "stack(KiB)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, { "stack(KiB)", RLIMIT_STACK, 1024, 's' },
1024, 's' },
#endif #endif
#ifdef RLIMIT_TIME #ifdef RLIMIT_MEMLOCK
{ "humantime(seconds)", RLIMIT, RLIMIT_TIME, RLIMIT_TIME, { "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
1, 'T' },
#endif #endif
#ifdef RLIMIT_CPU #ifdef RLIMIT_RSS
{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, { "memory(KiB)", RLIMIT_RSS, 1024, 'm' },
1, 't' }, #endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
#endif
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT_NPROC, 1, 'p' },
#endif #endif
#ifdef RLIMIT_VMEM #ifdef RLIMIT_VMEM
{ "vmemory(KiB)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, { "vmemory(KiB)", RLIMIT_VMEM, 1024, 'v' },
1024, 'v' },
#endif #endif
#ifdef RLIMIT_SWAP #ifdef RLIMIT_SWAP
{ "swap(KiB)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, { "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
1024, 'w' },
#endif #endif
{ NULL, RLIMIT, 0, 0, 0, 0 } #ifdef RLIMIT_LOCKS
{ "flocks", RLIMIT_LOCKS, -1, 'L' },
#endif
#ifdef RLIMIT_TIME
{ "humantime(seconds)", RLIMIT_TIME, 1, 'T' },
#endif
{ NULL, 0, 0, 0 }
}; };
static char opts[3 + NELEM(limits)]; static char opts[4 + NELEM(limits) * 2];
rlim_t val = (rlim_t)0; int how = SOFT | HARD, optc;
int how = SOFT | HARD, optc, what; bool all = false;
bool all = false, set;
const struct limits *l; const struct limits *l;
struct rlimit limit;
if (!opts[0]) { if (!opts[0]) {
/* build options string on first call - yuck */ /* build options string on first call - yuck */
char *p = opts; char *p = opts;
*p++ = 'H'; *p++ = 'S'; *p++ = 'a'; *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
for (l = limits; l->name; l++) for (l = limits; l->name; l++) {
*p++ = l->option; *p++ = l->option;
*p++ = '#';
}
*p = '\0'; *p = '\0';
} }
what = 'f'; /* first check for -a, -H and -S */
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (optc) { switch (optc) {
case 'H': case 'H':
@ -2948,106 +2938,133 @@ c_ulimit(const char **wp)
all = true; all = true;
break; break;
case '?': case '?':
return 1; return (1);
default: default:
what = optc; break;
} }
for (l = limits; l->name && l->option != what; l++) if (wp[builtin_opt.optind] != NULL) {
bi_errorf("usage: ulimit [-acdfHLlmnpSsTtvw] [value]");
return (1);
}
/* 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, opts)) != -1)
switch (optc) {
case 'a':
case 'H':
case 'S':
break;
case '?':
return (1);
default:
for (l = limits; l->name && l->option != optc; l++)
; ;
if (!l->name) { if (!l->name) {
internal_warningf("ulimit: %c", what); internal_warningf("ulimit: %c", optc);
return 1; return (1);
}
if (!builtin_opt.optarg)
print_ulimit(l, how);
else if (set_ulimit(l, builtin_opt.optarg, how))
return (1);
break;
} }
wp += builtin_opt.optind; wp += builtin_opt.optind;
if ((set = *wp ? true : false)) {
if (all || wp[1]) { if (all)
bi_errorf("too many arguments"); for (l = limits; l->name; l++) {
return 1; shprintf("%-20s ", l->name);
print_ulimit(l, how);
} }
if (strcmp(wp[0], "unlimited") == 0) else if (builtin_opt.optind == 1) {
/* no limit specified, use file size as default */
#ifndef RLIMIT_FSIZE
internal_warningf("ulimit: need argument");
return (1);
#else
#ifdef RLIMIT_CPU
l = &limits[1];
#else
l = &limits[0];
#endif
if (!wp[0])
print_ulimit(l, how);
else if (set_ulimit(l, wp[0], how))
return(1);
#endif
}
return (0);
}
static int
set_ulimit(const struct limits *l, const char *v, int how)
{
rlim_t val = (rlim_t)0;
struct rlimit limit;
if (strcmp(v, "unlimited") == 0)
val = (rlim_t)RLIM_INFINITY; val = (rlim_t)RLIM_INFINITY;
else { else {
long rval; long rval;
if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR, false)) if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
return 1; return (1);
/* Avoid problems caused by typos that /*
* evaluate misses due to evaluating unset * Avoid problems caused by typos that evaluate misses due
* parameters to 0... * to evaluating unset parameters to 0...
* If this causes problems, will have to * If this causes problems, will have to add parameter to
* add parameter to evaluate() to control * evaluate() to control if unset params are 0 or an error.
* if unset params are 0 or an error.
*/ */
if (!rval && !ksh_isdigit(wp[0][0])) { if (!rval && !ksh_isdigit(v[0])) {
bi_errorf("invalid limit: %s", wp[0]); bi_errorf("invalid limit: %s", v);
return 1; return (1);
} }
val = (rlim_t)((rlim_t)rval * l->factor); val = (rlim_t)rval * l->factor;
} }
}
if (all) { if (getrlimit(l->resource, &limit) < 0) {
for (l = limits; l->name; l++) { /* some cannot be read, e.g. Linux RLIMIT_LOCKS */
if (l->which == RLIMIT) {
#ifdef RLIMIT_LOCKS
if (getrlimit(l->gcmd, &limit) < 0)
if ((errno == EINVAL) &&
(l->gcmd == RLIMIT_LOCKS)) {
limit.rlim_cur = RLIM_INFINITY; limit.rlim_cur = RLIM_INFINITY;
limit.rlim_max = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY;
} }
#else
getrlimit(l->gcmd, &limit);
#endif
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
}
shprintf("%-20s ", l->name);
if (val == (rlim_t)RLIM_INFINITY)
shf_puts("unlimited\n", shl_stdout);
else {
val = (rlim_t)(val / l->factor);
shprintf("%ld\n", (long)val);
}
}
return 0;
}
if (l->which == RLIMIT) {
getrlimit(l->gcmd, &limit);
if (set) {
if (how & SOFT) if (how & SOFT)
limit.rlim_cur = val; limit.rlim_cur = val;
if (how & HARD) if (how & HARD)
limit.rlim_max = val; limit.rlim_max = val;
if (setrlimit(l->scmd, &limit) < 0) { if (setrlimit(l->resource, &limit) < 0) {
how = errno; if (errno == EPERM)
if (how == EPERM) bi_errorf("%s exceeds allowable limit", l->name);
bi_errorf("exceeds allowable limit");
else else
bi_errorf("bad limit: %s", bi_errorf("bad %s limit: %s", l->name, strerror(errno));
strerror(how)); return (1);
return 1; }
return (0);
}
static void
print_ulimit(const struct limits *l, int how)
{
rlim_t val = (rlim_t)0;
struct rlimit limit;
if (getrlimit(l->resource, &limit)) {
shf_puts("unknown\n", shl_stdout);
return;
} }
} else {
if (how & SOFT) if (how & SOFT)
val = limit.rlim_cur; val = limit.rlim_cur;
else if (how & HARD) else if (how & HARD)
val = limit.rlim_max; val = limit.rlim_max;
} if (val == RLIM_INFINITY)
}
if (!set) {
if (val == (rlim_t)RLIM_INFINITY)
shf_puts("unlimited\n", shl_stdout); shf_puts("unlimited\n", shl_stdout);
else { else {
val = (rlim_t)(val / l->factor); val /= l->factor;
shprintf("%ld\n", (long)val); shprintf("%ld\n", (long)val);
} }
} }
return (0);
}
int int
c_rename(const char **wp) c_rename(const char **wp)

19
misc.c
View File

@ -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 $ */
/* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */ /* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */
#include "sh.h" #include "sh.h"
@ -6,7 +6,7 @@
#include <grp.h> #include <grp.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.72 2008/04/11 19:55:23 tg Exp $\t" __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.73 2008/04/16 21:56:02 tg Exp $\t"
MKSH_SH_H_ID); MKSH_SH_H_ID);
#undef USE_CHVT #undef USE_CHVT
@ -810,10 +810,10 @@ ksh_getopt_reset(Getopt *go, int flags)
* the option is missing). * the option is missing).
* Used for 'read -u2', 'print -u2' and fc -40. * Used for 'read -u2', 'print -u2' and fc -40.
* - '#' is like ':' in options, expect that the argument is optional * - '#' is like ':' in options, expect that the argument is optional
* and must start with a digit. If the argument doesn't start with a * and must start with a digit or be the string "unlimited". If the
* digit, it is assumed to be missing and normal option processing * argument doesn't match, it is assumed to be missing and normal option
* continues (optarg is set to 0 if the option is missing). * processing continues (optarg is set to 0 if the option is missing).
* Used for 'typeset -LZ4'. * Used for 'typeset -LZ4' and 'ulimit -adunlimited'.
* - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an * - 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 * option starting with + is accepted, the GI_PLUS flag will be set
* in go->info. * in go->info.
@ -896,13 +896,16 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
* argument is missing. * argument is missing.
*/ */
if (argv[go->optind - 1][go->p]) { if (argv[go->optind - 1][go->p]) {
if (ksh_isdigit(argv[go->optind - 1][go->p])) { if (ksh_isdigit(argv[go->optind - 1][go->p]) ||
!strcmp(&argv[go->optind - 1][go->p], "unlimited")) {
go->optarg = argv[go->optind - 1] + go->p; go->optarg = argv[go->optind - 1] + go->p;
go->p = 0; go->p = 0;
} else } else
go->optarg = NULL; go->optarg = NULL;
} else { } else {
if (argv[go->optind] && ksh_isdigit(argv[go->optind][0])) { if (argv[go->optind] &&
(ksh_isdigit(argv[go->optind][0]) ||
!strcmp(argv[go->optind], "unlimited"))) {
go->optarg = argv[go->optind++]; go->optarg = argv[go->optind++];
go->p = 0; go->p = 0;
} else } else

15
mksh.1
View File

@ -1,5 +1,5 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.115 2008/04/01 21:07:20 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.116 2008/04/16 21:56:02 tg Exp $
.\" $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 $
.\"- .\"-
.\" Try to make GNU groff and AT&T nroff more compatible .\" Try to make GNU groff and AT&T nroff more compatible
.\" * ` generates in groff, so use \` .\" * ` generates in groff, so use \`
@ -30,7 +30,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
.. ..
.\"- .\"-
.Dd $Mdocdate: April 1 2008 $ .Dd $Mdocdate: April 16 2008 $
.Dt MKSH 1 .Dt MKSH 1
.Os MirBSD .Os MirBSD
.Sh NAME .Sh NAME
@ -4077,15 +4077,16 @@ unless they are also given on the same command line.
.Pp .Pp
.It Xo .It Xo
.Ic ulimit .Ic ulimit
.Op Fl acdfHLlmnpSsTtvw .Op Fl acdfHLlmnpSsTtvw Op Ar value
.Op Ar value .Ar ...
.Xc .Xc
Display or set process limits. Display or set process limits.
If no options are used, the file size limit If no options are used, the file size limit
.Pq Fl f .Pq Fl f
is assumed. is assumed.
.Ar value , .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 . .Dq unlimited .
The limits affect the shell and any processes created by the shell after a The limits affect the shell and any processes created by the shell after a
limit is imposed. limit is imposed.
@ -5454,7 +5455,7 @@ and many other persons, and is currently maintained by
.An Thorsten Glaser Aq tg@mirbsd.de . .An Thorsten Glaser Aq tg@mirbsd.de .
.Sh BUGS .Sh BUGS
This document attempts to describe This document attempts to describe
.Nm mksh\ R33c .Nm mksh\ R34
and up, and up,
compiled without any options impacting functionality, such as compiled without any options impacting functionality, such as
.Dv MKSH_SMALL , .Dv MKSH_SMALL ,

4
sh.h
View File

@ -8,8 +8,8 @@
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */ /* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */ /* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.204 2008/04/11 19:55:24 tg Exp $" #define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.205 2008/04/16 21:56:03 tg Exp $"
#define MKSH_VERSION "R33 2008/04/11" #define MKSH_VERSION "R33 2008/04/16"
#if HAVE_SYS_PARAM_H #if HAVE_SYS_PARAM_H
#include <sys/param.h> #include <sys/param.h>