commit bash-20141031 snapshot

This commit is contained in:
Chet Ramey
2014-11-03 14:32:12 -05:00
parent e0722a04ec
commit f3aad56dce
52 changed files with 55059 additions and 2492 deletions
+46
View File
@@ -223,6 +223,52 @@ sh_getopt_restore_state (argv)
nextchar = argv[sh_curopt] + sh_charindex;
}
sh_getopt_state_t *
sh_getopt_alloc_istate ()
{
sh_getopt_state_t *ret;
ret = (sh_getopt_state_t *)xmalloc (sizeof (sh_getopt_state_t));
return ret;
}
void
sh_getopt_dispose_istate (gs)
sh_getopt_state_t *gs;
{
free (gs);
}
sh_getopt_state_t *
sh_getopt_save_istate ()
{
sh_getopt_state_t *ret;
ret = sh_getopt_alloc_istate ();
ret->gs_optarg = sh_optarg;
ret->gs_optind = sh_optind;
ret->gs_curopt = sh_curopt;
ret->gs_nextchar = nextchar; /* XXX */
ret->gs_charindex = sh_charindex;
ret->gs_flags = 0; /* XXX for later use */
return ret;
}
void
sh_getopt_restore_istate (state)
sh_getopt_state_t *state;
{
sh_optarg = state->gs_optarg;
sh_optind = state->gs_optind;
sh_curopt = state->gs_curopt;
nextchar = state->gs_nextchar; /* XXX - probably not usable */
sh_charindex = state->gs_charindex;
sh_getopt_dispose_istate (state);
}
#if 0
void
sh_getopt_debug_restore_state (argv)
+339
View File
@@ -0,0 +1,339 @@
/* getopt.c - getopt for Bash. Used by the getopt builtin. */
/* Copyright (C) 1993-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "memalloc.h"
#include "../bashintl.h"
#include "../shell.h"
#include "getopt.h"
/* For communication from `sh_getopt' to the caller.
When `sh_getopt' finds an option that takes an argument,
the argument value is returned here. */
char *sh_optarg = 0;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `sh_getopt'.
On entry to `sh_getopt', zero means this is the first call; initialize.
When `sh_getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `sh_optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int sh_optind = 0;
/* Index of the current argument. */
static int sh_curopt;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
static int sh_charindex;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int sh_opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int sh_optopt = '?';
/* Set to 1 when we see an invalid option; public so getopts can reset it. */
int sh_badopt = 0;
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `sh_getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `sh_getopt' finds another option character, it returns that character,
updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `sh_getopt' returns `EOF'.
Then `sh_optind' is the index in ARGV of the first ARGV-element
that is not an option.
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `sh_opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `sh_optarg'. */
/* 1003.2 specifies the format of this message. */
#define BADOPT(x) fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], x)
#define NEEDARG(x) fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], x)
int
sh_getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
char c, *temp;
sh_optarg = 0;
if (sh_optind >= argc || sh_optind < 0) /* XXX was sh_optind > argc */
{
sh_optind = argc;
return (EOF);
}
/* Initialize the internal data when the first call is made.
Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (sh_optind == 0)
{
sh_optind = 1;
nextchar = (char *)NULL;
}
if (nextchar == 0 || *nextchar == '\0')
{
/* If we have done all the ARGV-elements, stop the scan. */
if (sh_optind >= argc)
return EOF;
temp = argv[sh_optind];
/* Special ARGV-element `--' means premature end of options.
Skip it like a null option, and return EOF. */
if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
{
sh_optind++;
return EOF;
}
/* If we have come to a non-option, either stop the scan or describe
it to the caller and pass it by. This makes the pseudo-option
`-' mean the end of options, but does not skip over it. */
if (temp[0] != '-' || temp[1] == '\0')
return EOF;
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = argv[sh_curopt = sh_optind] + 1;
sh_charindex = 1;
}
/* Look at and handle the next option-character. */
c = *nextchar++; sh_charindex++;
temp = strchr (optstring, c);
sh_optopt = c;
/* Increment `sh_optind' when we start to process its last character. */
if (nextchar == 0 || *nextchar == '\0')
{
sh_optind++;
nextchar = (char *)NULL;
}
if (sh_badopt = (temp == NULL || c == ':'))
{
if (sh_opterr)
BADOPT (c);
return '?';
}
if (temp[1] == ':')
{
if (nextchar && *nextchar)
{
/* This is an option that requires an argument. */
sh_optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
sh_optind++;
}
else if (sh_optind == argc)
{
if (sh_opterr)
NEEDARG (c);
sh_optopt = c;
sh_optarg = ""; /* Needed by getopts. */
c = (optstring[0] == ':') ? ':' : '?';
}
else
/* We already incremented `sh_optind' once;
increment it again when taking next ARGV-elt as argument. */
sh_optarg = argv[sh_optind++];
nextchar = (char *)NULL;
}
return c;
}
void
sh_getopt_restore_state (argv)
char **argv;
{
if (nextchar)
nextchar = argv[sh_curopt] + sh_charindex;
}
sh_getopt_state_t *
sh_getopt_save_istate ()
{
sh_getopt_state_t *ret;
ret = (sh_getopt_state_t *)xmalloc (sizeof (sh_getopt_state_t));
ret->gs_optarg = sh_optarg;
ret->gs_optind = sh_optind;
ret->gs_curopt = sh_curopt;
ret->gs_nextchar = nextchar; /* XXX */
ret->gs_charindex = sh_charindex;
ret->gs_flags = 0; /* XXX for later use */
return ret;
}
void
sh_getopt_restore_istate (state)
sh_getopt_state_t *state;
{
sh_optarg = state->gs_optarg;
sh_optind = state->gs_optind;
sh_curopt = state->gs_curopt;
nextchar = state->gs_nextchar; /* XXX - probably not usable */
sh_charindex = state->gs_charindex;
free (state);
}
#if 0
void
sh_getopt_debug_restore_state (argv)
char **argv;
{
if (nextchar && nextchar != argv[sh_curopt] + sh_charindex)
{
itrace("sh_getopt_debug_restore_state: resetting nextchar");
nextchar = argv[sh_curopt] + sh_charindex;
}
}
#endif
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `sh_getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_sh_optind = 0;
while (1)
{
int this_option_sh_optind = sh_optind ? sh_optind : 1;
c = sh_getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
printf ("digits occur in two different argv-elements.\n");
digit_sh_optind = this_option_sh_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", sh_optarg);
break;
case '?':
break;
default:
printf ("?? sh_getopt returned character code 0%o ??\n", c);
}
}
if (sh_optind < argc)
{
printf ("non-option ARGV-elements: ");
while (sh_optind < argc)
printf ("%s ", argv[sh_optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
+17
View File
@@ -60,6 +60,23 @@ extern int sh_optopt;
extern int sh_badopt;
extern int sh_getopt __P((int, char *const *, const char *));
typedef struct sh_getopt_state
{
char *gs_optarg;
int gs_optind;
int gs_curopt;
char *gs_nextchar;
int gs_charindex;
int gs_flags;
} sh_getopt_state_t;
extern void sh_getopt_restore_state __P((char **));
extern sh_getopt_state_t *sh_getopt_alloc_istate __P((void));
extern void sh_getopt_dispose_istate __P((sh_getopt_state_t *));
extern sh_getopt_state_t *sh_getopt_save_istate __P((void));
extern void sh_getopt_restore_istate __P((sh_getopt_state_t *));
#endif /* _SH_GETOPT_H */
+79
View File
@@ -0,0 +1,79 @@
/* getopt.h - declarations for getopt. */
/* Copyright (C) 1989, 1990, 1991, 1992, 1993, 2008,2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
/* XXX THIS HAS BEEN MODIFIED FOR INCORPORATION INTO BASH XXX */
#ifndef _SH_GETOPT_H
#define _SH_GETOPT_H 1
#include "stdc.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *sh_optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `sh_optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int sh_optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int sh_opterr;
/* Set to an option character which was unrecognized. */
extern int sh_optopt;
/* Set to 1 when an unrecognized option is encountered. */
extern int sh_badopt;
extern int sh_getopt __P((int, char *const *, const char *));
typedef struct sh_getopt_state
{
char *gs_optarg;
int gs_optind;
int gs_curopt;
char *gs_nextchar;
int gs_charindex;
int gs_flags;
} sh_getopt_state_t;
extern void sh_getopt_restore_state __P((char **));
extern sh_getopt_state_t *sh_getopt_save_istate __P((void));
extern void sh_getopt_restore_istate __P((sh_getopt_state_t *));
#endif /* _SH_GETOPT_H */
+332
View File
@@ -0,0 +1,332 @@
This file is getopts.def, from which is created getopts.c.
It implements the builtin "getopts" in Bash.
Copyright (C) 1987-2004 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES getopts.c
$BUILTIN getopts
$FUNCTION getopts_builtin
$SHORT_DOC getopts optstring name [arg]
Parse option arguments.
Getopts is used by shell procedures to parse positional parameters
as options.
OPTSTRING contains the option letters to be recognized; if a letter
is followed by a colon, the option is expected to have an argument,
which should be separated from it by white space.
Each time it is invoked, getopts will place the next option in the
shell variable $name, initializing name if it does not exist, and
the index of the next argument to be processed into the shell
variable OPTIND. OPTIND is initialized to 1 each time the shell or
a shell script is invoked. When an option requires an argument,
getopts places that argument into the shell variable OPTARG.
getopts reports errors in one of two ways. If the first character
of OPTSTRING is a colon, getopts uses silent error reporting. In
this mode, no error messages are printed. If an invalid option is
seen, getopts places the option character found into OPTARG. If a
required argument is not found, getopts places a ':' into NAME and
sets OPTARG to the option character found. If getopts is not in
silent mode, and an invalid option is seen, getopts places '?' into
NAME and unsets OPTARG. If a required argument is not found, a '?'
is placed in NAME, OPTARG is unset, and a diagnostic message is
printed.
If the shell variable OPTERR has the value 0, getopts disables the
printing of error messages, even if the first character of
OPTSTRING is not a colon. OPTERR has the value 1 by default.
Getopts normally parses the positional parameters ($0 - $9), but if
more arguments are given, they are parsed instead.
Exit Status:
Returns success if an option is found; fails if the end of options is
encountered or an error occurs.
$END
#include <config.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include "getopt.h"
#define G_EOF -1
#define G_INVALID_OPT -2
#define G_ARG_MISSING -3
extern char *this_command_name;
static int getopts_bind_variable __P((char *, char *));
static int dogetopts __P((int, char **));
/* getopts_reset is magic code for when OPTIND is reset. N is the
value that has just been assigned to OPTIND. */
void
getopts_reset (newind)
int newind;
{
itrace("getopts_reset: setting newind to %d", newind);
sh_optind = newind;
sh_badopt = 0;
}
static int
getopts_bind_variable (name, value)
char *name, *value;
{
SHELL_VAR *v;
if (legal_identifier (name))
{
v = bind_variable (name, value, 0);
if (v && (readonly_p (v) || noassign_p (v)))
return (EX_MISCERROR);
return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
else
{
sh_invalidid (name);
return (EXECUTION_FAILURE);
}
}
/* Error handling is now performed as specified by Posix.2, draft 11
(identical to that of ksh-88). The special handling is enabled if
the first character of the option string is a colon; this handling
disables diagnostic messages concerning missing option arguments
and invalid option characters. The handling is as follows.
INVALID OPTIONS:
name -> "?"
if (special_error) then
OPTARG = option character found
no error output
else
OPTARG unset
diagnostic message
fi
MISSING OPTION ARGUMENT;
if (special_error) then
name -> ":"
OPTARG = option character found
else
name -> "?"
OPTARG unset
diagnostic message
fi
*/
static int
dogetopts (argc, argv)
int argc;
char **argv;
{
int ret, special_error, old_opterr, i, n;
char strval[2], numval[16];
char *optstr; /* list of options */
char *name; /* variable to get flag val */
char *t;
if (argc < 3)
{
builtin_usage ();
return (EX_USAGE);
}
/* argv[0] is "getopts". */
optstr = argv[1];
name = argv[2];
argc -= 2;
argv += 2;
special_error = optstr[0] == ':';
if (special_error)
{
old_opterr = sh_opterr;
optstr++;
sh_opterr = 0; /* suppress diagnostic messages */
}
if (argc > 1)
{
sh_getopt_restore_state (argv);
t = argv[0];
argv[0] = dollar_vars[0];
ret = sh_getopt (argc, argv, optstr);
argv[0] = t;
}
else if (rest_of_args == (WORD_LIST *)NULL)
{
for (i = 0; i < 10 && dollar_vars[i]; i++)
;
sh_getopt_restore_state (dollar_vars);
ret = sh_getopt (i, dollar_vars, optstr);
}
else
{
register WORD_LIST *words;
char **v;
for (i = 0; i < 10 && dollar_vars[i]; i++)
;
for (words = rest_of_args; words; words = words->next, i++)
;
v = strvec_create (i + 1);
for (i = 0; i < 10 && dollar_vars[i]; i++)
v[i] = dollar_vars[i];
for (words = rest_of_args; words; words = words->next, i++)
v[i] = words->word->word;
v[i] = (char *)NULL;
sh_getopt_restore_state (v);
ret = sh_getopt (i, v, optstr);
free (v);
}
if (special_error)
sh_opterr = old_opterr;
/* Set the OPTIND variable in any case, to handle "--" skipping. It's
highly unlikely that 14 digits will be too few. */
if (sh_optind < 10)
{
numval[14] = sh_optind + '0';
numval[15] = '\0';
i = 14;
}
else
{
numval[i = 15] = '\0';
n = sh_optind;
do
{
numval[--i] = (n % 10) + '0';
}
while (n /= 10);
}
bind_variable ("OPTIND", numval + i, 0);
/* If an error occurred, decide which one it is and set the return
code appropriately. In all cases, the option character in error
is in OPTOPT. If an invalid option was encountered, OPTARG is
NULL. If a required option argument was missing, OPTARG points
to a NULL string (that is, sh_optarg[0] == 0). */
if (ret == '?')
{
if (sh_optarg == NULL)
ret = G_INVALID_OPT;
else if (sh_optarg[0] == '\0')
ret = G_ARG_MISSING;
}
if (ret == G_EOF)
{
unbind_variable ("OPTARG");
getopts_bind_variable (name, "?");
return (EXECUTION_FAILURE);
}
if (ret == G_INVALID_OPT)
{
/* Invalid option encountered. */
ret = getopts_bind_variable (name, "?");
if (special_error)
{
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
unbind_variable ("OPTARG");
return (ret);
}
if (ret == G_ARG_MISSING)
{
/* Required argument missing. */
if (special_error)
{
ret = getopts_bind_variable (name, ":");
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
{
ret = getopts_bind_variable (name, "?");
unbind_variable ("OPTARG");
}
return (ret);
}
bind_variable ("OPTARG", sh_optarg, 0);
strval[0] = (char) ret;
strval[1] = '\0';
return (getopts_bind_variable (name, strval));
}
/* The getopts builtin. Build an argv, and call dogetopts with it. */
int
getopts_builtin (list)
WORD_LIST *list;
{
char **av;
int ac, ret;
if (list == 0)
{
builtin_usage ();
return EX_USAGE;
}
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage ();
return (EX_USAGE);
}
list = loptend;
av = make_builtin_argv (list, &ac);
ret = dogetopts (ac, av);
free ((char *)av);
return (ret);
}
+15 -1
View File
@@ -23,7 +23,7 @@ $PRODUCES ulimit.c
$BUILTIN ulimit
$FUNCTION ulimit_builtin
$DEPENDS_ON !_MINIX
$SHORT_DOC ulimit [-SHabcdefilmnpqrstuvxT] [limit]
$SHORT_DOC ulimit [-SHabcdefiklmnpqrstuvxPT] [limit]
Modify shell resource limits.
Provides control over the resources available to the shell and processes
@@ -39,6 +39,7 @@ Options:
-e the maximum scheduling priority (`nice')
-f the maximum size of files written by the shell and its children
-i the maximum number of pending signals
-k the maximum number of kqueues allocated for this process
-l the maximum size a process may lock into memory
-m the maximum resident set size
-n the maximum number of open file descriptors
@@ -50,6 +51,7 @@ Options:
-u the maximum number of user processes
-v the size of virtual memory
-x the maximum number of file locks
-P the maximum number of pseudoterminals
-T the maximum number of threads
Not all options are available on all platforms.
@@ -131,11 +133,17 @@ extern int errno;
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
#endif
/* Alternate names */
/* 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 */
#if defined (HAVE_RESOURCE) && defined (RLIMIT_POSIXLOCKS) && !defined (RLIMIT_LOCKS)
# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
#endif /* HAVE_RESOURCE && RLIMIT_POSIXLOCKS && !RLIMIT_LOCKS */
/* Some systems have these, some do not. */
#ifdef RLIMIT_FSIZE
# define RLIMIT_FILESIZE RLIMIT_FSIZE
@@ -223,6 +231,9 @@ typedef struct {
} RESOURCE_LIMITS;
static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_NPTS
{ 'P', RLIMIT_NPTS, 1, "number of pseudoterminals", (char *)NULL },
#endif
#ifdef RLIMIT_PTHREAD
{ 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
#endif
@@ -242,6 +253,9 @@ static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_SIGPENDING
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
#endif
#ifdef RLIMIT_KQUEUES
{ 'k', RLIMIT_KQUEUES, 1, "max kqueues", (char *)NULL" },
#endif
#ifdef RLIMIT_MEMLOCK
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
#endif
+793
View File
@@ -0,0 +1,793 @@
This file is ulimit.def, from which is created ulimit.c.
It implements the builtin "ulimit" in Bash.
Copyright (C) 1987-2010 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES ulimit.c
$BUILTIN ulimit
$FUNCTION ulimit_builtin
$DEPENDS_ON !_MINIX
$SHORT_DOC ulimit [-SHabcdefilmnpqrstuvxT] [limit]
Modify shell resource limits.
Provides control over the resources available to the shell and processes
it creates, on systems that allow such control.
Options:
-S use the `soft' resource limit
-H use the `hard' resource limit
-a all current limits are reported
-b the socket buffer size
-c the maximum size of core files created
-d the maximum size of a process's data segment
-e the maximum scheduling priority (`nice')
-f the maximum size of files written by the shell and its children
-i the maximum number of pending signals
-k the maximum number of kqueues allocated for this process
-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
-q the maximum number of bytes in POSIX message queues
-r the maximum real-time scheduling priority
-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
-x the maximum number of file locks
-T the maximum number of threads
Not all options are available on all platforms.
If LIMIT is given, it is the new value of the specified resource; the
special LIMIT values `soft', `hard', and `unlimited' stand for the
current soft limit, the current hard limit, and no limit, respectively.
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.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#if !defined (_MINIX)
#include <config.h>
#include "../bashtypes.h"
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#include "../bashintl.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
#elif defined (HAVE_SYS_TIMES_H)
# 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 (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
# include <ulimit.h>
#endif
#if !defined (RLIMTYPE)
# define RLIMTYPE long
# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
#endif
/* Alternate names */
/* 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 */
#if defined (HAVE_RESOURCE) && defined (RLIMIT_POSIXLOCKS) && !defined (RLIMIT_LOCKS)
# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
#endif /* HAVE_RESOURCE && RLIMIT_POSIXLOCKS && !RLIMIT_LOCKS */
/* 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 (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR)
# define RLIMIT_PTHREAD RLIMIT_NTHR
#endif
#if !defined (RLIM_INFINITY)
# define RLIM_INFINITY 0x7fffffff
#endif
#if !defined (RLIM_SAVED_CUR)
# define RLIM_SAVED_CUR RLIM_INFINITY
#endif
#if !defined (RLIM_SAVED_MAX)
# define RLIM_SAVED_MAX RLIM_INFINITY
#endif
#define LIMIT_HARD 0x01
#define LIMIT_SOFT 0x02
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
otherwise. */
#define POSIXBLK -2
#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
extern int posixly_correct;
static int _findlim __P((int));
static int ulimit_internal __P((int, char *, int, int));
static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *));
static int set_limit __P((int, RLIMTYPE, int));
static void printone __P((int, RLIMTYPE, int));
static void print_all_limits __P((int));
static int set_all_limits __P((int, RLIMTYPE));
static int filesize __P((RLIMTYPE *));
static int pipesize __P((RLIMTYPE *));
static int getmaxuprc __P((RLIMTYPE *));
static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *));
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. */
const char * const description; /* Descriptive string to output. */
const char * const units; /* scale */
} RESOURCE_LIMITS;
static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_PTHREAD
{ 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
#endif
#ifdef RLIMIT_SBSIZE
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
#endif
#ifdef RLIMIT_CORE
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
#endif
#ifdef RLIMIT_DATA
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
#endif
#ifdef RLIMIT_NICE
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
#endif
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
#ifdef RLIMIT_SIGPENDING
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
#endif
#ifdef RLIMIT_KQUEUES
{ 'k', RLIMIT_KQUEUES, 1, "max kqueues", (char *)NULL" },
#endif
#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", (char *)NULL},
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
#ifdef RLIMIT_MSGQUEUE
{ 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
#endif
#ifdef RLIMIT_RTPRIO
{ 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
#endif
#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", (char *)NULL },
#if defined (HAVE_RESOURCE)
{ 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
#endif
#ifdef RLIMIT_SWAP
{ 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
#endif
#ifdef RLIMIT_LOCKS
{ 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
#endif
{ -1, -1, -1, (char *)NULL, (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)
{
#ifdef NOTYET
if (list) /* setting */
{
if (STREQ (list->word->word, "unlimited") == 0)
{
builtin_error (_("%s: invalid limit argument"), list->word->word);
return (EXECUTION_FAILURE);
}
return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
}
#endif
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
return (sh_chkwrite (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 (_("`%c': bad command"), 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;
int block_factor;
RLIMTYPE soft_limit, hard_limit, real_limit, limit;
setting = cmdarg != 0;
limind = _findlim (cmd);
if (mode == 0)
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
opt = get_limit (limind, &soft_limit, &hard_limit);
if (opt < 0)
{
builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
strerror (errno));
return (EXECUTION_FAILURE);
}
if (setting == 0) /* print the value of the specified limit */
{
printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
return (EXECUTION_SUCCESS);
}
/* Setting the limit. */
if (STREQ (cmdarg, "hard"))
real_limit = hard_limit;
else if (STREQ (cmdarg, "soft"))
real_limit = soft_limit;
else if (STREQ (cmdarg, "unlimited"))
real_limit = RLIM_INFINITY;
else if (all_digits (cmdarg))
{
limit = string_to_rlimtype (cmdarg);
block_factor = BLOCKSIZE(limits[limind].block_factor);
real_limit = limit * block_factor;
if ((real_limit / block_factor) != limit)
{
sh_erange (cmdarg, _("limit"));
return (EXECUTION_FAILURE);
}
}
else
{
sh_invalidnum (cmdarg);
return (EXECUTION_FAILURE);
}
if (set_limit (limind, real_limit, mode) < 0)
{
builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
strerror (errno));
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
static int
get_limit (ind, softlim, hardlim)
int ind;
RLIMTYPE *softlim, *hardlim;
{
RLIMTYPE value;
#if defined (HAVE_RESOURCE)
struct rlimit limit;
#endif
if (limits[ind].parameter >= 256)
{
switch (limits[ind].parameter)
{
case RLIMIT_FILESIZE:
if (filesize (&value) < 0)
return -1;
break;
case RLIMIT_PIPESIZE:
if (pipesize (&value) < 0)
return -1;
break;
case RLIMIT_OPENFILES:
value = (RLIMTYPE)getdtablesize ();
break;
case RLIMIT_VIRTMEM:
return (getmaxvm (softlim, hardlim));
case RLIMIT_MAXUPROC:
if (getmaxuprc (&value) < 0)
return -1;
break;
default:
errno = EINVAL;
return -1;
}
*softlim = *hardlim = value;
return (0);
}
else
{
#if defined (HAVE_RESOURCE)
if (getrlimit (limits[ind].parameter, &limit) < 0)
return -1;
*softlim = limit.rlim_cur;
*hardlim = limit.rlim_max;
# if defined (HPUX9)
if (limits[ind].parameter == RLIMIT_FILESIZE)
{
*softlim *= 512;
*hardlim *= 512; /* Ugh. */
}
else
# endif /* HPUX9 */
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)
# if defined (__CYGWIN__)
/* Grrr... Cygwin declares setdtablesize as void. */
setdtablesize (newlim);
return 0;
# else
return (setdtablesize (newlim));
# endif
#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;
# if defined (HPUX9)
if (limits[ind].parameter == RLIMIT_FILESIZE)
newlim /= 512; /* Ugh. */
# endif /* HPUX9 */
val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
(mode & LIMIT_HARD) == 0 && /* XXX -- test */
(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 int
getmaxvm (softlim, hardlim)
RLIMTYPE *softlim, *hardlim;
{
#if defined (HAVE_RESOURCE)
struct rlimit datalim, stacklim;
if (getrlimit (RLIMIT_DATA, &datalim) < 0)
return -1;
if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
return -1;
/* Protect against overflow. */
*softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
*hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
return 0;
#else
errno = EINVAL;
return -1;
#endif /* HAVE_RESOURCE */
}
static int
filesize(valuep)
RLIMTYPE *valuep;
{
#if !defined (HAVE_RESOURCE)
long result;
if ((result = ulimit (1, 0L)) < 0)
return -1;
else
*valuep = (RLIMTYPE) result * 512;
return 0;
#else
errno = EINVAL;
return -1;
#endif
}
static int
pipesize (valuep)
RLIMTYPE *valuep;
{
#if defined (PIPE_BUF)
/* This is defined on Posix systems. */
*valuep = (RLIMTYPE) PIPE_BUF;
return 0;
#else
# if defined (_POSIX_PIPE_BUF)
*valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
return 0;
# else
# if defined (PIPESIZE)
/* This is defined by running a program from the Makefile. */
*valuep = (RLIMTYPE) PIPESIZE;
return 0;
# else
errno = EINVAL;
return -1;
# endif /* PIPESIZE */
# endif /* _POSIX_PIPE_BUF */
#endif /* PIPE_BUF */
}
static int
getmaxuprc (valuep)
RLIMTYPE *valuep;
{
long maxchild;
maxchild = getmaxchild ();
if (maxchild < 0)
{
errno = EINVAL;
return -1;
}
else
{
*valuep = (RLIMTYPE) maxchild;
return 0;
}
}
static void
print_all_limits (mode)
int mode;
{
register int i;
RLIMTYPE softlim, hardlim;
if (mode == 0)
mode |= LIMIT_SOFT;
for (i = 0; limits[i].option > 0; i++)
{
if (get_limit (i, &softlim, &hardlim) == 0)
printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
else if (errno != EINVAL)
builtin_error ("%s: cannot get limit: %s", limits[i].description,
strerror (errno));
}
}
static void
printone (limind, curlim, pdesc)
int limind;
RLIMTYPE curlim;
int pdesc;
{
char unitstr[64];
int factor;
factor = BLOCKSIZE(limits[limind].block_factor);
if (pdesc)
{
if (limits[limind].units)
sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
else
sprintf (unitstr, "(-%c) ", limits[limind].option);
printf ("%-20s %16s", limits[limind].description, unitstr);
}
if (curlim == RLIM_INFINITY)
puts ("unlimited");
else if (curlim == RLIM_SAVED_MAX)
puts ("hard");
else if (curlim == RLIM_SAVED_CUR)
puts ("soft");
else
print_rlimtype ((curlim / factor), 1);
}
/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
causes all limits to be set as high as possible depending on mode (like
csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
were set successfully, and 1 if at least one limit could not be set.
To raise all soft limits to their corresponding hard limits, use
ulimit -S -a unlimited
To attempt to raise all hard limits to infinity (superuser-only), use
ulimit -H -a unlimited
To attempt to raise all soft and hard limits to infinity, use
ulimit -a unlimited
*/
static int
set_all_limits (mode, newlim)
int mode;
RLIMTYPE newlim;
{
register int i;
int retval = 0;
if (newlim != RLIM_INFINITY)
{
errno = EINVAL;
return -1;
}
if (mode == 0)
mode = LIMIT_SOFT|LIMIT_HARD;
for (retval = i = 0; limits[i].option > 0; i++)
if (set_limit (i, newlim, mode) < 0)
{
builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
strerror (errno));
retval = 1;
}
return retval;
}
#endif /* !_MINIX */