581 lines
13 KiB
Modula-2
581 lines
13 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
|
|
$SHORT_DOC ulimit [-SHacdmstfpn [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
|
|
-m the maximum resident set size
|
|
-s the maximum stack size
|
|
-t the maximum amount of cpu time in seconds
|
|
-f the maximum size of files created by the shell
|
|
-p the pipe buffer size
|
|
-n the maximum number of open file descriptors
|
|
|
|
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 1k
|
|
increments, except for -t, which is in seconds, and -p, which is in
|
|
increments of 512 bytes.
|
|
$END
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <errno.h>
|
|
#include "../shell.h"
|
|
#include "pipesize.h"
|
|
|
|
#if !defined (errno)
|
|
extern int errno;
|
|
#endif
|
|
|
|
#if defined (HAVE_RESOURCE)
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#else
|
|
#include <sys/times.h>
|
|
#endif
|
|
|
|
#if defined (_POSIX_VERSION)
|
|
#include <limits.h>
|
|
#endif
|
|
|
|
/* Check for the most basic synbols. If they aren't present, this
|
|
system's <sys/resource.h> isn't very useful to us. */
|
|
#if !defined RLIMIT_FSIZE
|
|
# undef HAVE_RESOURCE
|
|
#endif
|
|
|
|
/* **************************************************************** */
|
|
/* */
|
|
/* Ulimit builtin and Hacks. */
|
|
/* */
|
|
/* **************************************************************** */
|
|
|
|
/* Block size for ulimit operations. */
|
|
#define ULIMIT_BLOCK_SIZE ((long)1024)
|
|
|
|
#define u_FILE_SIZE 0x001
|
|
#define u_MAX_BREAK_VAL 0x002
|
|
#define u_PIPE_SIZE 0x004
|
|
#define u_CORE_FILE_SIZE 0x008
|
|
#define u_DATA_SEG_SIZE 0x010
|
|
#define u_PHYS_MEM_SIZE 0x020
|
|
#define u_CPU_TIME_LIMIT 0x040
|
|
#define u_STACK_SIZE 0x080
|
|
#define u_NUM_OPEN_FILES 0x100
|
|
|
|
#define u_ALL_LIMITS 0x7ff
|
|
|
|
#ifndef RLIM_INFINITY
|
|
# define RLIM_INFINITY 0x7fffffff
|
|
#endif
|
|
|
|
#define LIMIT_HARD 0x01
|
|
#define LIMIT_SOFT 0x02
|
|
|
|
static long shell_ulimit ();
|
|
static long pipesize ();
|
|
static int open_files ();
|
|
|
|
static void print_specific_limits ();
|
|
static void print_all_limits ();
|
|
|
|
static char t[2];
|
|
|
|
/* Report or set limits associated with certain per-process resources.
|
|
See the help documentation in builtins.c for a full description.
|
|
|
|
Rewritten by Chet Ramey 6/30/91. */
|
|
|
|
int
|
|
ulimit_builtin (list)
|
|
register WORD_LIST *list;
|
|
{
|
|
register char *s;
|
|
int c, setting, cmd, mode, verbose_print, opt_eof;
|
|
int all_limits, specific_limits;
|
|
long current_limit, real_limit, limit = -1L;
|
|
long block_factor;
|
|
|
|
c = mode = verbose_print = opt_eof = 0;
|
|
|
|
do
|
|
{
|
|
cmd = setting = all_limits = specific_limits = 0;
|
|
block_factor = ULIMIT_BLOCK_SIZE;
|
|
|
|
/* read_options: */
|
|
if (list && !opt_eof && *list->word->word == '-')
|
|
{
|
|
s = &(list->word->word[1]);
|
|
list = list->next;
|
|
|
|
while (*s && (c = *s++))
|
|
{
|
|
switch (c)
|
|
{
|
|
#define ADD_CMD(x) { if (cmd) specific_limits++; cmd |= (x); }
|
|
|
|
case '-': /* ulimit -- */
|
|
opt_eof++;
|
|
break;
|
|
|
|
case 'a':
|
|
all_limits++;
|
|
break;
|
|
|
|
case 'f':
|
|
ADD_CMD (u_FILE_SIZE);
|
|
break;
|
|
|
|
#if defined (HAVE_RESOURCE)
|
|
/* -S and -H are modifiers, not real options. */
|
|
case 'S':
|
|
mode |= LIMIT_SOFT;
|
|
break;
|
|
|
|
case 'H':
|
|
mode |= LIMIT_HARD;
|
|
break;
|
|
|
|
case 'c':
|
|
ADD_CMD (u_CORE_FILE_SIZE);
|
|
break;
|
|
|
|
case 'd':
|
|
ADD_CMD (u_DATA_SEG_SIZE);
|
|
break;
|
|
|
|
#if !defined (USGr4)
|
|
case 'm':
|
|
ADD_CMD (u_PHYS_MEM_SIZE);
|
|
break;
|
|
#endif /* USGr4 */
|
|
|
|
case 't':
|
|
ADD_CMD (u_CPU_TIME_LIMIT);
|
|
block_factor = 1; /* seconds */
|
|
break;
|
|
|
|
case 's':
|
|
ADD_CMD (u_STACK_SIZE);
|
|
break;
|
|
#endif /* HAVE_RESOURCE */
|
|
|
|
case 'p':
|
|
ADD_CMD (u_PIPE_SIZE);
|
|
block_factor = 512;
|
|
break;
|
|
|
|
case 'n':
|
|
ADD_CMD (u_NUM_OPEN_FILES);
|
|
block_factor = 1;
|
|
break;
|
|
|
|
default: /* error_case: */
|
|
t[0] = c;
|
|
t[1] = '\0';
|
|
bad_option (t);
|
|
#if !defined (HAVE_RESOURCE)
|
|
builtin_error("usage: ulimit [-afnp] [new limit]");
|
|
#else
|
|
builtin_error("usage: ulimit [-SHacmdstfnp] [new limit]");
|
|
#endif
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (all_limits)
|
|
{
|
|
print_all_limits (mode);
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
if (specific_limits)
|
|
{
|
|
print_specific_limits (cmd, mode);
|
|
if (list)
|
|
verbose_print++;
|
|
continue;
|
|
}
|
|
|
|
if (cmd == 0)
|
|
cmd = u_FILE_SIZE;
|
|
|
|
/* If an argument was supplied for the command, then we want to
|
|
set the limit. Note that `ulimit something' means a command
|
|
of -f with argument `something'. */
|
|
if (list)
|
|
{
|
|
if (opt_eof || (*list->word->word != '-'))
|
|
{
|
|
s = list->word->word;
|
|
list = list->next;
|
|
if (sscanf (s, "%ld", &limit) != 1)
|
|
{
|
|
if (strcmp (s, "unlimited") == 0)
|
|
limit = RLIM_INFINITY;
|
|
else
|
|
{
|
|
builtin_error ("bad non-numeric arg `%s'", s);
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
}
|
|
setting++;
|
|
}
|
|
else if (!opt_eof)
|
|
verbose_print++;
|
|
}
|
|
|
|
if (limit == RLIM_INFINITY)
|
|
block_factor = 1;
|
|
|
|
real_limit = limit * block_factor;
|
|
|
|
/* If more than one option is given, list each in a verbose format,
|
|
the same that is used for -a. */
|
|
if (!setting && verbose_print)
|
|
{
|
|
print_specific_limits (cmd, mode);
|
|
continue;
|
|
}
|
|
|
|
current_limit = shell_ulimit (cmd, real_limit, 0, mode);
|
|
|
|
if (setting)
|
|
{
|
|
#if !defined (HAVE_RESOURCE)
|
|
/* USG systems do not allow limits to be raised by any user
|
|
other than root. */
|
|
if ((current_limit < real_limit) && (getuid () != 0))
|
|
{
|
|
builtin_error ("cannot raise limit: %s", strerror (EPERM));
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
#endif /* !HAVE_RESOURCE */
|
|
|
|
if (shell_ulimit (cmd, real_limit, 1, mode) == -1)
|
|
{
|
|
builtin_error ("cannot raise limit: %s", strerror(errno));
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (current_limit != RLIM_INFINITY)
|
|
printf ("%ld\n", (current_limit / block_factor));
|
|
else
|
|
printf ("unlimited\n");
|
|
}
|
|
}
|
|
while (list);
|
|
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
/* The ulimit that we call from within Bash.
|
|
|
|
WHICH says which limit to twiddle; SETTING is non-zero if NEWLIM
|
|
contains the desired new limit. Otherwise, the existing limit is
|
|
returned. If mode & LIMIT_HARD, the hard limit is used; if
|
|
mode & LIMIT_SOFT, the soft limit. Both may be set by specifying
|
|
-H and -S; if both are specified, or if neither is specified, the
|
|
soft limit will be returned.
|
|
|
|
Systems without BSD resource limits can specify only u_FILE_SIZE.
|
|
This includes most USG systems.
|
|
|
|
Chet Ramey supplied the BSD resource limit code. */
|
|
|
|
static long
|
|
shell_ulimit (which, newlim, setting, mode)
|
|
int which, setting, mode;
|
|
long newlim;
|
|
{
|
|
#if defined (HAVE_RESOURCE)
|
|
struct rlimit limit;
|
|
int cmd;
|
|
|
|
if (mode == 0)
|
|
mode |= LIMIT_SOFT;
|
|
#endif
|
|
|
|
switch (which)
|
|
{
|
|
#if !defined (HAVE_RESOURCE)
|
|
|
|
case u_FILE_SIZE:
|
|
if (!setting)
|
|
{
|
|
/* ulimit () returns a number that is in 512 byte blocks, thus we
|
|
must multiply it by 512 to get back to bytes. This is false
|
|
only under HP/UX 6.x. */
|
|
long result;
|
|
|
|
result = ulimit (1, 0L);
|
|
|
|
# if defined (hpux) && !defined (_POSIX_VERSION)
|
|
return (result);
|
|
# else
|
|
return (result * 512);
|
|
# endif /* hpux 6.x */
|
|
}
|
|
else
|
|
return (ulimit (2, newlim / 512L));
|
|
|
|
break;
|
|
|
|
#else /* defined (HAVE_RESOURCE) */
|
|
|
|
case u_FILE_SIZE:
|
|
cmd = RLIMIT_FSIZE;
|
|
goto do_ulimit;
|
|
|
|
case u_CORE_FILE_SIZE:
|
|
cmd = RLIMIT_CORE;
|
|
goto do_ulimit;
|
|
|
|
case u_DATA_SEG_SIZE:
|
|
cmd = RLIMIT_DATA;
|
|
goto do_ulimit;
|
|
|
|
#if !defined (USGr4)
|
|
case u_PHYS_MEM_SIZE:
|
|
cmd = RLIMIT_RSS;
|
|
goto do_ulimit;
|
|
#endif /* USGr4 */
|
|
|
|
case u_CPU_TIME_LIMIT:
|
|
cmd = RLIMIT_CPU;
|
|
goto do_ulimit;
|
|
|
|
case u_STACK_SIZE:
|
|
cmd = RLIMIT_STACK;
|
|
|
|
do_ulimit:
|
|
|
|
if (getrlimit (cmd, &limit) != 0)
|
|
return ((long) -1);
|
|
|
|
if (!setting)
|
|
{
|
|
if (mode & LIMIT_SOFT)
|
|
return (limit.rlim_cur);
|
|
else
|
|
return (limit.rlim_max);
|
|
}
|
|
else
|
|
{
|
|
if (mode & LIMIT_SOFT)
|
|
limit.rlim_cur = newlim;
|
|
if (mode & LIMIT_HARD)
|
|
limit.rlim_max = newlim;
|
|
|
|
return (setrlimit (cmd, &limit));
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* HAVE_RESOURCE */
|
|
|
|
/* You can't get or set the pipe size with getrlimit, so we have to
|
|
cheat. */
|
|
case u_PIPE_SIZE:
|
|
if (setting)
|
|
{
|
|
errno = EINVAL;
|
|
return ((long) -1);
|
|
}
|
|
return (pipesize ());
|
|
|
|
case u_NUM_OPEN_FILES:
|
|
if (setting)
|
|
{
|
|
#if defined (HAVE_RESOURCE) && defined (RLIMIT_NOFILE)
|
|
cmd = RLIMIT_NOFILE;
|
|
goto do_ulimit;
|
|
#else
|
|
# if defined (HAVE_SETDTABLESIZE)
|
|
return (setdtablesize (newlim));
|
|
# else
|
|
errno = EINVAL;
|
|
return ((long) -1);
|
|
# endif /* HAVE_SETDTABLESIZE */
|
|
#endif /* !HAVE_RESOURCE || !RLIMIT_NOFILE */
|
|
}
|
|
else
|
|
return ((long) open_files (mode));
|
|
|
|
default:
|
|
errno = EINVAL;
|
|
return ((long) -1);
|
|
}
|
|
}
|
|
|
|
static int
|
|
open_files (mode)
|
|
int mode;
|
|
{
|
|
#if !defined (RLIMIT_NOFILE)
|
|
return (getdtablesize ());
|
|
#else
|
|
struct rlimit rl;
|
|
|
|
getrlimit (RLIMIT_NOFILE, &rl);
|
|
if (mode & LIMIT_SOFT)
|
|
return (rl.rlim_cur);
|
|
else
|
|
return (rl.rlim_max);
|
|
#endif
|
|
}
|
|
|
|
static long
|
|
pipesize ()
|
|
{
|
|
#if defined (PIPE_BUF)
|
|
/* This is defined on Posix systems. */
|
|
return ((long) PIPE_BUF);
|
|
#else
|
|
# if defined (PIPESIZE)
|
|
/* This is defined by running a program from the Makefile. */
|
|
return ((long) PIPESIZE);
|
|
# else
|
|
errno = EINVAL;
|
|
return ((long) -1);
|
|
# endif /* PIPESIZE */
|
|
#endif /* PIPE_BUF */
|
|
}
|
|
|
|
/* ulimit(2) returns information about file size limits in terms of 512-byte
|
|
blocks. This is the factor by which to divide to turn it into information
|
|
in terms of 1024-byte blocks. Except for hpux 6.x, which returns it in
|
|
terms of bytes. */
|
|
#if !defined (hpux) || defined (_POSIX_VERSION)
|
|
# define ULIMIT_DIVISOR 2
|
|
#else
|
|
# define ULIMIT_DIVISOR 1024
|
|
#endif
|
|
|
|
#if defined (HAVE_RESOURCE)
|
|
|
|
#if !defined (RLIM_NLIMITS)
|
|
# define RLIM_NLIMITS 6 /* Number of resource limits. */
|
|
#endif
|
|
|
|
typedef struct {
|
|
int option_cmd; /* The ulimit command for this limit. */
|
|
int parameter; /* Parameter to pass to getrlimit (). */
|
|
int block_factor; /* Blocking factor for specific limit. */
|
|
char *description; /* Descriptive string to output. */
|
|
} BSD_RESOURCE_LIMITS;
|
|
|
|
static BSD_RESOURCE_LIMITS limits[RLIM_NLIMITS + 1] = {
|
|
{ u_CORE_FILE_SIZE, RLIMIT_CORE, 1024, "core file size (blocks)" },
|
|
{ u_DATA_SEG_SIZE, RLIMIT_DATA, 1024, "data seg size (kbytes)" },
|
|
{ u_FILE_SIZE, RLIMIT_FSIZE, 1024, "file size (blocks)" },
|
|
#if !defined (USGr4)
|
|
{ u_PHYS_MEM_SIZE, RLIMIT_RSS, 1024, "max memory size (kbytes)" },
|
|
#endif /* USGr4 */
|
|
{ u_STACK_SIZE, RLIMIT_STACK, 1024, "stack size (kbytes)" },
|
|
{ u_CPU_TIME_LIMIT, RLIMIT_CPU, 1, "cpu time (seconds)" },
|
|
{ 0, 0, 0, (char *)NULL }
|
|
};
|
|
|
|
static void
|
|
print_bsd_limit (i, mode)
|
|
int i, mode;
|
|
{
|
|
struct rlimit rl;
|
|
long limit;
|
|
|
|
getrlimit (limits[i].parameter, &rl);
|
|
if (mode & LIMIT_HARD)
|
|
limit = rl.rlim_max;
|
|
else
|
|
limit = rl.rlim_cur;
|
|
printf ("%-25s", limits[i].description);
|
|
if (limit == RLIM_INFINITY)
|
|
printf ("unlimited\n");
|
|
else
|
|
printf ("%ld\n", limit / limits[i].block_factor);
|
|
}
|
|
|
|
static void
|
|
print_specific_bsd_limits (cmd, mode)
|
|
int cmd, mode;
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; limits[i].option_cmd; i++)
|
|
if (cmd & limits[i].option_cmd)
|
|
print_bsd_limit (i, mode);
|
|
}
|
|
#endif /* HAVE_RESOURCE */
|
|
|
|
/* Print the limits corresponding to a specific set of resources. This is
|
|
called when an option string contains more than one character (e.g. -at),
|
|
because limits may not be specified with that kind of argument. */
|
|
static void
|
|
print_specific_limits (cmd, mode)
|
|
int cmd, mode;
|
|
{
|
|
if (mode == 0)
|
|
mode |= LIMIT_SOFT;
|
|
|
|
#if defined (HAVE_RESOURCE)
|
|
print_specific_bsd_limits (cmd, mode);
|
|
#else
|
|
if (cmd & u_FILE_SIZE)
|
|
printf ("%-25s%ld\n", "file size (blocks)", ulimit (1, 0L) / ULIMIT_DIVISOR);
|
|
#endif
|
|
|
|
if (cmd & u_PIPE_SIZE)
|
|
printf ("%-25s%ld\n", "pipe size (512 bytes)", (pipesize () / 512));
|
|
|
|
if (cmd & u_NUM_OPEN_FILES)
|
|
printf ("%-25s%ld\n", "open files", open_files (mode));
|
|
}
|
|
|
|
static void
|
|
print_all_limits (mode)
|
|
int mode;
|
|
{
|
|
if (mode == 0)
|
|
mode |= LIMIT_SOFT;
|
|
|
|
print_specific_limits (u_ALL_LIMITS, mode);
|
|
}
|