Implement the "ulimit" builtin. This is the analogon to csh's "limit"

command and badly needed in sh(1) for everybody who wants to modify
the system-wide limits from inside /etc/rc.

The options are similar to other system's implemantations of this
command, with the FreeBSD additions for -m (memoryuse) and -p (max
processes) that are not available on other systems.
This commit is contained in:
Joerg Wunsch 1995-10-19 18:42:12 +00:00
parent c2cb0dfbf0
commit 7a2afe644c
3 changed files with 269 additions and 3 deletions

View File

@ -35,7 +35,7 @@
# SUCH DAMAGE.
#
# @(#)builtins 8.1 (Berkeley) 5/31/93
# $Id$
# $Id: builtins,v 1.2 1994/09/24 02:57:23 davidg Exp $
#
# This file lists all the builtin commands. The first column is the name
@ -83,6 +83,7 @@ setvarcmd setvar
shiftcmd shift
trapcmd trap
truecmd : true
ulimitcmd ulimit
umaskcmd umask
unaliascmd unalias
unsetcmd unset

View File

@ -4,6 +4,7 @@
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
* The ulimit() builtin has been contributed by Joerg Wunsch.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -33,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: miscbltin.c,v 1.2 1994/09/24 02:57:52 davidg Exp $
*/
#ifndef lint
@ -52,6 +53,18 @@ static char sccsid[] = "@(#)miscbltin.c 8.2 (Berkeley) 4/16/94";
#include "error.h"
#include "mystring.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if BSD
#include <limits.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#undef eflag
extern char **argptr; /* argument list for builtin command */
@ -166,3 +179,203 @@ umaskcmd(argc, argv) char **argv; {
}
return 0;
}
#if BSD
struct restab {
int resource;
int scale;
char *descript;
};
/* multi-purpose */
#define RLIMIT_UNSPEC (-2)
/* resource */
#define RLIMIT_ALL (-1)
/* mode */
#define RLIMIT_SHOW 0
#define RLIMIT_SET 1
/* what */
#define RLIMIT_SOFT 1
#define RLIMIT_HARD 2
static struct restab restab[] = {
{RLIMIT_CORE, 512, "coredump(512-blocks) "},
{RLIMIT_CPU, 1, "time(seconds) "},
{RLIMIT_DATA, 1024, "datasize(kilobytes) "},
{RLIMIT_FSIZE, 512, "filesize(512-blocks) "},
{RLIMIT_MEMLOCK, 1024, "lockedmem(kilobytes) "},
{RLIMIT_NOFILE, 1, "nofiles(descriptors) "},
{RLIMIT_NPROC, 1, "processes(max) "},
{RLIMIT_RSS, 1024, "memoryuse(kilobytes) "},
{RLIMIT_STACK, 1024, "stacksize(kilobytes) "}
};
/* get entry into above table */
static struct restab *
find_resource(resource) {
int i;
struct restab *rp;
for(i = 0, rp = restab;
i < sizeof restab / sizeof(struct restab);
i++, rp++)
if(rp->resource == resource)
return rp;
error("internal error: resource not in table");
return 0;
}
static void
print_resource(rp, what, with_descript) struct restab *rp; {
struct rlimit rlim;
quad_t val;
(void)getrlimit(rp->resource, &rlim);
val = (what == RLIMIT_SOFT)?
rlim.rlim_cur: rlim.rlim_max;
if(with_descript)
out1str(rp->descript);
if(val == RLIM_INFINITY)
out1str("unlimited\n");
else {
val /= (quad_t)rp->scale;
if(val > (quad_t)ULONG_MAX)
out1fmt("> %lu\n", (unsigned long)ULONG_MAX);
else
out1fmt("%lu\n", (unsigned long)val);
}
}
ulimitcmd(argc, argv) char **argv; {
struct rlimit rlim;
char *p;
int i;
int resource = RLIMIT_UNSPEC;
quad_t val;
int what = RLIMIT_UNSPEC;
int mode = RLIMIT_UNSPEC;
int errs = 0, arg = 1;
struct restab *rp;
extern int optreset; /* XXX should be declared in <stdlib.h> */
opterr = 0; /* use own error processing */
optreset = 1;
optind = 1;
while ((i = getopt(argc, argv, "HSacdfnstmlp")) != EOF) {
arg++;
switch(i) {
case 'H':
if(what == RLIMIT_UNSPEC) what = 0;
what |= RLIMIT_HARD;
break;
case 'S':
if(what == RLIMIT_UNSPEC) what = 0;
what |= RLIMIT_SOFT;
break;
case 'a':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_ALL;
mode = RLIMIT_SHOW;
break;
case 'c':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_CORE;
break;
case 'd':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_DATA;
break;
case 'f':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_FSIZE;
break;
case 'n':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_NOFILE;
break;
case 's':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_STACK;
break;
case 't':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_CPU;
break;
case 'm':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_RSS;
break;
case 'l':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_MEMLOCK;
break;
case 'p':
if(resource != RLIMIT_UNSPEC) errs++;
resource = RLIMIT_NPROC;
break;
case '?':
error("illegal option -%c", optopt);
}
}
argc -= optind;
argv += optind;
if(argc > 1)
error("too many arguments");
if(argc == 0)
mode = RLIMIT_SHOW;
else if (resource == RLIMIT_ALL)
errs++;
else
mode = RLIMIT_SET;
if(mode == RLIMIT_UNSPEC)
mode = RLIMIT_SHOW;
if(resource == RLIMIT_UNSPEC)
resource = RLIMIT_FSIZE;
if(what == RLIMIT_UNSPEC)
what = (mode == RLIMIT_SHOW)?
RLIMIT_SOFT: (RLIMIT_SOFT|RLIMIT_HARD);
if(mode == RLIMIT_SHOW && what == (RLIMIT_SOFT|RLIMIT_HARD))
errs++;
if(errs)
error("Wrong option combination");
if(resource == RLIMIT_ALL)
for(i = 0; i < sizeof restab / sizeof(struct restab); i++)
print_resource(restab + i, what, 1);
else if(mode == RLIMIT_SHOW)
print_resource(find_resource(resource), what, 0);
else {
rp = find_resource(resource);
if(strcmp(argv[0], "unlimited") == 0)
val = RLIM_INFINITY;
else {
val = 0;
p = argv[0];
do {
if((i = *p - '0') < 0 || i > 9)
error("Illegal number: %s", argv[0]);
val = (10 * val) + (quad_t)i;
} while (*++p != '\0');
val *= (quad_t)rp->scale;
}
(void)getrlimit(resource, &rlim);
if(what & RLIMIT_HARD)
rlim.rlim_max = val;
if(what & RLIMIT_SOFT)
rlim.rlim_cur = val;
if(setrlimit(resource, &rlim) == -1) {
outfmt(&errout, "ulimit: bad limit: %s\n",
strerror(errno));
return 1;
}
}
return 0;
}
#else /* !BSD */
#error ulimit() not implemented
#endif /* BSD */

View File

@ -33,7 +33,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)sh.1 8.4 (Berkeley) 4/18/94
.\" $Id: sh.1,v 1.2 1994/09/24 02:58:13 davidg Exp $
.\" $Id: sh.1,v 1.3 1995/05/05 16:49:15 adam Exp $
.\"
.\"
.\"
.na
.TH SH 1
@ -1277,6 +1279,56 @@ resets trapped (but not ignored) signals to the
default action. The trap command has no effect on
signals that were ignored on entry to the shell.
.TP
ulimit [ -HSacdflmnpst ] [ limit ]
Set or display resource limits (see getrlimit(2)).
If ``limit'' is specified, the named resource will be set;
otherwise the current resource value will be displayed.
.br
If ``-H'' is specified, the hard limits will be
set or displayed. While everybody is allowed to reduce a
hard limit, only the superuser can increase it. Option ``-S''
specifies the soft limits instead. When displaying limits,
only one of ``-S'' or ``-H'' can be given. The default is
to display the soft limits, and to set both, the hard and
the soft limits.
.br
Option ``-a'' requests to display all resources. The parameter
``limit'' is not acceptable in this mode.
.br
The remaining options specify which resource value is to be
displayed or modified. They are mutually exclusive.
.RS +.7i
.TP 2
-c coredumpsize
The maximal size of core dump files, in 512-byte blocks.
.TP 2
-d datasize
The maximal size of the data segment of a process, in kilobytes.
.TP 2
-f filesize
The maximal size of a file, in 512-byte blocks. This is the
default.
.TP 2
-l lockedmem
The maximal size of memory that can be locked by a process, in
kilobytes.
.TP 2
-m memoryuse
The maximal resident set size of a process, in kilobytes.
.TP 2
-n nofiles
The maximal number of descriptors that could be opened by a process.
.TP 2
-p procmax
The maximal number of simultaneous processes for this user ID.
.TP 2
-s stacksize
The maximal size of the stack segment, in kilobytes.
.TP 2
-t time
The maximal amount of CPU time to be used by each process, in seconds.
.RE
.TP
umask [ mask ]
Set the value of umask (see umask(2)) to the specified octal value.
If the argument is omitted, the