603 lines
14 KiB
Modula-2
603 lines
14 KiB
Modula-2
This file is ulimit.def, from which is created ulimit.c.
|
|
It implements the builtin "ulimit" in Bash.
|
|
|
|
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
|
|
|
Bash is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 1, or (at your option) any later
|
|
version.
|
|
|
|
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with Bash; see the file COPYING. If not, write to the Free Software
|
|
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
$PRODUCES ulimit.c
|
|
|
|
$BUILTIN ulimit
|
|
$FUNCTION ulimit_builtin
|
|
$DEPENDS_ON !MINIX
|
|
$SHORT_DOC ulimit [-SHacdflmnpstuv] [limit]
|
|
Ulimit provides control over the resources available to processes
|
|
started by the shell, on systems that allow such control. If an
|
|
option is given, it is interpreted as follows:
|
|
|
|
-S use the `soft' resource limit
|
|
-H use the `hard' resource limit
|
|
-a all current limits are reported
|
|
-c the maximum size of core files created
|
|
-d the maximum size of a process's data segment
|
|
-f the maximum size of files created by the shell
|
|
-l the maximum size a process may lock into memory
|
|
-m the maximum resident set size
|
|
-n the maximum number of open file descriptors
|
|
-p the pipe buffer size
|
|
-s the maximum stack size
|
|
-t the maximum amount of cpu time in seconds
|
|
-u the maximum number of user processes
|
|
-v the size of virtual memory
|
|
|
|
If LIMIT is given, it is the new value of the specified resource.
|
|
Otherwise, the current value of the specified resource is printed.
|
|
If no option is given, then -f is assumed. Values are in 1024-byte
|
|
increments, except for -t, which is in seconds, -p, which is in
|
|
increments of 512 bytes, and -u, which is an unscaled number of
|
|
processes.
|
|
$END
|
|
|
|
#include <config.h>
|
|
|
|
#include "../bashtypes.h"
|
|
#include <sys/param.h>
|
|
|
|
#if defined (HAVE_UNISTD_H)
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "../shell.h"
|
|
#include "common.h"
|
|
#include "bashgetopt.h"
|
|
#include "pipesize.h"
|
|
|
|
#if !defined (errno)
|
|
extern int errno;
|
|
#endif
|
|
|
|
/* For some reason, HPUX chose to make these definitions visible only if
|
|
_KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
|
|
and #undef it afterward. */
|
|
#if defined (HAVE_RESOURCE)
|
|
# include <sys/time.h>
|
|
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
|
# define _KERNEL
|
|
# endif
|
|
# include <sys/resource.h>
|
|
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
|
# undef _KERNEL
|
|
# endif
|
|
#else
|
|
# include <sys/times.h>
|
|
#endif
|
|
|
|
#if defined (HAVE_LIMITS_H)
|
|
# include <limits.h>
|
|
#endif
|
|
|
|
/* Check for the most basic symbols. If they aren't present, this
|
|
system's <sys/resource.h> isn't very useful to us. */
|
|
#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
|
|
# undef HAVE_RESOURCE
|
|
#endif
|
|
|
|
#if !defined (RLIMTYPE)
|
|
# define RLIMTYPE long
|
|
# define string_to_rlimtype string_to_long
|
|
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
|
|
#endif
|
|
|
|
#define DESCFMT "%-28s"
|
|
|
|
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
|
|
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
|
|
# define RLIMIT_NOFILE RLIMIT_OFILE
|
|
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
|
|
|
|
/* Some systems have these, some do not. */
|
|
#ifdef RLIMIT_FSIZE
|
|
# define RLIMIT_FILESIZE RLIMIT_FSIZE
|
|
#else
|
|
# define RLIMIT_FILESIZE 256
|
|
#endif
|
|
|
|
#define RLIMIT_PIPESIZE 257
|
|
|
|
#ifdef RLIMIT_NOFILE
|
|
# define RLIMIT_OPENFILES RLIMIT_NOFILE
|
|
#else
|
|
# define RLIMIT_OPENFILES 258
|
|
#endif
|
|
|
|
#ifdef RLIMIT_VMEM
|
|
# define RLIMIT_VIRTMEM RLIMIT_VMEM
|
|
# define RLIMIT_VMBLKSZ 1024
|
|
#else
|
|
# ifdef RLIMIT_AS
|
|
# define RLIMIT_VIRTMEM RLIMIT_AS
|
|
# define RLIMIT_VMBLKSZ 1024
|
|
# else
|
|
# define RLIMIT_VIRTMEM 259
|
|
# define RLIMIT_VMBLKSZ 1
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NPROC
|
|
# define RLIMIT_MAXUPROC RLIMIT_NPROC
|
|
#else
|
|
# define RLIMIT_MAXUPROC 260
|
|
#endif
|
|
|
|
#if !defined (RLIM_INFINITY)
|
|
# define RLIM_INFINITY 0x7fffffff
|
|
#endif
|
|
|
|
#if !defined (RLIM_INVALID)
|
|
# define RLIM_INVALID (RLIMTYPE)-1
|
|
#endif
|
|
|
|
#define LIMIT_HARD 0x01
|
|
#define LIMIT_SOFT 0x02
|
|
|
|
static int ulimit_internal ();
|
|
static void printone ();
|
|
static void print_all_limits ();
|
|
|
|
static int get_limit ();
|
|
static int set_limit ();
|
|
|
|
static RLIMTYPE filesize ();
|
|
static RLIMTYPE pipesize ();
|
|
static RLIMTYPE getmaxuprc ();
|
|
static RLIMTYPE getmaxvm ();
|
|
|
|
typedef struct {
|
|
int option; /* The ulimit option for this limit. */
|
|
int parameter; /* Parameter to pass to get_limit (). */
|
|
int block_factor; /* Blocking factor for specific limit. */
|
|
char *description; /* Descriptive string to output. */
|
|
} RESOURCE_LIMITS;
|
|
|
|
static RESOURCE_LIMITS limits[] = {
|
|
#ifdef RLIMIT_CORE
|
|
{ 'c', RLIMIT_CORE, 1024, "core file size (blocks)" },
|
|
#endif
|
|
#ifdef RLIMIT_DATA
|
|
{ 'd', RLIMIT_DATA, 1024, "data seg size (kbytes)" },
|
|
#endif
|
|
{ 'f', RLIMIT_FILESIZE, 1024, "file size (blocks)" },
|
|
#ifdef RLIMIT_MEMLOCK
|
|
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory (kbytes)" },
|
|
#endif
|
|
#ifdef RLIMIT_RSS
|
|
{ 'm', RLIMIT_RSS, 1024, "max memory size (kbytes)" },
|
|
#endif /* RLIMIT_RSS */
|
|
{ 'n', RLIMIT_OPENFILES, 1, "open files" },
|
|
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size (512 bytes)" },
|
|
#ifdef RLIMIT_STACK
|
|
{ 's', RLIMIT_STACK, 1024, "stack size (kbytes)" },
|
|
#endif
|
|
#ifdef RLIMIT_CPU
|
|
{ 't', RLIMIT_CPU, 1, "cpu time (seconds)" },
|
|
#endif /* RLIMIT_CPU */
|
|
{ 'u', RLIMIT_MAXUPROC, 1, "max user processes" },
|
|
#if defined (HAVE_RESOURCE)
|
|
{ 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory (kbytes)" },
|
|
#endif
|
|
{ -1, -1, -1, (char *)NULL }
|
|
};
|
|
#define NCMDS (sizeof(limits) / sizeof(limits[0]))
|
|
|
|
typedef struct _cmd {
|
|
int cmd;
|
|
char *arg;
|
|
} ULCMD;
|
|
|
|
static ULCMD *cmdlist;
|
|
static int ncmd;
|
|
static int cmdlistsz;
|
|
|
|
#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
|
|
long
|
|
ulimit (cmd, newlim)
|
|
int cmd;
|
|
long newlim;
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
|
|
|
|
static int
|
|
_findlim (opt)
|
|
int opt;
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; limits[i].option > 0; i++)
|
|
if (limits[i].option == opt)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
static char optstring[4 + 2 * NCMDS];
|
|
|
|
/* Report or set limits associated with certain per-process resources.
|
|
See the help documentation in builtins.c for a full description. */
|
|
int
|
|
ulimit_builtin (list)
|
|
register WORD_LIST *list;
|
|
{
|
|
register char *s;
|
|
int c, limind, mode, opt, all_limits;
|
|
|
|
mode = 0;
|
|
|
|
all_limits = 0;
|
|
|
|
/* Idea stolen from pdksh -- build option string the first time called. */
|
|
if (optstring[0] == 0)
|
|
{
|
|
s = optstring;
|
|
*s++ = 'a'; *s++ = 'S'; *s++ = 'H';
|
|
for (c = 0; limits[c].option > 0; c++)
|
|
{
|
|
*s++ = limits[c].option;
|
|
*s++ = ';';
|
|
}
|
|
*s = '\0';
|
|
}
|
|
|
|
/* Initialize the command list. */
|
|
if (cmdlistsz == 0)
|
|
cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
|
|
ncmd = 0;
|
|
|
|
reset_internal_getopt ();
|
|
while ((opt = internal_getopt (list, optstring)) != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'a':
|
|
all_limits++;
|
|
break;
|
|
|
|
/* -S and -H are modifiers, not real options. */
|
|
case 'S':
|
|
mode |= LIMIT_SOFT;
|
|
break;
|
|
|
|
case 'H':
|
|
mode |= LIMIT_HARD;
|
|
break;
|
|
|
|
case '?':
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
|
|
default:
|
|
if (ncmd >= cmdlistsz)
|
|
cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
|
|
cmdlist[ncmd].cmd = opt;
|
|
cmdlist[ncmd++].arg = list_optarg;
|
|
break;
|
|
}
|
|
}
|
|
list = loptend;
|
|
|
|
if (all_limits)
|
|
{
|
|
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
/* default is `ulimit -f' */
|
|
if (ncmd == 0)
|
|
{
|
|
cmdlist[ncmd].cmd = 'f';
|
|
/* `ulimit something' is same as `ulimit -f something' */
|
|
cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
|
|
if (list)
|
|
list = list->next;
|
|
}
|
|
|
|
/* verify each command in the list. */
|
|
for (c = 0; c < ncmd; c++)
|
|
{
|
|
limind = _findlim (cmdlist[c].cmd);
|
|
if (limind == -1)
|
|
{
|
|
builtin_error ("bad command: `%c'", cmdlist[c].cmd);
|
|
return (EX_USAGE);
|
|
}
|
|
}
|
|
|
|
for (c = 0; c < ncmd; c++)
|
|
if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
|
|
return (EXECUTION_FAILURE);
|
|
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
static int
|
|
ulimit_internal (cmd, cmdarg, mode, multiple)
|
|
int cmd;
|
|
char *cmdarg;
|
|
int mode, multiple;
|
|
{
|
|
int opt, limind, setting;
|
|
long block_factor;
|
|
RLIMTYPE current_limit, real_limit, limit;
|
|
|
|
limit = RLIM_INVALID;
|
|
setting = cmdarg != 0;
|
|
limind = _findlim (cmd);
|
|
if (mode == 0)
|
|
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
|
|
opt = get_limit (limind, mode, ¤t_limit);
|
|
if (opt < 0)
|
|
{
|
|
builtin_error ("cannot get limit: %s", strerror (errno));
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
|
|
if (setting == 0) /* print the value of the specified limit */
|
|
{
|
|
printone (limind, current_limit, multiple);
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
/* Setting the limit. */
|
|
if (STREQ (cmdarg, "unlimited"))
|
|
limit = RLIM_INFINITY;
|
|
else if (all_digits (cmdarg))
|
|
limit = string_to_rlimtype (cmdarg);
|
|
else
|
|
{
|
|
builtin_error ("bad non-numeric arg `%s'", cmdarg);
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
|
|
block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor;
|
|
real_limit = limit * block_factor;
|
|
|
|
if (real_limit < 0 || (real_limit == 0 && limit != 0))
|
|
{
|
|
builtin_error ("limit out of range: %d", limit);
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
|
|
if (set_limit (limind, real_limit, mode) < 0)
|
|
{
|
|
builtin_error ("cannot modify limit: %s", strerror (errno));
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
static int
|
|
get_limit (ind, mode, limptr)
|
|
int ind, mode;
|
|
RLIMTYPE *limptr;
|
|
{
|
|
RLIMTYPE value;
|
|
#if defined (HAVE_RESOURCE)
|
|
struct rlimit limit;
|
|
#endif
|
|
|
|
if (limits[ind].parameter >= 256)
|
|
{
|
|
switch (limits[ind].parameter)
|
|
{
|
|
case RLIMIT_FILESIZE:
|
|
value = filesize ();
|
|
break;
|
|
case RLIMIT_PIPESIZE:
|
|
value = pipesize ();
|
|
break;
|
|
case RLIMIT_OPENFILES:
|
|
value = (RLIMTYPE)getdtablesize ();
|
|
break;
|
|
case RLIMIT_VIRTMEM:
|
|
value = getmaxvm (mode);
|
|
break;
|
|
case RLIMIT_MAXUPROC:
|
|
value = getmaxuprc (mode);
|
|
break;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
*limptr = value;
|
|
return ((value == RLIM_INVALID) ? -1 : 0);
|
|
}
|
|
else
|
|
{
|
|
#if defined (HAVE_RESOURCE)
|
|
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
|
return -1;
|
|
value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max;
|
|
*limptr = value;
|
|
return 0;
|
|
#else
|
|
errno = EINVAL;
|
|
return -1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static int
|
|
set_limit (ind, newlim, mode)
|
|
int ind;
|
|
RLIMTYPE newlim;
|
|
int mode;
|
|
{
|
|
#if defined (HAVE_RESOURCE)
|
|
struct rlimit limit;
|
|
RLIMTYPE val;
|
|
#endif
|
|
|
|
if (limits[ind].parameter >= 256)
|
|
switch (limits[ind].parameter)
|
|
{
|
|
case RLIMIT_FILESIZE:
|
|
#if !defined (HAVE_RESOURCE)
|
|
return (ulimit (2, newlim / 512L));
|
|
#else
|
|
errno = EINVAL;
|
|
return -1;
|
|
#endif
|
|
|
|
case RLIMIT_OPENFILES:
|
|
#if defined (HAVE_SETDTABLESIZE)
|
|
return (setdtablesize (newlim));
|
|
#endif
|
|
case RLIMIT_PIPESIZE:
|
|
case RLIMIT_VIRTMEM:
|
|
case RLIMIT_MAXUPROC:
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
#if defined (HAVE_RESOURCE)
|
|
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
|
return -1;
|
|
val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
|
|
(limit.rlim_cur <= limit.rlim_max))
|
|
? limit.rlim_max : newlim;
|
|
if (mode & LIMIT_SOFT)
|
|
limit.rlim_cur = val;
|
|
if (mode & LIMIT_HARD)
|
|
limit.rlim_max = val;
|
|
|
|
return (setrlimit (limits[ind].parameter, &limit));
|
|
#else
|
|
errno = EINVAL;
|
|
return -1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static RLIMTYPE
|
|
getmaxvm (mode)
|
|
int mode;
|
|
{
|
|
#if defined (HAVE_RESOURCE)
|
|
struct rlimit rl;
|
|
RLIMTYPE maxdata, maxstack;
|
|
|
|
if (getrlimit (RLIMIT_DATA, &rl) < 0)
|
|
return (RLIM_INVALID);
|
|
else
|
|
maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
|
|
|
|
if (getrlimit (RLIMIT_STACK, &rl) < 0)
|
|
return (RLIM_INVALID);
|
|
else
|
|
maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
|
|
|
|
/* Protect against overflow. */
|
|
return ((maxdata / 1024L) + (maxstack / 1024L));
|
|
#else
|
|
errno = EINVAL;
|
|
return RLIM_INVALID;
|
|
#endif /* HAVE_RESOURCE */
|
|
}
|
|
|
|
static RLIMTYPE
|
|
filesize()
|
|
{
|
|
#if !defined (HAVE_RESOURCE)
|
|
return ((RLIMTYPE)ulimit (1, 0L));
|
|
#else
|
|
errno = EINVAL;
|
|
return RLIM_INVALID;
|
|
#endif
|
|
}
|
|
|
|
static RLIMTYPE
|
|
pipesize ()
|
|
{
|
|
#if defined (PIPE_BUF)
|
|
/* This is defined on Posix systems. */
|
|
return ((RLIMTYPE) PIPE_BUF);
|
|
#else
|
|
# if defined (PIPESIZE)
|
|
/* This is defined by running a program from the Makefile. */
|
|
return ((RLIMTYPE) PIPESIZE);
|
|
# else
|
|
errno = EINVAL;
|
|
return RLIM_INVALID;
|
|
# endif /* PIPESIZE */
|
|
#endif /* PIPE_BUF */
|
|
}
|
|
|
|
static RLIMTYPE
|
|
getmaxuprc (mode)
|
|
int mode;
|
|
{
|
|
# if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
|
|
return ((RLIMTYPE)sysconf (_SC_CHILD_MAX));
|
|
# else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
|
|
# if defined (MAXUPRC)
|
|
return ((RLIMTYPE)MAXUPRC);
|
|
# else /* MAXUPRC */
|
|
errno = EINVAL;
|
|
return RLIM_INVALID;
|
|
# endif /* !MAXUPRC */
|
|
# endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
|
|
}
|
|
|
|
static void
|
|
print_all_limits (mode)
|
|
int mode;
|
|
{
|
|
register int i;
|
|
RLIMTYPE value;
|
|
|
|
if (mode == 0)
|
|
mode |= LIMIT_SOFT;
|
|
|
|
for (i = 0; limits[i].option > 0; i++)
|
|
{
|
|
if (get_limit (i, mode, &value) < 0)
|
|
value = RLIM_INVALID;
|
|
printone (i, value, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
printone (limind, curlim, pdesc)
|
|
int limind;
|
|
RLIMTYPE curlim;
|
|
int pdesc;
|
|
{
|
|
if (pdesc)
|
|
printf (DESCFMT, limits[limind].description);
|
|
if (curlim == RLIM_INFINITY)
|
|
puts ("unlimited");
|
|
else if (curlim == RLIM_INVALID)
|
|
printf ("cannot get limit: %s\n", strerror (errno));
|
|
else
|
|
print_rlimtype ((curlim / limits[limind].block_factor), 1);
|
|
}
|