From 7a2afe644c45728b93a82e743e3bd49df17c3f43 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Thu, 19 Oct 1995 18:42:12 +0000 Subject: [PATCH] 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. --- bin/sh/builtins | 3 +- bin/sh/miscbltin.c | 215 ++++++++++++++++++++++++++++++++++++++++++++- bin/sh/sh.1 | 54 +++++++++++- 3 files changed, 269 insertions(+), 3 deletions(-) diff --git a/bin/sh/builtins b/bin/sh/builtins index 96247185b34b..a0b0f8fc7e9a 100755 --- a/bin/sh/builtins +++ b/bin/sh/builtins @@ -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 diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c index 52a66e72e65c..be7f0f793702 100644 --- a/bin/sh/miscbltin.c +++ b/bin/sh/miscbltin.c @@ -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 +#include +#include +#include + +#if BSD +#include +#include +#include +#include +#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 */ + + 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 */ diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 989b214d20a7..a5201a253130 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -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