mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-15 16:10:50 +02:00
commit bash-20141031 snapshot
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user