_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: 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 $
@ -7,7 +7,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R33 2008/04/11
@(#)MIRBSD KSH R33 2008/04/16
description:
Check version of shell.
category: pdksh

307
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_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_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"
__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 a POSIX special builtin;
@ -2853,89 +2853,79 @@ ptest_error(Test_env *te, int ofs, const char *msg)
#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;
};
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
int
c_ulimit(const 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 */
#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' },
static const struct limits limits[] = {
/* do not use options -H, -S or -a or change the order */
#ifdef RLIMIT_CPU
{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE,
512, 'f' },
{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
#endif
#ifdef RLIMIT_LOCKS
{ "flocks", RLIMIT, RLIMIT_LOCKS, RLIMIT_LOCKS,
-1, 'L' },
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "lockedmem(KiB)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK,
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' },
#ifdef RLIMIT_DATA
{ "data(KiB)", RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack(KiB)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK,
1024, 's' },
{ "stack(KiB)", RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_TIME
{ "humantime(seconds)", RLIMIT, RLIMIT_TIME, RLIMIT_TIME,
1, 'T' },
#ifdef RLIMIT_MEMLOCK
{ "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_CPU
{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU,
1, 't' },
#ifdef RLIMIT_RSS
{ "memory(KiB)", RLIMIT_RSS, 1024, 'm' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
#endif
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_VMEM
{ "vmemory(KiB)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM,
1024, 'v' },
{ "vmemory(KiB)", RLIMIT_VMEM, 1024, 'v' },
#endif
#ifdef RLIMIT_SWAP
{ "swap(KiB)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP,
1024, 'w' },
{ "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
#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)];
rlim_t val = (rlim_t)0;
int how = SOFT | HARD, optc, what;
bool all = false, set;
static char opts[4 + NELEM(limits) * 2];
int how = SOFT | HARD, optc;
bool all = false;
const struct limits *l;
struct rlimit limit;
if (!opts[0]) {
/* build options string on first call - yuck */
char *p = opts;
*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, opts)) != -1)
switch (optc) {
case 'H':
@ -2948,107 +2938,134 @@ c_ulimit(const char **wp)
all = true;
break;
case '?':
return 1;
return (1);
default:
what = optc;
break;
}
for (l = limits; l->name && l->option != what; l++)
;
if (!l->name) {
internal_warningf("ulimit: %c", what);
return 1;
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) {
internal_warningf("ulimit: %c", optc);
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;
if ((set = *wp ? true : false)) {
if (all || wp[1]) {
bi_errorf("too many arguments");
return 1;
}
if (strcmp(wp[0], "unlimited") == 0)
val = (rlim_t)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 && !ksh_isdigit(wp[0][0])) {
bi_errorf("invalid limit: %s", wp[0]);
return 1;
}
val = (rlim_t)((rlim_t)rval * l->factor);
}
}
if (all) {
if (all)
for (l = limits; l->name; l++) {
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_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)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (setrlimit(l->scmd, &limit) < 0) {
how = errno;
if (how == EPERM)
bi_errorf("exceeds allowable limit");
else
bi_errorf("bad limit: %s",
strerror(how));
return 1;
}
} else {
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
}
}
if (!set) {
if (val == (rlim_t)RLIM_INFINITY)
shf_puts("unlimited\n", shl_stdout);
else {
val = (rlim_t)(val / l->factor);
shprintf("%ld\n", (long)val);
print_ulimit(l, how);
}
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;
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 && !ksh_isdigit(v[0])) {
bi_errorf("invalid limit: %s", v);
return (1);
}
val = (rlim_t)rval * l->factor;
}
if (getrlimit(l->resource, &limit) < 0) {
/* some cannot be read, e.g. Linux RLIMIT_LOCKS */
limit.rlim_cur = RLIM_INFINITY;
limit.rlim_max = RLIM_INFINITY;
}
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("%s exceeds allowable limit", l->name);
else
bi_errorf("bad %s limit: %s", l->name, strerror(errno));
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;
}
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
if (val == RLIM_INFINITY)
shf_puts("unlimited\n", shl_stdout);
else {
val /= l->factor;
shprintf("%ld\n", (long)val);
}
}
int
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 $ */
#include "sh.h"
@ -6,7 +6,7 @@
#include <grp.h>
#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);
#undef USE_CHVT
@ -810,10 +810,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.
@ -896,13 +896,16 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
* argument is missing.
*/
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->p = 0;
} else
go->optarg = NULL;
} 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->p = 0;
} 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 $
.\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.116 2008/04/16 21:56:02 tg 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
.\" * ` generates in groff, so use \`
@ -30,7 +30,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
..
.\"-
.Dd $Mdocdate: April 1 2008 $
.Dd $Mdocdate: April 16 2008 $
.Dt MKSH 1
.Os MirBSD
.Sh NAME
@ -4077,15 +4077,16 @@ unless they are also given on the same command line.
.Pp
.It Xo
.Ic ulimit
.Op Fl acdfHLlmnpSsTtvw
.Op Ar value
.Op Fl acdfHLlmnpSsTtvw 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.
@ -5454,7 +5455,7 @@ and many other persons, and is currently maintained by
.An Thorsten Glaser Aq tg@mirbsd.de .
.Sh BUGS
This document attempts to describe
.Nm mksh\ R33c
.Nm mksh\ R34
and up,
compiled without any options impacting functionality, such as
.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: 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_VERSION "R33 2008/04/11"
#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/16"
#if HAVE_SYS_PARAM_H
#include <sys/param.h>