_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:
parent
92eb2aee78
commit
6c6be2a87e
4
check.t
4
check.t
@ -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
307
funcs.c
@ -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
19
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 $ */
|
||||
/* $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
15
mksh.1
@ -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
4
sh.h
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user