commit bash-20120727 snapshot

This commit is contained in:
Chet Ramey
2012-08-13 11:57:32 -04:00
parent aaf6036e86
commit fd58d46e0d
65 changed files with 32048 additions and 102 deletions
+64
View File
@@ -14227,3 +14227,67 @@ bashline.c
before adding the dummy history entry to make sure the dummy entry
doesn't get added to previous incomplete command. Partial fix for
problem reported by Peng Yu <pengyu.ut@gmail.com>
7/24
----
configure.in
- interix: define RECYCLES_PIDS. Based on a report from Michael
Haubenwallner <michael.haubenwallner@salomon.at>
7/26
----
jobs.c
- make_child: call bgp_delete on the newly-created pid unconditionally.
Some systems reuse pids before cycling through an entire set of
CHILD_MAX/_SC_CHILD_MAX unique pids. This is no longer dependent
on RECYCLES_PIDS. Based on a report from Michael Haubenwallner
<michael.haubenwallner@salomon.at>
support/shobj-conf
- Mac OS X: drop MACOSX_DEPLOYMENT_TARGET=10.3 from the LDFLAGS. We
can finally kill Panther
7/28
----
subst.c
- command_substitute: make sure last_made_pid gets reset if make_child
fails
execute_cmd.c
- execute_command_internal: case cm_simple: decide whether or not to
wait_for a child if already_making_children is non-zero, indicates
that there is an unwaited-for child. More of fix for bug report
from Michael Haubenwallner <michael.haubenwallner@salomon.at>
jobs.c
- make_child: call delete_old_job (new_pid) unconditionally, don't
bother to check whether or not pid wrap occurred. Rest of fix for
bug report from Michael Haubenwallner
<michael.haubenwallner@salomon.at>
7/29
----
shell.c
- subshell_exit: new function, exits the shell (via call to sh_exit())
after calling any defined exit trap
externs.h
- subshell_exit: new extern declaration
execute_cmd.c
- execute_command_internal: make sure to call subshell_exit for
{} group commands executed asynchronously (&). Part of fix for
EXIT trap bug reported by Maarten Billemont <lhunath@lyndir.com>
sig.c
- reset_terminating_signals: make sure to set termsigs_initialized back
to 0, so a subsequent call to initialize_terminating_signals works
right. Rest of fix for bug reported by Maarten Billemont
<lhunath@lyndir.com>
{execute_cmd,general,jobs,mailcheck,mksyntax,test}.c
builtins/{cd,fc,pushd,ulimit}.def
lib/malloc/getpagesize.h
lib/sh/{clktck,fpurge,inet_aton,mailstat,oslib,pathcanon,pathphys,spell,strerror}.c
- make inclusion of <sys/param.h> dependent on HAVE_SYS_PARAM_H
consistently
+71
View File
@@ -14219,3 +14219,74 @@ doc/{bash.1,bashref.texi}
- add some text to the description of set -e clarifying its effect
on shell functions and shell function execution. Suggested by
Rainer Blome <rainer.blome@gmx.de>
bashline.c
- edit_and_execute_command: increment current_command_line_count before
adding partial line to command history (for command-oriented-history
because of rl_newline at beginning of function), then reset it to 0
before adding the dummy history entry to make sure the dummy entry
doesn't get added to previous incomplete command. Partial fix for
problem reported by Peng Yu <pengyu.ut@gmail.com>
7/24
----
configure.in
- interix: define RECYCLES_PIDS. Based on a report from Michael
Haubenwallner <michael.haubenwallner@salomon.at>
7/26
----
jobs.c
- make_child: call bgp_delete on the newly-created pid unconditionally.
Some systems reuse pids before cycling through an entire set of
CHILD_MAX/_SC_CHILD_MAX unique pids. This is no longer dependent
on RECYCLES_PIDS. Based on a report from Michael Haubenwallner
<michael.haubenwallner@salomon.at>
support/shobj-conf
- Mac OS X: drop MACOSX_DEPLOYMENT_TARGET=10.3 from the LDFLAGS. We
can finally kill Panther
7/28
----
subst.c
- command_substitute: make sure last_made_pid gets reset if make_child
fails
execute_cmd.c
- execute_command_internal: case cm_simple: decide whether or not to
wait_for a child if already_making_children is non-zero, indicates
that there is an unwaited-for child. More of fix for bug report
from Michael Haubenwallner <michael.haubenwallner@salomon.at>
jobs.c
- make_child: call delete_old_job (new_pid) unconditionally, don't
bother to check whether or not pid wrap occurred. Rest of fix for
bug report from Michael Haubenwallner
<michael.haubenwallner@salomon.at>
7/29
----
shell.c
- subshell_exit: new function, exits the shell (via call to sh_exit())
after calling any defined exit trap
externs.h
- subshell_exit: new extern declaration
execute_cmd.c
- execute_command_internal: make sure to call subshell_exit for
{} group commands executed asynchronously (&). Part of fix for
EXIT trap bug reported by Maarten Billemont <lhunath@lyndir.com>
sig.c
- reset_terminating_signals: make sure to set termsigs_initialized back
to 0, so a subsequent call to initialize_terminating_signals works
right. Rest of fix for bug reported by Maarten Billemont
<lhunath@lyndir.com>
{execute_cmd,general,jobs,mailcheck,mksyntax,test}.c
builtins/{cd,fc,pushd,ulimit}.def
lib/malloc/getpagesize.h
- make inclusion of <sys/param.h> dependent on HAVE_SYS_PARAM_H
consistently
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.sigs</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Binary file not shown.
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.sigstat</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
+3 -3
View File
@@ -1,5 +1,5 @@
@%:@! /bin/sh
@%:@ From configure.in for Bash 4.2, version 4.048.
@%:@ From configure.in for Bash 4.2, version 4.050.
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.68 for bash 4.2-maint.
@%:@
@@ -9160,7 +9160,7 @@ fi
done
for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h \
for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h sys/param.h \
sys/resource.h sys/param.h sys/socket.h sys/stat.h \
sys/time.h sys/times.h sys/types.h sys/wait.h
do :
@@ -15760,7 +15760,7 @@ linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading
*qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s" LOCAL_LIBS="-lunix -lncurses" ;;
powerux*) LOCAL_LIBS="-lgen" ;;
cygwin*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE" ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE -DRECYCLES_PIDS" ;;
esac
case "${host_os}-${CC}" in
+53 -53
View File
@@ -15,55 +15,55 @@
'configure.in'
],
{
'_LT_AC_TAGCONFIG' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_INIT' => 1,
'_LT_AC_TAGCONFIG' => 1,
'm4_pattern_forbid' => 1,
'_AM_COND_IF' => 1,
'AC_INIT' => 1,
'AC_CANONICAL_TARGET' => 1,
'AC_SUBST' => 1,
'_AM_COND_IF' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_FC_SRCEXT' => 1,
'AC_SUBST' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_FC_SRCEXT' => 1,
'AC_PROG_LIBTOOL' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AM_PATH_GUILE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AM_PATH_GUILE' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AC_CONFIG_LINKS' => 1,
'm4_sinclude' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'LT_SUPPORTED_TAG' => 1,
'm4_sinclude' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_NLS' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
'_m4_warn' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
'AM_PROG_CXX_C_O' => 1,
'_AM_COND_ENDIF' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'_AM_COND_ENDIF' => 1,
'AM_ENABLE_MULTILIB' => 1,
'AM_SILENT_RULES' => 1,
'AM_PROG_MOC' => 1,
'AC_CONFIG_FILES' => 1,
'include' => 1,
'LT_INIT' => 1,
'AM_PROG_AR' => 1,
'include' => 1,
'AM_GNU_GETTEXT' => 1,
'AM_PROG_AR' => 1,
'AC_LIBSOURCE' => 1,
'AM_PROG_FC_C_O' => 1,
'AC_CANONICAL_BUILD' => 1,
'AM_PROG_FC_C_O' => 1,
'AC_FC_FREEFORM' => 1,
'AH_OUTPUT' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'sinclude' => 1,
'AM_PROG_CC_C_O' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'm4_pattern_allow' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_PROG_CC_C_O' => 1,
'sinclude' => 1,
'AM_CONDITIONAL' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AM_POT_TOOLS' => 1,
@@ -84,55 +84,55 @@
'configure.in'
],
{
'AM_PROG_F77_C_O' => 1,
'_LT_AC_TAGCONFIG' => 1,
'm4_pattern_forbid' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_INIT' => 1,
'AC_CANONICAL_TARGET' => 1,
'm4_pattern_forbid' => 1,
'_AM_COND_IF' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_CANONICAL_TARGET' => 1,
'AC_SUBST' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_FC_SRCEXT' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_PROG_LIBTOOL' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AM_PATH_GUILE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AC_CONFIG_LINKS' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'LT_SUPPORTED_TAG' => 1,
'AC_CONFIG_LINKS' => 1,
'm4_sinclude' => 1,
'LT_SUPPORTED_TAG' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_NLS' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'_m4_warn' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
'_m4_warn' => 1,
'AM_PROG_CXX_C_O' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'_AM_COND_ENDIF' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'AM_ENABLE_MULTILIB' => 1,
'AM_SILENT_RULES' => 1,
'AM_PROG_MOC' => 1,
'AC_CONFIG_FILES' => 1,
'LT_INIT' => 1,
'include' => 1,
'AM_GNU_GETTEXT' => 1,
'LT_INIT' => 1,
'AM_PROG_AR' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_LIBSOURCE' => 1,
'AC_CANONICAL_BUILD' => 1,
'AM_PROG_FC_C_O' => 1,
'AC_CANONICAL_BUILD' => 1,
'AC_FC_FREEFORM' => 1,
'AH_OUTPUT' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'm4_pattern_allow' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'sinclude' => 1,
'AM_CONDITIONAL' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_PROG_CC_C_O' => 1,
'm4_pattern_allow' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_CONDITIONAL' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AM_POT_TOOLS' => 1,
@@ -155,19 +155,19 @@
{
'm4_pattern_forbid' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_C_VOLATILE' => 1,
'AC_TYPE_OFF_T' => 1,
'AC_C_VOLATILE' => 1,
'AC_FUNC_CLOSEDIR_VOID' => 1,
'AC_REPLACE_FNMATCH' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_FUNC_STAT' => 1,
'AC_FUNC_WAIT3' => 1,
'AC_HEADER_TIME' => 1,
'AC_FUNC_LSTAT' => 1,
'AC_STRUCT_TM' => 1,
'AC_FUNC_WAIT3' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AC_FUNC_GETMNTENT' => 1,
'AC_STRUCT_TM' => 1,
'AC_FUNC_LSTAT' => 1,
'AC_TYPE_MODE_T' => 1,
'AC_FUNC_GETMNTENT' => 1,
'AC_FUNC_STRTOD' => 1,
'AC_CHECK_HEADERS' => 1,
'AC_FUNC_STRNLEN' => 1,
@@ -186,17 +186,17 @@
'AC_STRUCT_ST_BLOCKS' => 1,
'AC_TYPE_SIGNAL' => 1,
'AC_TYPE_UID_T' => 1,
'AC_PROG_MAKE_SET' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'm4_pattern_allow' => 1,
'AC_PROG_MAKE_SET' => 1,
'sinclude' => 1,
'm4_pattern_allow' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_FUNC_STRERROR_R' => 1,
'AC_PROG_CC' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AC_FUNC_FORK' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AC_FUNC_VPRINTF' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_PROG_YACC' => 1,
'AC_INIT' => 1,
'AC_STRUCT_TIMEZONE' => 1,
@@ -218,33 +218,33 @@
'AM_MAINTAINER_MODE' => 1,
'AC_FUNC_UTIME_NULL' => 1,
'AC_FUNC_SELECT_ARGTYPES' => 1,
'AC_HEADER_STAT' => 1,
'AC_FUNC_STRFTIME' => 1,
'AC_PROG_CPP' => 1,
'AC_HEADER_STAT' => 1,
'AC_C_INLINE' => 1,
'AC_PROG_LEX' => 1,
'AC_C_CONST' => 1,
'AC_PROG_CPP' => 1,
'AC_TYPE_PID_T' => 1,
'AC_C_CONST' => 1,
'AC_PROG_LEX' => 1,
'AC_CONFIG_FILES' => 1,
'include' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
'AC_PROG_INSTALL' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_CHECK_LIB' => 1,
'AC_FUNC_OBSTACK' => 1,
'AC_CHECK_LIB' => 1,
'AC_FUNC_MALLOC' => 1,
'AC_FUNC_GETGROUPS' => 1,
'AC_FUNC_GETLOADAVG' => 1,
'AH_OUTPUT' => 1,
'AC_FUNC_FSEEKO' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_FUNC_MKTIME' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_CONDITIONAL' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_FUNC_MKTIME' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_HEADER_SYS_WAIT' => 1,
'AC_PROG_LN_S' => 1,
'AC_FUNC_MEMCMP' => 1,
'AC_PROG_LN_S' => 1,
'm4_include' => 1,
'AC_HEADER_DIRENT' => 1,
'AC_CHECK_FUNCS' => 1
+2
View File
@@ -1228,6 +1228,8 @@ m4trace:configure.in:687: -1- AH_OUTPUT([HAVE_SYS_SELECT_H], [/* Define to 1 if
@%:@undef HAVE_SYS_SELECT_H])
m4trace:configure.in:687: -1- AH_OUTPUT([HAVE_SYS_FILE_H], [/* Define to 1 if you have the <sys/file.h> header file. */
@%:@undef HAVE_SYS_FILE_H])
m4trace:configure.in:687: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the <sys/param.h> header file. */
@%:@undef HAVE_SYS_PARAM_H])
m4trace:configure.in:687: -1- AH_OUTPUT([HAVE_SYS_RESOURCE_H], [/* Define to 1 if you have the <sys/resource.h> header file. */
@%:@undef HAVE_SYS_RESOURCE_H])
m4trace:configure.in:687: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the <sys/param.h> header file. */
+1 -1
View File
@@ -31,7 +31,7 @@ $PRODUCES cd.c
#include "../bashtypes.h"
#include "posixdir.h"
#include "posixstat.h"
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
+555
View File
@@ -0,0 +1,555 @@
This file is cd.def, from which is created cd.c. It implements the
builtins "cd" and "pwd" in Bash.
Copyright (C) 1987-2011 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 cd.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixdir.h"
#include "posixstat.h"
#ifndef _MINIX
#include <sys/param.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../flags.h"
#include "maxpath.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int posixly_correct;
extern int array_needs_making;
extern const char * const bash_getcwd_errstr;
static int bindpwd __P((int));
static int setpwd __P((char *));
static char *resetpwd __P((char *));
static int change_to_directory __P((char *, int));
/* Change this to 1 to get cd spelling correction by default. */
int cdspelling = 0;
int cdable_vars;
static int eflag; /* file scope so bindpwd() can see it */
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [-L|[-P [-e]]] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed: resolve symbolic links in
DIR after processing instances of `..'
-P use the physical directory structure without following symbolic
links: resolve symbolic links in DIR before processing instances
of `..'
-e if the -P option is supplied, and the current working directory
cannot be determined successfully, exit with a non-zero status
The default is to follow symbolic links, as if `-L' were specified.
`..' is processed by removing the immediately previous pathname component
back to a slash or the beginning of DIR.
Exit Status:
Returns 0 if the directory is changed, and if $PWD is set successfully when
-P is used; non-zero otherwise.
$END
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
static int
setpwd (dirname)
char *dirname;
{
int old_anm;
SHELL_VAR *tvar;
old_anm = array_needs_making;
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (tvar && readonly_p (tvar))
return EXECUTION_FAILURE;
if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
array_needs_making = 0;
}
return EXECUTION_SUCCESS;
}
static int
bindpwd (no_symlinks)
int no_symlinks;
{
char *dirname, *pwdvar;
int old_anm, r;
SHELL_VAR *tvar;
r = sh_chkwrite (EXECUTION_SUCCESS);
#define tcwd the_current_working_directory
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("cd");
#undef tcwd
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (tvar && readonly_p (tvar))
r = EXECUTION_FAILURE;
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
if (setpwd (dirname) == EXECUTION_FAILURE)
r = EXECUTION_FAILURE;
if (dirname == 0 && eflag)
r = EXECUTION_FAILURE;
if (dirname && dirname != the_current_working_directory)
free (dirname);
return (r);
}
/* Call get_working_directory to reset the value of
the_current_working_directory () */
static char *
resetpwd (caller)
char *caller;
{
char *tdir;
FREE (the_current_working_directory);
the_current_working_directory = (char *)NULL;
tdir = get_working_directory (caller);
return (tdir);
}
#define LCD_DOVARS 0x001
#define LCD_DOSPELL 0x002
#define LCD_PRINTPATH 0x004
#define LCD_FREEDIRNAME 0x008
/* This builtin is ultimately the way that all user-visible commands should
change the current working directory. It is called by cd_to_string (),
so the programming interface is simple, and it handles errors and
restrictions properly. */
int
cd_builtin (list)
WORD_LIST *list;
{
char *dirname, *cdpath, *path, *temp;
int path_index, no_symlinks, opt, lflag;
#if defined (RESTRICTED_SHELL)
if (restricted)
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif /* RESTRICTED_SHELL */
eflag = 0;
no_symlinks = no_symbolic_links;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
no_symlinks = 1;
break;
case 'L':
no_symlinks = 0;
break;
case 'e':
eflag = 1;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
lflag = (cdable_vars ? LCD_DOVARS : 0) |
((interactive && cdspelling) ? LCD_DOSPELL : 0);
if (eflag && no_symlinks == 0)
eflag = 0;
if (list == 0)
{
/* `cd' without arguments is equivalent to `cd $HOME' */
dirname = get_string_value ("HOME");
if (dirname == 0)
{
builtin_error (_("HOME not set"));
return (EXECUTION_FAILURE);
}
lflag = 0;
}
#if defined (CD_COMPLAINS)
else if (list->next)
{
builtin_error (_("too many arguments"));
return (EXECUTION_FAILURE);
}
#endif
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
{
/* This is `cd -', equivalent to `cd $OLDPWD' */
dirname = get_string_value ("OLDPWD");
if (dirname == 0)
{
builtin_error (_("OLDPWD not set"));
return (EXECUTION_FAILURE);
}
#if 0
lflag = interactive ? LCD_PRINTPATH : 0;
#else
lflag = LCD_PRINTPATH; /* According to SUSv3 */
#endif
}
else if (absolute_pathname (list->word->word))
dirname = list->word->word;
else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
{
dirname = list->word->word;
/* Find directory in $CDPATH. */
path_index = 0;
while (path = extract_colon_unit (cdpath, &path_index))
{
/* OPT is 1 if the path element is non-empty */
opt = path[0] != '\0';
temp = sh_makepath (path, dirname, MP_DOTILDE);
free (path);
if (change_to_directory (temp, no_symlinks))
{
/* POSIX.2 says that if a nonempty directory from CDPATH
is used to find the directory to change to, the new
directory name is echoed to stdout, whether or not
the shell is interactive. */
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
printf ("%s\n", path);
free (temp);
#if 0
/* Posix.2 says that after using CDPATH, the resultant
value of $PWD will not contain `.' or `..'. */
return (bindpwd (posixly_correct || no_symlinks));
#else
return (bindpwd (no_symlinks));
#endif
}
else
free (temp);
}
#if 0
/* changed for bash-4.2 Posix cd description steps 5-6 */
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
try the current directory, so we just punt now with an error
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
is so we don't mistakenly treat a CDPATH value of "" as not
specifying the current directory. */
if (posixly_correct && cdpath[0])
{
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
}
#endif
}
else
dirname = list->word->word;
/* When we get here, DIRNAME is the directory to change to. If we
chdir successfully, just return. */
if (change_to_directory (dirname, no_symlinks))
{
if (lflag & LCD_PRINTPATH)
printf ("%s\n", dirname);
return (bindpwd (no_symlinks));
}
/* If the user requests it, then perhaps this is the name of
a shell variable, whose value contains the directory to
change to. */
if (lflag & LCD_DOVARS)
{
temp = get_string_value (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
}
/* If the user requests it, try to find a directory name similar in
spelling to the one requested, in case the user made a simple
typo. This is similar to the UNIX 8th and 9th Edition shells. */
if (lflag & LCD_DOSPELL)
{
temp = dirspell (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
free (temp);
return (bindpwd (no_symlinks));
}
else
FREE (temp);
}
builtin_error ("%s: %s", dirname, strerror (errno));
return (EXECUTION_FAILURE);
}
$BUILTIN pwd
$FUNCTION pwd_builtin
$SHORT_DOC pwd [-LP]
Print the name of the current working directory.
Options:
-L print the value of $PWD if it names the current working
directory
-P print the physical directory, without any symbolic links
By default, `pwd' behaves as if `-L' were specified.
Exit Status:
Returns 0 unless an invalid option is given or the current directory
cannot be read.
$END
/* Non-zero means that pwd always prints the physical directory, without
symbolic links. */
static int verbatim_pwd;
/* Print the name of the current working directory. */
int
pwd_builtin (list)
WORD_LIST *list;
{
char *directory;
int opt, pflag;
verbatim_pwd = no_symbolic_links;
pflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
verbatim_pwd = pflag = 1;
break;
case 'L':
verbatim_pwd = 0;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
#define tcwd the_current_working_directory
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("pwd");
/* Try again using getcwd() if canonicalization fails (for instance, if
the file system has changed state underneath bash). */
if ((tcwd && directory == 0) ||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
{
if (directory && directory != tcwd)
free (directory);
directory = resetpwd ("pwd");
}
#undef tcwd
if (directory)
{
opt = EXECUTION_SUCCESS;
printf ("%s\n", directory);
/* This is dumb but posix-mandated. */
if (posixly_correct && pflag)
opt = setpwd (directory);
if (directory != the_current_working_directory)
free (directory);
return (sh_chkwrite (opt));
}
else
return (EXECUTION_FAILURE);
}
/* Do the work of changing to the directory NEWDIR. Handle symbolic
link following, etc. This function *must* return with
the_current_working_directory either set to NULL (in which case
getcwd() will eventually be called), or set to a string corresponding
to the working directory. Return 1 on success, 0 on failure. */
static int
change_to_directory (newdir, nolinks)
char *newdir;
int nolinks;
{
char *t, *tdir;
int err, canon_failed, r, ndlen, dlen;
tdir = (char *)NULL;
if (the_current_working_directory == 0)
{
t = get_working_directory ("chdir");
FREE (t);
}
t = make_absolute (newdir, the_current_working_directory);
/* TDIR is either the canonicalized absolute pathname of NEWDIR
(nolinks == 0) or the absolute physical pathname of NEWDIR
(nolinks != 0). */
tdir = nolinks ? sh_physpath (t, 0)
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
ndlen = strlen (newdir);
dlen = strlen (t);
/* Use the canonicalized version of NEWDIR, or, if canonicalization
failed, use the non-canonical form. */
canon_failed = 0;
if (tdir && *tdir)
free (t);
else
{
FREE (tdir);
tdir = t;
canon_failed = 1;
}
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
returns NULL (because it checks the path, it will return NULL if the
resolved path doesn't exist), fail immediately. */
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
{
#if defined ENAMETOOLONG
if (errno != ENOENT && errno != ENAMETOOLONG)
#else
if (errno != ENOENT)
#endif
errno = ENOTDIR;
free (tdir);
return (0);
}
/* If the chdir succeeds, update the_current_working_directory. */
if (chdir (nolinks ? newdir : tdir) == 0)
{
/* If canonicalization failed, but the chdir succeeded, reset the
shell's idea of the_current_working_directory. */
if (canon_failed)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
}
else
set_working_directory (tdir);
free (tdir);
return (1);
}
/* We failed to change to the appropriate directory name. If we tried
what the user passed (nolinks != 0), punt now. */
if (nolinks)
{
free (tdir);
return (0);
}
err = errno;
/* We're not in physical mode (nolinks == 0), but we failed to change to
the canonicalized directory name (TDIR). Try what the user passed
verbatim. If we succeed, reinitialize the_current_working_directory. */
if (chdir (newdir) == 0)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
r = 1;
}
else
{
errno = err;
r = 0;
}
free (tdir);
return r;
}
+1 -1
View File
@@ -52,7 +52,7 @@ $END
#include <config.h>
#if defined (HISTORY)
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include "../bashtypes.h"
+683
View File
@@ -0,0 +1,683 @@
This file is fc.def, from which is created fc.c.
It implements the builtin "fc" in Bash.
Copyright (C) 1987-2011 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 fc.c
$BUILTIN fc
$FUNCTION fc_builtin
$DEPENDS_ON HISTORY
$SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
fc is used to list or edit and re-execute commands from the history list.
FIRST and LAST can be numbers specifying the range, or FIRST can be a
string, which means the most recent command beginning with that
string.
Options:
-e ENAME select which editor to use. Default is FCEDIT, then EDITOR,
then vi
-l list lines instead of editing
-n omit line numbers when listing
-r reverse the order of the lines (newest listed first)
With the `fc -s [pat=rep ...] [command]' format, COMMAND is
re-executed after the substitution OLD=NEW is performed.
A useful alias to use with this is r='fc -s', so that typing `r cc'
runs the last command beginning with `cc' and typing `r' re-executes
the last command.
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
$END
#include <config.h>
#if defined (HISTORY)
#ifndef _MINIX
# include <sys/param.h>
#endif
#include "../bashtypes.h"
#include "posixstat.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <chartypes.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include "../shell.h"
#include "../builtins.h"
#include "../flags.h"
#include "../bashhist.h"
#include "maxpath.h"
#include <readline/history.h>
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int current_command_line_count;
extern int literal_history;
extern int posixly_correct;
extern int subshell_environment, interactive_shell;
extern int unlink __P((const char *));
extern FILE *sh_mktmpfp __P((char *, int, char **));
/* **************************************************************** */
/* */
/* The K*rn shell style fc command (Fix Command) */
/* */
/* **************************************************************** */
/* fc builtin command (fix command) for Bash for those who
like K*rn-style history better than csh-style.
fc [-e ename] [-nlr] [first] [last]
FIRST and LAST can be numbers specifying the range, or FIRST can be
a string, which means the most recent command beginning with that
string.
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
then the editor which corresponds to the current readline editing
mode, then vi.
-l means list lines instead of editing.
-n means no line numbers listed.
-r means reverse the order of the lines (making it newest listed first).
fc -e - [pat=rep ...] [command]
fc -s [pat=rep ...] [command]
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
*/
/* Data structure describing a list of global replacements to perform. */
typedef struct repl {
struct repl *next;
char *pat;
char *rep;
} REPL;
/* Accessors for HIST_ENTRY lists that are called HLIST. */
#define histline(i) (hlist[(i)]->line)
#define histdata(i) (hlist[(i)]->data)
#define FREE_RLIST() \
do { \
for (rl = rlist; rl; ) { \
REPL *r; \
r = rl->next; \
if (rl->pat) \
free (rl->pat); \
if (rl->rep) \
free (rl->rep); \
free (rl); \
rl = r; \
} \
} while (0)
static char *fc_dosubs __P((char *, REPL *));
static char *fc_gethist __P((char *, HIST_ENTRY **));
static int fc_gethnum __P((char *, HIST_ENTRY **));
static int fc_number __P((WORD_LIST *));
static void fc_replhist __P((char *));
#ifdef INCLUDE_UNUSED
static char *fc_readline __P((FILE *));
static void fc_addhist __P((char *));
#endif
/* String to execute on a file that we want to edit. */
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
#if defined (STRICT_POSIX)
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
#else
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
#endif
int
fc_builtin (list)
WORD_LIST *list;
{
register int i;
register char *sep;
int numbering, reverse, listing, execute;
int histbeg, histend, last_hist, retval, opt, rh;
FILE *stream;
REPL *rlist, *rl;
char *ename, *command, *newcom, *fcedit;
HIST_ENTRY **hlist;
char *fn;
numbering = 1;
reverse = listing = execute = 0;
ename = (char *)NULL;
/* Parse out the options and set which of the two forms we're in. */
reset_internal_getopt ();
lcurrent = list; /* XXX */
while (fc_number (loptend = lcurrent) == 0 &&
(opt = internal_getopt (list, ":e:lnrs")) != -1)
{
switch (opt)
{
case 'n':
numbering = 0;
break;
case 'l':
listing = 1;
break;
case 'r':
reverse = 1;
break;
case 's':
execute = 1;
break;
case 'e':
ename = list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (ename && (*ename == '-') && (ename[1] == '\0'))
execute = 1;
/* The "execute" form of the command (re-run, with possible string
substitutions). */
if (execute)
{
rlist = (REPL *)NULL;
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
{
*sep++ = '\0';
rl = (REPL *)xmalloc (sizeof (REPL));
rl->next = (REPL *)NULL;
rl->pat = savestring (list->word->word);
rl->rep = savestring (sep);
if (rlist == NULL)
rlist = rl;
else
{
rl->next = rlist;
rlist = rl;
}
list = list->next;
}
/* If we have a list of substitutions to do, then reverse it
to get the replacements in the proper order. */
rlist = REVERSE_LIST (rlist, REPL *);
hlist = history_list ();
/* If we still have something in list, it is a command spec.
Otherwise, we use the most recent command in time. */
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
if (command == NULL)
{
builtin_error (_("no command found"));
if (rlist)
FREE_RLIST ();
return (EXECUTION_FAILURE);
}
if (rlist)
{
newcom = fc_dosubs (command, rlist);
free (command);
FREE_RLIST ();
command = newcom;
}
fprintf (stderr, "%s\n", command);
fc_replhist (command); /* replace `fc -s' with command */
/* Posix says that the re-executed commands should be entered into the
history. */
return (parse_and_execute (command, "fc", SEVAL_NOHIST));
}
/* This is the second form of the command (the list-or-edit-and-rerun
form). */
hlist = history_list ();
if (hlist == 0)
return (EXECUTION_SUCCESS);
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. */
/* Even though command substitution through parse_and_execute turns off
remember_on_history, command substitution in a shell when set -o history
has been enabled (interactive or not) should use it in the last_hist
calculation as if it were on. */
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
last_hist = i - rh - hist_last_line_added;
/* XXX */
if (i == last_hist && hlist[last_hist] == 0)
while (last_hist >= 0 && hlist[last_hist] == 0)
last_hist--;
if (last_hist < 0)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
if (list)
{
histbeg = fc_gethnum (list->word->word, hlist);
list = list->next;
if (list)
histend = fc_gethnum (list->word->word, hlist);
else
histend = listing ? last_hist : histbeg;
}
else
{
/* The default for listing is the last 16 history items. */
if (listing)
{
histend = last_hist;
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
if (histbeg < 0)
histbeg = 0;
}
else
/* For editing, it is the last history command. */
histbeg = histend = last_hist;
}
/* "When not listing, the fc command that caused the editing shall not be
entered into the history list." */
if (listing == 0 && hist_last_line_added)
{
bash_delete_last_history ();
/* If we're editing a single command -- the last command in the
history -- and we just removed the dummy command added by
edit_and_execute_command (), we need to check whether or not we
just removed the last command in the history and need to back
the pointer up. remember_on_history is off because we're running
in parse_and_execute(). */
if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
last_hist = histbeg = --histend;
}
/* We print error messages for line specifications out of range. */
if ((histbeg < 0) || (histend < 0))
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
if (histend < histbeg)
{
i = histend;
histend = histbeg;
histbeg = i;
reverse = 1;
}
if (listing)
stream = stdout;
else
{
numbering = 0;
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
if (stream == 0)
{
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
FREE (fn);
return (EXECUTION_FAILURE);
}
}
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
{
QUIT;
if (numbering)
fprintf (stream, "%d", i + history_base);
if (listing)
{
if (posixly_correct)
fputs ("\t", stream);
else
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
}
fprintf (stream, "%s\n", histline (i));
}
if (listing)
return (sh_chkwrite (EXECUTION_SUCCESS));
fflush (stream);
if (ferror (stream))
{
sh_wrerror ();
fclose (stream);
return (EXECUTION_FAILURE);
}
fclose (stream);
/* Now edit the file of commands. */
if (ename)
{
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
sprintf (command, "%s %s", ename, fn);
}
else
{
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
sprintf (command, "%s %s", fcedit, fn);
}
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
if (retval != EXECUTION_SUCCESS)
{
unlink (fn);
free (fn);
return (EXECUTION_FAILURE);
}
/* Make sure parse_and_execute doesn't turn this off, even though a
call to parse_and_execute farther up the function call stack (e.g.,
if this is called by vi_edit_and_execute_command) may have already
called bash_history_disable. */
remember_on_history = 1;
/* Turn on the `v' flag while fc_execute_file runs so the commands
will be echoed as they are read by the parser. */
begin_unwind_frame ("fc builtin");
add_unwind_protect ((Function *)xfree, fn);
add_unwind_protect (unlink, fn);
unwind_protect_int (echo_input_at_read);
echo_input_at_read = 1;
retval = fc_execute_file (fn);
run_unwind_frame ("fc builtin");
return (retval);
}
/* Return 1 if LIST->word->word is a legal number for fc's use. */
static int
fc_number (list)
WORD_LIST *list;
{
char *s;
if (list == 0)
return 0;
s = list->word->word;
if (*s == '-')
s++;
return (legal_number (s, (intmax_t *)NULL));
}
/* Return an absolute index into HLIST which corresponds to COMMAND. If
COMMAND is a number, then it was specified in relative terms. If it
is a string, then it is the start of a command line present in HLIST. */
static int
fc_gethnum (command, hlist)
char *command;
HIST_ENTRY **hlist;
{
int sign, n, clen, rh;
register int i, j, last_hist;
register char *s;
sign = 1;
/* Count history elements. */
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. This needs to agree with the
calculation of last_hist in fc_builtin above. */
/* Even though command substitution through parse_and_execute turns off
remember_on_history, command substitution in a shell when set -o history
has been enabled (interactive or not) should use it in the last_hist
calculation as if it were on. */
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
last_hist = i - rh - hist_last_line_added;
if (i == last_hist && hlist[last_hist] == 0)
while (last_hist >= 0 && hlist[last_hist] == 0)
last_hist--;
if (last_hist < 0)
return (-1);
i = last_hist;
/* No specification defaults to most recent command. */
if (command == NULL)
return (i);
/* Otherwise, there is a specification. It can be a number relative to
the current position, or an absolute history number. */
s = command;
/* Handle possible leading minus sign. */
if (s && (*s == '-'))
{
sign = -1;
s++;
}
if (s && DIGIT(*s))
{
n = atoi (s);
n *= sign;
/* If the value is negative or zero, then it is an offset from
the current history item. */
if (n < 0)
{
n += i + 1;
return (n < 0 ? 0 : n);
}
else if (n == 0)
return (i);
else
{
n -= history_base;
return (i < n ? i : n);
}
}
clen = strlen (command);
for (j = i; j >= 0; j--)
{
if (STREQN (command, histline (j), clen))
return (j);
}
return (-1);
}
/* Locate the most recent history line which begins with
COMMAND in HLIST, and return a malloc()'ed copy of it. */
static char *
fc_gethist (command, hlist)
char *command;
HIST_ENTRY **hlist;
{
int i;
if (hlist == 0)
return ((char *)NULL);
i = fc_gethnum (command, hlist);
if (i >= 0)
return (savestring (histline (i)));
else
return ((char *)NULL);
}
#ifdef INCLUDE_UNUSED
/* Read the edited history lines from STREAM and return them
one at a time. This can read unlimited length lines. The
caller should free the storage. */
static char *
fc_readline (stream)
FILE *stream;
{
register int c;
int line_len = 0, lindex = 0;
char *line = (char *)NULL;
while ((c = getc (stream)) != EOF)
{
if ((lindex + 2) >= line_len)
line = (char *)xrealloc (line, (line_len += 128));
if (c == '\n')
{
line[lindex++] = '\n';
line[lindex++] = '\0';
return (line);
}
else
line[lindex++] = c;
}
if (!lindex)
{
if (line)
free (line);
return ((char *)NULL);
}
if (lindex + 2 >= line_len)
line = (char *)xrealloc (line, lindex + 3);
line[lindex++] = '\n'; /* Finish with newline if none in file */
line[lindex++] = '\0';
return (line);
}
#endif
/* Perform the SUBS on COMMAND.
SUBS is a list of substitutions, and COMMAND is a simple string.
Return a pointer to a malloc'ed string which contains the substituted
command. */
static char *
fc_dosubs (command, subs)
char *command;
REPL *subs;
{
register char *new, *t;
register REPL *r;
for (new = savestring (command), r = subs; r; r = r->next)
{
t = strsub (new, r->pat, r->rep, 1);
free (new);
new = t;
}
return (new);
}
/* Use `command' to replace the last entry in the history list, which,
by this time, is `fc blah...'. The intent is that the new command
become the history entry, and that `fc' should never appear in the
history list. This way you can do `r' to your heart's content. */
static void
fc_replhist (command)
char *command;
{
int n;
if (command == 0 || *command == '\0')
return;
n = strlen (command);
if (command[n - 1] == '\n')
command[n - 1] = '\0';
if (command && *command)
{
bash_delete_last_history ();
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
}
}
#ifdef INCLUDE_UNUSED
/* Add LINE to the history, after removing a single trailing newline. */
static void
fc_addhist (line)
char *line;
{
register int n;
if (line == 0 || *line == 0)
return;
n = strlen (line);
if (line[n - 1] == '\n')
line[n - 1] = '\0';
if (line && *line)
maybe_add_history (line); /* Obeys HISTCONTROL setting. */
}
#endif
#endif /* HISTORY */
+1 -1
View File
@@ -115,7 +115,7 @@ $END
#if defined (PUSHD_AND_POPD)
#include <stdio.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+778
View File
@@ -0,0 +1,778 @@
This file is pushd.def, from which is created pushd.c. It implements the
builtins "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987-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/>.
$PRODUCES pushd.c
$BUILTIN pushd
$FUNCTION pushd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC pushd [-n] [+N | -N | dir]
Add directories to stack.
Adds a directory to the top of the directory stack, or rotates
the stack, making the new top of the stack the current working
directory. With no arguments, exchanges the top two directories.
Options:
-n Suppresses the normal change of directory when adding
directories to the stack, so only the stack is manipulated.
Arguments:
+N Rotates the stack so that the Nth directory (counting
from the left of the list shown by `dirs', starting with
zero) is at the top.
-N Rotates the stack so that the Nth directory (counting
from the right of the list shown by `dirs', starting with
zero) is at the top.
dir Adds DIR to the directory stack at the top, making it the
new current working directory.
The `dirs' builtin displays the directory stack.
Exit Status:
Returns success unless an invalid argument is supplied or the directory
change fails.
$END
$BUILTIN popd
$FUNCTION popd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC popd [-n] [+N | -N]
Remove directories from stack.
Removes entries from the directory stack. With no arguments, removes
the top directory from the stack, and changes to the new top directory.
Options:
-n Suppresses the normal change of directory when removing
directories from the stack, so only the stack is manipulated.
Arguments:
+N Removes the Nth entry counting from the left of the list
shown by `dirs', starting with zero. For example: `popd +0'
removes the first directory, `popd +1' the second.
-N Removes the Nth entry counting from the right of the list
shown by `dirs', starting with zero. For example: `popd -0'
removes the last directory, `popd -1' the next to last.
The `dirs' builtin displays the directory stack.
Exit Status:
Returns success unless an invalid argument is supplied or the directory
change fails.
$END
$BUILTIN dirs
$FUNCTION dirs_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC dirs [-clpv] [+N] [-N]
Display directory stack.
Display the list of currently remembered directories. Directories
find their way onto the list with the `pushd' command; you can get
back up through the list with the `popd' command.
Options:
-c clear the directory stack by deleting all of the elements
-l do not print tilde-prefixed versions of directories relative
to your home directory
-p print the directory stack with one entry per line
-v print the directory stack with one entry per line prefixed
with its position in the stack
Arguments:
+N Displays the Nth entry counting from the left of the list shown by
dirs when invoked without options, starting with zero.
-N Displays the Nth entry counting from the right of the list shown by
dirs when invoked without options, starting with zero.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#include <config.h>
#if defined (PUSHD_AND_POPD)
#include <stdio.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "maxpath.h"
#include "common.h"
#include "builtext.h"
#ifdef LOADABLE_BUILTIN
# include "builtins.h"
#endif
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* The list of remembered directories. */
static char **pushd_directory_list = (char **)NULL;
/* Number of existing slots in this list. */
static int directory_list_size;
/* Offset to the end of the list. */
static int directory_list_offset;
static void pushd_error __P((int, char *));
static void clear_directory_stack __P((void));
static int cd_to_string __P((char *));
static int change_to_temp __P((char *));
static void add_dirstack_element __P((char *));
static int get_dirstack_index __P((intmax_t, int, int *));
#define NOCD 0x01
#define ROTATE 0x02
#define LONGFORM 0x04
#define CLEARSTAK 0x08
int
pushd_builtin (list)
WORD_LIST *list;
{
WORD_LIST *orig_list;
char *temp, *current_directory, *top;
int j, flags, skipopt;
intmax_t num;
char direction;
orig_list = list;
if (list && list->word && ISOPTION (list->word->word, '-'))
{
list = list->next;
skipopt = 1;
}
else
skipopt = 0;
/* If there is no argument list then switch current and
top of list. */
if (list == 0)
{
if (directory_list_offset == 0)
{
builtin_error (_("no other directory"));
return (EXECUTION_FAILURE);
}
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = directory_list_offset - 1;
temp = pushd_directory_list[j];
pushd_directory_list[j] = current_directory;
j = change_to_temp (temp);
free (temp);
return j;
}
for (flags = 0; skipopt == 0 && list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
/* Let `pushd -' work like it used to. */
break;
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &num) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
if (direction == '-')
num = directory_list_offset - num;
if (num > directory_list_offset || num < 0)
{
pushd_error (directory_list_offset, list->word->word);
return (EXECUTION_FAILURE);
}
flags |= ROTATE;
}
else if (*list->word->word == '-')
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (flags & ROTATE)
{
/* Rotate the stack num times. Remember, the current
directory acts like it is part of the stack. */
temp = get_working_directory ("pushd");
if (num == 0)
{
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
do
{
top = pushd_directory_list[directory_list_offset - 1];
for (j = directory_list_offset - 2; j > -1; j--)
pushd_directory_list[j + 1] = pushd_directory_list[j];
pushd_directory_list[j + 1] = temp;
temp = top;
num--;
}
while (num);
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
if (list == 0)
return (EXECUTION_SUCCESS);
/* Change to the directory in list->word->word. Save the current
directory on the top of the stack. */
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS;
if (j == EXECUTION_SUCCESS)
{
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
dirs_builtin ((WORD_LIST *)NULL);
if (flags & NOCD)
free (current_directory);
return (EXECUTION_SUCCESS);
}
else
{
free (current_directory);
return (EXECUTION_FAILURE);
}
}
/* Pop the directory stack, and then change to the new top of the stack.
If LIST is non-null it should consist of a word +N or -N, which says
what element to delete from the stack. The default is the top one. */
int
popd_builtin (list)
WORD_LIST *list;
{
register int i;
intmax_t which;
int flags;
char direction;
char *which_word;
which_word = (char *)NULL;
for (flags = 0, which = 0, direction = '+'; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &which) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
which_word = list->word->word;
}
else if (*list->word->word == '-')
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
/* Handle case of no specification, or top of stack specification. */
if ((direction == '+' && which == 0) ||
(direction == '-' && which == directory_list_offset))
{
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
: EXECUTION_SUCCESS;
if (i != EXECUTION_SUCCESS)
return (i);
free (pushd_directory_list[--directory_list_offset]);
}
else
{
/* Since an offset other than the top directory was specified,
remove that directory from the list and shift the remainder
of the list into place. */
i = (direction == '+') ? directory_list_offset - which : which;
free (pushd_directory_list[i]);
directory_list_offset--;
/* Shift the remainder of the list into place. */
for (; i < directory_list_offset; i++)
pushd_directory_list[i] = pushd_directory_list[i + 1];
}
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
/* Print the current list of directories on the directory stack. */
int
dirs_builtin (list)
WORD_LIST *list;
{
int flags, desired_index, index_flag, vflag;
intmax_t i;
char *temp, *w;
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
{
if (ISOPTION (list->word->word, 'l'))
{
flags |= LONGFORM;
}
else if (ISOPTION (list->word->word, 'c'))
{
flags |= CLEARSTAK;
}
else if (ISOPTION (list->word->word, 'v'))
{
vflag |= 2;
}
else if (ISOPTION (list->word->word, 'p'))
{
vflag |= 1;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (*list->word->word == '+' || *list->word->word == '-')
{
int sign;
if (legal_number (w = list->word->word + 1, &i) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
sign = (*list->word->word == '+') ? 1 : -1;
desired_index = get_dirstack_index (i, sign, &index_flag);
}
else
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
if (flags & CLEARSTAK)
{
clear_directory_stack ();
return (EXECUTION_SUCCESS);
}
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
{
pushd_error (directory_list_offset, w);
return (EXECUTION_FAILURE);
}
#define DIRSTACK_FORMAT(temp) \
(flags & LONGFORM) ? temp : polite_directory_format (temp)
/* The first directory printed is always the current working directory. */
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
{
temp = get_working_directory ("dirs");
if (temp == 0)
temp = savestring (_("<no current directory>"));
if (vflag & 2)
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
else
printf ("%s", DIRSTACK_FORMAT (temp));
free (temp);
if (index_flag)
{
putchar ('\n');
return (sh_chkwrite (EXECUTION_SUCCESS));
}
}
#define DIRSTACK_ENTRY(i) \
(flags & LONGFORM) ? pushd_directory_list[i] \
: polite_directory_format (pushd_directory_list[i])
/* Now print the requested directory stack entries. */
if (index_flag)
{
if (vflag & 2)
printf ("%2d %s", directory_list_offset - desired_index,
DIRSTACK_ENTRY (desired_index));
else
printf ("%s", DIRSTACK_ENTRY (desired_index));
}
else
for (i = directory_list_offset - 1; i >= 0; i--)
if (vflag >= 2)
printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
else
printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
putchar ('\n');
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static void
pushd_error (offset, arg)
int offset;
char *arg;
{
if (offset == 0)
builtin_error (_("directory stack empty"));
else
sh_erange (arg, _("directory stack index"));
}
static void
clear_directory_stack ()
{
register int i;
for (i = 0; i < directory_list_offset; i++)
free (pushd_directory_list[i]);
directory_list_offset = 0;
}
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
so if the result is EXECUTION_FAILURE then an error message has already
been printed. */
static int
cd_to_string (name)
char *name;
{
WORD_LIST *tlist;
WORD_LIST *dir;
int result;
dir = make_word_list (make_word (name), NULL);
tlist = make_word_list (make_word ("--"), dir);
result = cd_builtin (tlist);
dispose_words (tlist);
return (result);
}
static int
change_to_temp (temp)
char *temp;
{
int tt;
tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
if (tt == EXECUTION_SUCCESS)
dirs_builtin ((WORD_LIST *)NULL);
return (tt);
}
static void
add_dirstack_element (dir)
char *dir;
{
if (directory_list_offset == directory_list_size)
pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10);
pushd_directory_list[directory_list_offset++] = dir;
}
static int
get_dirstack_index (ind, sign, indexp)
intmax_t ind;
int sign, *indexp;
{
if (indexp)
*indexp = sign > 0 ? 1 : 2;
/* dirs +0 prints the current working directory. */
/* dirs -0 prints last element in directory stack */
if (ind == 0 && sign > 0)
return 0;
else if (ind == directory_list_offset)
{
if (indexp)
*indexp = sign > 0 ? 2 : 1;
return 0;
}
else if (ind >= 0 && ind <= directory_list_offset)
return (sign > 0 ? directory_list_offset - ind : ind);
else
return -1;
}
/* Used by the tilde expansion code. */
char *
get_dirstack_from_string (string)
char *string;
{
int ind, sign, index_flag;
intmax_t i;
sign = 1;
if (*string == '-' || *string == '+')
{
sign = (*string == '-') ? -1 : 1;
string++;
}
if (legal_number (string, &i) == 0)
return ((char *)NULL);
index_flag = 0;
ind = get_dirstack_index (i, sign, &index_flag);
if (index_flag && (ind < 0 || ind > directory_list_offset))
return ((char *)NULL);
if (index_flag == 0 || (index_flag == 1 && ind == 0))
return (get_string_value ("PWD"));
else
return (pushd_directory_list[ind]);
}
#ifdef INCLUDE_UNUSED
char *
get_dirstack_element (ind, sign)
intmax_t ind;
int sign;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
return (i < 0 || i > directory_list_offset) ? (char *)NULL
: pushd_directory_list[i];
}
#endif
void
set_dirstack_element (ind, sign, value)
intmax_t ind;
int sign;
char *value;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
if (ind == 0 || i < 0 || i > directory_list_offset)
return;
free (pushd_directory_list[i]);
pushd_directory_list[i] = savestring (value);
}
WORD_LIST *
get_directory_stack (flags)
int flags;
{
register int i;
WORD_LIST *ret;
char *d, *t;
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
{
d = (flags&1) ? polite_directory_format (pushd_directory_list[i])
: pushd_directory_list[i];
ret = make_word_list (make_word (d), ret);
}
/* Now the current directory. */
d = get_working_directory ("dirstack");
i = 0; /* sentinel to decide whether or not to free d */
if (d == 0)
d = ".";
else
{
t = polite_directory_format (d);
/* polite_directory_format sometimes returns its argument unchanged.
If it does not, we can free d right away. If it does, we need to
mark d to be deleted later. */
if (t != d)
{
free (d);
d = t;
}
else /* t == d, so d is what we want */
i = 1;
}
ret = make_word_list (make_word (d), ret);
if (i)
free (d);
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
}
#ifdef LOADABLE_BUILTIN
char * const dirs_doc[] = {
N_("Display the list of currently remembered directories. Directories\n\
find their way onto the list with the `pushd' command; you can get\n\
back up through the list with the `popd' command.\n\
\n\
Options:\n\
-c clear the directory stack by deleting all of the elements\n\
-l do not print tilde-prefixed versions of directories relative\n\
to your home directory\n\
-p print the directory stack with one entry per line\n\
-v print the directory stack with one entry per line prefixed\n\
with its position in the stack\n\
\n\
Arguments:\n\
+N Displays the Nth entry counting from the left of the list shown by\n\
dirs when invoked without options, starting with zero.\n\
\n\
-N Displays the Nth entry counting from the right of the list shown by\n\
dirs when invoked without options, starting with zero."),
(char *)NULL
};
char * const pushd_doc[] = {
N_("Adds a directory to the top of the directory stack, or rotates\n\
the stack, making the new top of the stack the current working\n\
directory. With no arguments, exchanges the top two directories.\n\
\n\
Options:\n\
-n Suppresses the normal change of directory when adding\n\
directories to the stack, so only the stack is manipulated.\n\
\n\
Arguments:\n\
+N Rotates the stack so that the Nth directory (counting\n\
from the left of the list shown by `dirs', starting with\n\
zero) is at the top.\n\
\n\
-N Rotates the stack so that the Nth directory (counting\n\
from the right of the list shown by `dirs', starting with\n\
zero) is at the top.\n\
\n\
dir Adds DIR to the directory stack at the top, making it the\n\
new current working directory.\n\
\n\
The `dirs' builtin displays the directory stack."),
(char *)NULL
};
char * const popd_doc[] = {
N_("Removes entries from the directory stack. With no arguments, removes\n\
the top directory from the stack, and changes to the new top directory.\n\
\n\
Options:\n\
-n Suppresses the normal change of directory when removing\n\
directories from the stack, so only the stack is manipulated.\n\
\n\
Arguments:\n\
+N Removes the Nth entry counting from the left of the list\n\
shown by `dirs', starting with zero. For example: `popd +0'\n\
removes the first directory, `popd +1' the second.\n\
\n\
-N Removes the Nth entry counting from the right of the list\n\
shown by `dirs', starting with zero. For example: `popd -0'\n\
removes the last directory, `popd -1' the next to last.\n\
\n\
The `dirs' builtin displays the directory stack."),
(char *)NULL
};
struct builtin pushd_struct = {
"pushd",
pushd_builtin,
BUILTIN_ENABLED,
pushd_doc,
"pushd [+N | -N] [-n] [dir]",
0
};
struct builtin popd_struct = {
"popd",
popd_builtin,
BUILTIN_ENABLED,
popd_doc,
"popd [+N | -N] [-n]",
0
};
struct builtin dirs_struct = {
"dirs",
dirs_builtin,
BUILTIN_ENABLED,
dirs_doc,
"dirs [-clpv] [+N] [-N]",
0
};
#endif /* LOADABLE_BUILTIN */
#endif /* PUSHD_AND_POPD */
+1 -1
View File
@@ -73,7 +73,7 @@ $END
#include <config.h>
#include "../bashtypes.h"
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+779
View File
@@ -0,0 +1,779 @@
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
-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"
#ifndef _MINIX
# 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
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
# define RLIMIT_NOFILE RLIMIT_OFILE
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
/* Some systems have these, some do not. */
#ifdef RLIMIT_FSIZE
# define RLIMIT_FILESIZE RLIMIT_FSIZE
#else
# define RLIMIT_FILESIZE 256
#endif
#define RLIMIT_PIPESIZE 257
#ifdef RLIMIT_NOFILE
# define RLIMIT_OPENFILES RLIMIT_NOFILE
#else
# define RLIMIT_OPENFILES 258
#endif
#ifdef RLIMIT_VMEM
# define RLIMIT_VIRTMEM RLIMIT_VMEM
# define RLIMIT_VMBLKSZ 1024
#else
# ifdef RLIMIT_AS
# define RLIMIT_VIRTMEM RLIMIT_AS
# define RLIMIT_VMBLKSZ 1024
# else
# define RLIMIT_VIRTMEM 259
# define RLIMIT_VMBLKSZ 1
# endif
#endif
#ifdef RLIMIT_NPROC
# define RLIMIT_MAXUPROC RLIMIT_NPROC
#else
# define RLIMIT_MAXUPROC 260
#endif
#if !defined (RLIM_INFINITY)
# define RLIM_INFINITY 0x7fffffff
#endif
#if !defined (RLIM_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_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 */
Vendored
+3 -3
View File
@@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in for Bash 4.2, version 4.048.
# From configure.in for Bash 4.2, version 4.050.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.68 for bash 4.2-maint.
#
@@ -9160,7 +9160,7 @@ fi
done
for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h \
for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h sys/param.h \
sys/resource.h sys/param.h sys/socket.h sys/stat.h \
sys/time.h sys/times.h sys/types.h sys/wait.h
do :
@@ -15760,7 +15760,7 @@ linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading
*qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s" LOCAL_LIBS="-lunix -lncurses" ;;
powerux*) LOCAL_LIBS="-lgen" ;;
cygwin*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE" ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE -DRECYCLES_PIDS" ;;
esac
case "${host_os}-${CC}" in
+2 -2
View File
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
AC_REVISION([for Bash 4.2, version 4.048])dnl
AC_REVISION([for Bash 4.2, version 4.049])dnl
define(bashvers, 4.2)
define(relstatus, maint)
@@ -1067,7 +1067,7 @@ linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading
*qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s" LOCAL_LIBS="-lunix -lncurses" ;;
powerux*) LOCAL_LIBS="-lgen" ;;
cygwin*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE" ;;
opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE -DRECYCLES_PIDS" ;;
esac
dnl Stanza for OS/compiler pair-specific flags
+979
View File
@@ -0,0 +1,979 @@
*** ../bash-4.2-patched/execute_cmd.c 2012-05-02 12:02:27.000000000 -0400
--- execute_cmd.c 2012-07-28 18:14:33.000000000 -0400
***************
*** 1,5 ****
/* execute_cmd.c -- Execute a COMMAND structure. */
! /* Copyright (C) 1987-2010 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
--- 1,5 ----
/* execute_cmd.c -- Execute a COMMAND structure. */
! /* Copyright (C) 1987-2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
***************
*** 119,122 ****
--- 119,124 ----
#endif
+ extern int job_control; /* XXX */
+
extern int close __P((int));
***************
*** 196,200 ****
static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *));
! static int execute_intern_function __P((WORD_DESC *, COMMAND *));
/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global
--- 198,202 ----
static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *));
! static int execute_intern_function __P((WORD_DESC *, FUNCTION_DEF *));
/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global
***************
*** 273,277 ****
static int showing_function_line;
! static int line_number_for_err_trap;
/* A sort of function nesting level counter */
--- 275,281 ----
static int showing_function_line;
! /* $LINENO ($BASH_LINENO) for use by an ERR trap. Global so parse_and_execute
! can save and restore it. */
! int line_number_for_err_trap;
/* A sort of function nesting level counter */
***************
*** 531,534 ****
--- 535,542 ----
volatile int last_pid;
volatile int save_line_number;
+ #if defined (PROCESS_SUBSTITUTION)
+ volatile int ofifo, nfifo, osize, saved_fifo;
+ volatile char *ofifo_list;
+ #endif
#if 0
***************
*** 593,597 ****
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
! unlink_fifo_list ();
#endif
/* If we are part of a pipeline, and not the end of the pipeline,
--- 601,606 ----
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
! if (variable_context == 0) /* wait until shell function completes */
! unlink_fifo_list ();
#endif
/* If we are part of a pipeline, and not the end of the pipeline,
***************
*** 670,673 ****
--- 679,693 ----
stdin_redir = stdin_redirects (command->redirects);
+ #if defined (PROCESS_SUBSTITUTION)
+ if (variable_context != 0)
+ {
+ ofifo = num_fifos ();
+ ofifo_list = copy_fifo_list (&osize);
+ saved_fifo = 1;
+ }
+ else
+ saved_fifo = 0;
+ #endif
+
/* Handle WHILE FOR CASE etc. with redirections. (Also '&' input
redirection.) */
***************
*** 677,680 ****
--- 697,704 ----
redirection_undo_list = (REDIRECT *)NULL;
dispose_exec_redirects ();
+ #if defined (PROCESS_SUBSTITUTION)
+ if (saved_fifo)
+ free (ofifo_list);
+ #endif
return (last_command_exit_value = EXECUTION_FAILURE);
}
***************
*** 752,758 ****
/* XXX - this is something to watch out for if there are problems
! when the shell is compiled without job control. */
! if (already_making_children && pipe_out == NO_PIPE &&
! last_made_pid != last_pid)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
--- 776,784 ----
/* XXX - this is something to watch out for if there are problems
! when the shell is compiled without job control. Don't worry about
! whether or not last_made_pid == last_pid; already_making_children
! tells us whether or not there are unwaited-for children to wait
! for and reap. */
! if (already_making_children && pipe_out == NO_PIPE)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
***************
*** 952,956 ****
case cm_function_def:
exec_result = execute_intern_function (command->value.Function_def->name,
! command->value.Function_def->command);
break;
--- 978,982 ----
case cm_function_def:
exec_result = execute_intern_function (command->value.Function_def->name,
! command->value.Function_def);
break;
***************
*** 971,974 ****
--- 997,1010 ----
discard_unwind_frame ("loop_redirections");
+ #if defined (PROCESS_SUBSTITUTION)
+ if (saved_fifo)
+ {
+ nfifo = num_fifos ();
+ if (nfifo > ofifo)
+ close_new_fifos (ofifo_list, osize);
+ free (ofifo_list);
+ }
+ #endif
+
/* Invert the return value if we have to */
if (invert)
***************
*** 1001,1004 ****
--- 1037,1041 ----
#endif
currently_executing_command = (COMMAND *)NULL;
+
return (last_command_exit_value);
}
***************
*** 1223,1227 ****
#endif
! posix_time = (command->flags & CMD_TIME_POSIX);
nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
--- 1260,1264 ----
#endif
! posix_time = command && (command->flags & CMD_TIME_POSIX);
nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
***************
*** 1505,1509 ****
return_code = return_catch_value;
else
! return_code = execute_command_internal (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
/* If we are asked to, invert the return value. */
--- 1542,1546 ----
return_code = return_catch_value;
else
! return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
/* If we are asked to, invert the return value. */
***************
*** 1549,1556 ****
static void cpl_reap __P((void));
static void cpl_flush __P((void));
static struct cpelement *cpl_search __P((pid_t));
! static struct cpelement *cpl_searchbyname __P((char *));
static void cpl_prune __P((void));
Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 };
--- 1586,1597 ----
static void cpl_reap __P((void));
static void cpl_flush __P((void));
+ static void cpl_closeall __P((void));
static struct cpelement *cpl_search __P((pid_t));
! static struct cpelement *cpl_searchbyname __P((const char *));
static void cpl_prune __P((void));
+ static void coproc_free __P((struct coproc *));
+
+ /* Will go away when there is fully-implemented support for multiple coprocs. */
Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 };
***************
*** 1639,1668 ****
cpl_reap ()
{
! struct cpelement *prev, *p;
! for (prev = p = coproc_list.head; p; prev = p, p = p->next)
! if (p->coproc->c_flags & COPROC_DEAD)
! {
! prev->next = p->next; /* remove from list */
!
! /* Housekeeping in the border cases. */
! if (p == coproc_list.head)
! coproc_list.head = coproc_list.head->next;
! else if (p == coproc_list.tail)
! coproc_list.tail = prev;
!
! coproc_list.ncoproc--;
! if (coproc_list.ncoproc == 0)
! coproc_list.head = coproc_list.tail = 0;
! else if (coproc_list.ncoproc == 1)
! coproc_list.tail = coproc_list.head; /* just to make sure */
#if defined (DEBUG)
! itrace("cpl_reap: deleting %d", p->coproc->c_pid);
#endif
! coproc_dispose (p->coproc);
! cpe_dispose (p);
! }
}
--- 1680,1722 ----
cpl_reap ()
{
! struct cpelement *p, *next, *nh, *nt;
! /* Build a new list by removing dead coprocs and fix up the coproc_list
! pointers when done. */
! nh = nt = next = (struct cpelement *)0;
! for (p = coproc_list.head; p; p = next)
! {
! next = p->next;
! if (p->coproc->c_flags & COPROC_DEAD)
! {
! coproc_list.ncoproc--; /* keep running count, fix up pointers later */
#if defined (DEBUG)
! itrace("cpl_reap: deleting %d", p->coproc->c_pid);
#endif
! coproc_dispose (p->coproc);
! cpe_dispose (p);
! }
! else if (nh == 0)
! nh = nt = p;
! else
! {
! nt->next = p;
! nt = nt->next;
! }
! }
!
! if (coproc_list.ncoproc == 0)
! coproc_list.head = coproc_list.tail = 0;
! else
! {
! if (nt)
! nt->next = 0;
! coproc_list.head = nh;
! coproc_list.tail = nt;
! if (coproc_list.ncoproc == 1)
! coproc_list.tail = coproc_list.head; /* just to make sure */
! }
}
***************
*** 1686,1689 ****
--- 1740,1762 ----
}
+ static void
+ cpl_closeall ()
+ {
+ struct cpelement *cpe;
+
+ for (cpe = coproc_list.head; cpe; cpe = cpe->next)
+ coproc_close (cpe->coproc);
+ }
+
+ static void
+ cpl_fdchk (fd)
+ int fd;
+ {
+ struct cpelement *cpe;
+
+ for (cpe = coproc_list.head; cpe; cpe = cpe->next)
+ coproc_checkfd (cpe->coproc, fd);
+ }
+
/* Search for PID in the list of coprocs; return the cpelement struct if
found. If not found, return NULL. */
***************
*** 1692,1700 ****
pid_t pid;
{
! struct cpelement *cp;
! for (cp = coproc_list.head ; cp; cp = cp->next)
! if (cp->coproc->c_pid == pid)
! return cp;
return (struct cpelement *)NULL;
}
--- 1765,1773 ----
pid_t pid;
{
! struct cpelement *cpe;
! for (cpe = coproc_list.head ; cpe; cpe = cpe->next)
! if (cpe->coproc->c_pid == pid)
! return cpe;
return (struct cpelement *)NULL;
}
***************
*** 1704,1708 ****
static struct cpelement *
cpl_searchbyname (name)
! char *name;
{
struct cpelement *cp;
--- 1777,1781 ----
static struct cpelement *
cpl_searchbyname (name)
! const char *name;
{
struct cpelement *cp;
***************
*** 1739,1743 ****
--- 1812,1823 ----
pid_t pid;
{
+ #if MULTIPLE_COPROCS
+ struct cpelement *p;
+
+ p = cpl_search (pid);
+ return (p ? p->coproc : 0);
+ #else
return (pid == sh_coproc.c_pid ? &sh_coproc : 0);
+ #endif
}
***************
*** 1746,1750 ****
--- 1826,1837 ----
const char *name;
{
+ #if MULTIPLE_COPROCS
+ struct cpelement *p;
+
+ p = cpl_searchbyname (name);
+ return (p ? p->coproc : 0);
+ #else
return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0);
+ #endif
}
***************
*** 1767,1771 ****
struct coproc *cp;
! cp = &sh_coproc; /* XXX */
coproc_init (cp);
--- 1854,1862 ----
struct coproc *cp;
! #if MULTIPLE_COPROCS
! cp = (struct coproc *)xmalloc (sizeof (struct coproc));
! #else
! cp = &sh_coproc;
! #endif
coproc_init (cp);
***************
*** 1773,1779 ****
--- 1864,1881 ----
cp->c_pid = pid;
+ #if MULTIPLE_COPROCS
+ cpl_add (cp);
+ #endif
+
return (cp);
}
+ static void
+ coproc_free (cp)
+ struct coproc *cp;
+ {
+ free (cp);
+ }
+
void
coproc_dispose (cp)
***************
*** 1786,1797 ****
FREE (cp->c_name);
coproc_close (cp);
coproc_init (cp);
}
! /* Placeholder for now. */
void
coproc_flush ()
{
coproc_dispose (&sh_coproc);
}
--- 1888,1907 ----
FREE (cp->c_name);
coproc_close (cp);
+ #if MULTIPLE_COPROCS
+ coproc_free (cp);
+ #else
coproc_init (cp);
+ #endif
}
! /* Placeholder for now. Will require changes for multiple coprocs */
void
coproc_flush ()
{
+ #if MULTIPLE_COPROCS
+ cpl_flush ();
+ #else
coproc_dispose (&sh_coproc);
+ #endif
}
***************
*** 1816,1820 ****
coproc_closeall ()
{
! coproc_close (&sh_coproc);
}
--- 1926,1934 ----
coproc_closeall ()
{
! #if MULTIPLE_COPROCS
! cpl_closeall ();
! #else
! coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */
! #endif
}
***************
*** 1822,1830 ****
coproc_reap ()
{
struct coproc *cp;
! cp = &sh_coproc;
if (cp && (cp->c_flags & COPROC_DEAD))
coproc_dispose (cp);
}
--- 1936,1948 ----
coproc_reap ()
{
+ #if MULTIPLE_COPROCS
+ cpl_reap ();
+ #else
struct coproc *cp;
! cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */
if (cp && (cp->c_flags & COPROC_DEAD))
coproc_dispose (cp);
+ #endif
}
***************
*** 1873,1877 ****
--- 1991,1999 ----
int fd;
{
+ #if MULTIPLE_COPROCS
+ cpl_fdchk (fd);
+ #else
coproc_checkfd (&sh_coproc, fd);
+ #endif
}
***************
*** 1908,1923 ****
struct coproc *cp;
cp = getcoprocbypid (pid);
- #if 0
- if (cp)
- itrace("coproc_pidchk: pid %d has died", pid);
#endif
if (cp)
{
cp->c_status = status;
cp->c_flags |= COPROC_DEAD;
cp->c_flags &= ~COPROC_RUNNING;
! #if 0
coproc_dispose (cp);
#endif
}
--- 2030,2053 ----
struct coproc *cp;
+ #if MULTIPLE_COPROCS
+ struct cpelement *cpe;
+
+ cpe = cpl_delete (pid);
+ cp = cpe ? cpe->coproc : 0;
+ #else
cp = getcoprocbypid (pid);
#endif
if (cp)
{
+ #if 0
+ itrace("coproc_pidchk: pid %d has died", pid);
+ #endif
cp->c_status = status;
cp->c_flags |= COPROC_DEAD;
cp->c_flags &= ~COPROC_RUNNING;
! #if MULTIPLE_COPROCS
coproc_dispose (cp);
+ #else
+ coproc_unsetvars (cp);
#endif
}
***************
*** 2015,2029 ****
char *tcmd;
! /* XXX -- will require changes to handle multiple coprocs */
if (sh_coproc.c_pid != NO_PID)
! {
! #if 0
! internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name);
! return (last_command_exit_value = EXECUTION_FAILURE);
! #else
! internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name);
! #endif
! }
coproc_init (&sh_coproc);
command_string_index = 0;
--- 2145,2154 ----
char *tcmd;
! /* XXX -- can be removed after changes to handle multiple coprocs */
! #if !MULTIPLE_COPROCS
if (sh_coproc.c_pid != NO_PID)
! internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name);
coproc_init (&sh_coproc);
+ #endif
command_string_index = 0;
***************
*** 2197,2202 ****
cmd->flags |= CMD_IGNORE_RETURN;
- #if defined (JOB_CONTROL)
lastpipe_flag = 0;
begin_unwind_frame ("lastpipe-exec");
lstdin = -1;
--- 2322,2327 ----
cmd->flags |= CMD_IGNORE_RETURN;
lastpipe_flag = 0;
+
begin_unwind_frame ("lastpipe-exec");
lstdin = -1;
***************
*** 2222,2233 ****
if (prev >= 0)
add_unwind_protect (close, prev);
- #endif
exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close);
- #if defined (JOB_CONTROL)
if (lstdin > 0)
restore_stdin (lstdin);
- #endif
if (prev >= 0)
--- 2347,2355 ----
***************
*** 2252,2258 ****
}
- #if defined (JOB_CONTROL)
discard_unwind_frame ("lastpipe-exec");
- #endif
return (exec_result);
--- 2374,2378 ----
***************
*** 2471,2479 ****
/* Save this command unless it's a trap command and we're not running
a debug trap. */
- #if 0
- if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
- #else
if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
- #endif
{
FREE (the_printed_command_except_trap);
--- 2591,2595 ----
***************
*** 2490,2494 ****
this_command_name = (char *)NULL;
! v = bind_variable (identifier, list->word->word, 0);
if (readonly_p (v) || noassign_p (v))
{
--- 2606,2617 ----
this_command_name = (char *)NULL;
! /* XXX - special ksh93 for command index variable handling */
! v = find_variable_last_nameref (identifier);
! if (v && nameref_p (v))
! {
! v = bind_variable_value (v, list->word->word, 0);
! }
! else
! v = bind_variable (identifier, list->word->word, 0);
if (readonly_p (v) || noassign_p (v))
{
***************
*** 2749,2752 ****
--- 2872,2877 ----
for (i = ind, l = list; l && --i; l = l->next)
;
+ if (l == 0) /* don't think this can happen */
+ return (0);
fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word);
return (displen (l->word->word));
***************
*** 2889,2893 ****
for (l = list; l && --reply; l = l->next)
;
! return (l->word->word);
}
}
--- 3014,3018 ----
for (l = list; l && --reply; l = l->next)
;
! return (l->word->word); /* XXX - can't be null? */
}
}
***************
*** 3330,3333 ****
--- 3455,3459 ----
static char * const nullstr = "";
+ /* XXX - can COND ever be NULL when this is called? */
static int
execute_cond_node (cond)
***************
*** 3379,3384 ****
{
rmatch = 0;
! patmatch = ((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
! (cond->op->word[0] == '!' || cond->op->word[0] == '=') ||
(cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
#if defined (COND_REGEXP)
--- 3505,3510 ----
{
rmatch = 0;
! patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
! (cond->op->word[0] == '!' || cond->op->word[0] == '=')) ||
(cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
#if defined (COND_REGEXP)
***************
*** 3581,3585 ****
WORD_LIST *words;
{
! WORD_LIST *w;
struct builtin *b;
int assoc, global;
--- 3707,3711 ----
WORD_LIST *words;
{
! WORD_LIST *w, *wcmd;
struct builtin *b;
int assoc, global;
***************
*** 3591,3594 ****
--- 3717,3721 ----
assoc = global = 0;
+ wcmd = words;
for (w = words; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
***************
*** 3596,3604 ****
if (b == 0)
{
! b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
! words->word->flags |= W_ASSNBLTIN;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
--- 3723,3738 ----
if (b == 0)
{
! /* Posix (post-2008) says that `command' doesn't change whether
! or not the builtin it shadows is a `declaration command', even
! though it removes other special builtin properties. In Posix
! mode, we skip over one or more instances of `command' and
! deal with the next word as the assignment builtin. */
! while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
! wcmd = wcmd->next;
! b = builtin_address_internal (wcmd->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
! wcmd->word->flags |= W_ASSNBLTIN;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
***************
*** 3620,3632 ****
if (b == 0)
{
! b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
! words->word->flags |= W_ASSNBLTIN;
}
! if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A'))
assoc = 1;
! if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g'))
global = 1;
}
--- 3754,3768 ----
if (b == 0)
{
! while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
! wcmd = wcmd->next;
! b = builtin_address_internal (wcmd->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
! wcmd->word->flags |= W_ASSNBLTIN;
}
! if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A'))
assoc = 1;
! if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g'))
global = 1;
}
***************
*** 3640,3645 ****
{
char *temp;
! temp = search_for_command (pathname);
! return (temp ? file_isdir (temp) : file_isdir (pathname));
}
--- 3776,3785 ----
{
char *temp;
! int ret;
!
! temp = search_for_command (pathname, 0);
! ret = (temp ? file_isdir (temp) : file_isdir (pathname));
! free (temp);
! return ret;
}
***************
*** 3665,3668 ****
--- 3805,3810 ----
command_line = (char *)0;
+ QUIT;
+
/* If we're in a function, update the line number information. */
if (variable_context && interactive_shell && sourcelevel == 0)
***************
*** 3981,3985 ****
if (command_line == 0)
! command_line = savestring (the_printed_command_except_trap);
#if defined (PROCESS_SUBSTITUTION)
--- 4123,4127 ----
if (command_line == 0)
! command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : "");
#if defined (PROCESS_SUBSTITUTION)
***************
*** 4042,4050 ****
char *error_trap;
- #if 0
- /* XXX -- added 12/11 */
- terminate_immediately++;
- #endif
-
error_trap = 0;
old_e_flag = exit_immediately_on_error;
--- 4184,4187 ----
***************
*** 4128,4136 ****
}
- #if 0
- /* XXX -- added 12/11 */
- terminate_immediately--;
- #endif
-
return (result);
}
--- 4265,4268 ----
***************
*** 4160,4164 ****
if (funcnest_max > 0 && funcnest >= funcnest_max)
{
! internal_error ("%s: maximum function nesting level exceeded (%d)", var->name, funcnest);
funcnest = 0; /* XXX - should we reset it somewhere else? */
jump_to_top_level (DISCARD);
--- 4292,4296 ----
if (funcnest_max > 0 && funcnest >= funcnest_max)
{
! internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest);
funcnest = 0; /* XXX - should we reset it somewhere else? */
jump_to_top_level (DISCARD);
***************
*** 4252,4260 ****
shell_fn = find_function_def (this_shell_function->name);
sfile = shell_fn ? shell_fn->source_file : "";
! array_push (funcname_a, this_shell_function->name);
! array_push (bash_source_a, sfile);
t = itos (executing_line_number ());
! array_push (bash_lineno_a, t);
free (t);
#endif
--- 4384,4392 ----
shell_fn = find_function_def (this_shell_function->name);
sfile = shell_fn ? shell_fn->source_file : "";
! array_push ((ARRAY *)funcname_a, this_shell_function->name);
! array_push ((ARRAY *)bash_source_a, sfile);
t = itos (executing_line_number ());
! array_push ((ARRAY *)bash_lineno_a, t);
free (t);
#endif
***************
*** 4331,4336 ****
/* These two variables cannot be unset, and cannot be affected by the
function. */
! array_pop (bash_source_a);
! array_pop (bash_lineno_a);
/* FUNCNAME can be unset, and so can potentially be changed by the
--- 4463,4468 ----
/* These two variables cannot be unset, and cannot be affected by the
function. */
! array_pop ((ARRAY *)bash_source_a);
! array_pop ((ARRAY *)bash_lineno_a);
/* FUNCNAME can be unset, and so can potentially be changed by the
***************
*** 4666,4670 ****
#endif /* RESTRICTED_SHELL */
! command = search_for_command (pathname);
if (command)
--- 4798,4802 ----
#endif /* RESTRICTED_SHELL */
! command = search_for_command (pathname, 1);
if (command)
***************
*** 4765,4768 ****
--- 4897,4902 ----
{
parent_return:
+ QUIT;
+
/* Make sure that the pipes are closed in the parent. */
close_pipes (pipe_in, pipe_out);
***************
*** 4993,4996 ****
--- 5127,5131 ----
#if defined (HAVE_HASH_BANG_EXEC)
READ_SAMPLE_BUF (command, sample, sample_len);
+ sample[sample_len - 1] = '\0';
if (sample_len > 2 && sample[0] == '#' && sample[1] == '!')
{
***************
*** 5045,5049 ****
if (check_binary_file (sample, sample_len))
{
! internal_error (_("%s: cannot execute binary file"), command);
return (EX_BINARY_FILE);
}
--- 5180,5184 ----
if (check_binary_file (sample, sample_len))
{
! internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i));
return (EX_BINARY_FILE);
}
***************
*** 5098,5104 ****
static int
! execute_intern_function (name, function)
WORD_DESC *name;
! COMMAND *function;
{
SHELL_VAR *var;
--- 5233,5239 ----
static int
! execute_intern_function (name, funcdef)
WORD_DESC *name;
! FUNCTION_DEF *funcdef;
{
SHELL_VAR *var;
***************
*** 5114,5117 ****
--- 5249,5260 ----
}
+ /* Posix interpretation 383 */
+ if (posixly_correct && find_special_builtin (name->word))
+ {
+ internal_error (_("`%s': is a special builtin"), name->word);
+ last_command_exit_value = EX_BADUSAGE;
+ jump_to_top_level (ERREXIT);
+ }
+
var = find_function (name->word);
if (var && (readonly_p (var) || noassign_p (var)))
***************
*** 5122,5126 ****
}
! bind_function (name->word, function);
return (EXECUTION_SUCCESS);
}
--- 5265,5273 ----
}
! #if defined (DEBUGGER)
! bind_function_def (name->word, funcdef);
! #endif
!
! bind_function (name->word, funcdef->command);
return (EXECUTION_SUCCESS);
}
+20 -11
View File
@@ -33,7 +33,7 @@
#include "filecntl.h"
#include "posixstat.h"
#include <signal.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
@@ -539,15 +539,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
volatile char *ofifo_list;
#endif
#if 0
if (command == 0 || breaking || continuing || read_but_dont_execute)
return (EXECUTION_SUCCESS);
#else
if (breaking || continuing)
return (last_command_exit_value);
if (command == 0 || read_but_dont_execute)
return (EXECUTION_SUCCESS);
#endif
QUIT;
run_pending_traps ();
@@ -586,6 +581,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
(pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous)))
{
pid_t paren_pid;
int s;
/* Fork a subshell, turn off the subshell bit, turn off job
control and call execute_command () on the command again. */
@@ -593,8 +589,19 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
paren_pid = make_child (savestring (make_command_string (command)),
asynchronous);
if (paren_pid == 0)
exit (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close));
/* NOTREACHED */
{
/* We want to run the exit trap for forced {} subshells, and we
want to note this before execute_in_subshell modifies the
COMMAND struct. Need to keep in mind that execute_in_subshell
runs the exit trap for () subshells itself. */
s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous;
last_command_exit_value = execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close);
if (s)
subshell_exit (last_command_exit_value);
else
exit (last_command_exit_value);
/* NOTREACHED */
}
else
{
close_pipes (pipe_in, pipe_out);
@@ -775,9 +782,11 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
the child. */
/* XXX - this is something to watch out for if there are problems
when the shell is compiled without job control. */
if (already_making_children && pipe_out == NO_PIPE &&
last_made_pid != last_pid)
when the shell is compiled without job control. Don't worry about
whether or not last_made_pid == last_pid; already_making_children
tells us whether or not there are unwaited-for children to wait
for and reap. */
if (already_making_children && pipe_out == NO_PIPE)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
+5354
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -78,6 +78,7 @@ extern void xtrace_print_cond_term __P((int, int, WORD_DESC *, char *, char *));
/* Functions from shell.c. */
extern void exit_shell __P((int)) __attribute__((__noreturn__));
extern void sh_exit __P((int)) __attribute__((__noreturn__));
extern void subshell_exit __P((int)) __attribute__((__noreturn__));
extern void disable_priv_mode __P((void));
extern void unbind_args __P((void));
+502
View File
@@ -0,0 +1,502 @@
/* externs.h -- extern function declarations which do not appear in their
own header file. */
/* Copyright (C) 1993-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/>.
*/
/* Make sure that this is included *after* config.h! */
#if !defined (_EXTERNS_H_)
# define _EXTERNS_H_
#include "stdc.h"
/* Functions from expr.c. */
extern intmax_t evalexp __P((char *, int *));
/* Functions from print_cmd.c. */
#define FUNC_MULTILINE 0x01
#define FUNC_EXTERNAL 0x02
extern char *make_command_string __P((COMMAND *));
extern char *named_function_string __P((char *, COMMAND *, int));
extern void print_command __P((COMMAND *));
extern void print_simple_command __P((SIMPLE_COM *));
extern void print_word_list __P((WORD_LIST *, char *));
/* debugger support */
extern void print_for_command_head __P((FOR_COM *));
#if defined (SELECT_COMMAND)
extern void print_select_command_head __P((SELECT_COM *));
#endif
extern void print_case_command_head __P((CASE_COM *));
#if defined (DPAREN_ARITHMETIC)
extern void print_arith_command __P((WORD_LIST *));
#endif
#if defined (COND_COMMAND)
extern void print_cond_command __P((COND_COM *));
#endif
/* set -x support */
extern void xtrace_init __P((void));
#ifdef NEED_XTRACE_SET_DECL
extern void xtrace_set __P((int, FILE *));
#endif
extern void xtrace_fdchk __P((int));
extern void xtrace_reset __P((void));
extern char *indirection_level_string __P((void));
extern void xtrace_print_assignment __P((char *, char *, int, int));
extern void xtrace_print_word_list __P((WORD_LIST *, int));
extern void xtrace_print_for_command_head __P((FOR_COM *));
#if defined (SELECT_COMMAND)
extern void xtrace_print_select_command_head __P((SELECT_COM *));
#endif
extern void xtrace_print_case_command_head __P((CASE_COM *));
#if defined (DPAREN_ARITHMETIC)
extern void xtrace_print_arith_cmd __P((WORD_LIST *));
#endif
#if defined (COND_COMMAND)
extern void xtrace_print_cond_term __P((int, int, WORD_DESC *, char *, char *));
#endif
/* Functions from shell.c. */
extern void exit_shell __P((int)) __attribute__((__noreturn__));
extern void sh_exit __P((int)) __attribute__((__noreturn__));
extern void disable_priv_mode __P((void));
extern void unbind_args __P((void));
#if defined (RESTRICTED_SHELL)
extern int shell_is_restricted __P((char *));
extern int maybe_make_restricted __P((char *));
#endif
extern void unset_bash_input __P((int));
extern void get_current_user_info __P((void));
/* Functions from eval.c. */
extern int reader_loop __P((void));
extern int parse_command __P((void));
extern int read_command __P((void));
/* Functions from braces.c. */
#if defined (BRACE_EXPANSION)
extern char **brace_expand __P((char *));
#endif
/* Miscellaneous functions from parse.y */
extern int yyparse __P((void));
extern int return_EOF __P((void));
extern char *xparse_dolparen __P((char *, char *, int *, int));
extern void reset_parser __P((void));
extern WORD_LIST *parse_string_to_word_list __P((char *, int, const char *));
extern int parser_in_command_position __P((void));
extern void free_pushed_string_input __P((void));
extern char *decode_prompt_string __P((char *));
extern int get_current_prompt_level __P((void));
extern void set_current_prompt_level __P((int));
#if defined (HISTORY)
extern char *history_delimiting_chars __P((const char *));
#endif
/* Declarations for functions defined in locale.c */
extern void set_default_locale __P((void));
extern void set_default_locale_vars __P((void));
extern int set_locale_var __P((char *, char *));
extern int set_lang __P((char *, char *));
extern void set_default_lang __P((void));
extern char *get_locale_var __P((char *));
extern char *localetrans __P((char *, int, int *));
extern char *mk_msgstr __P((char *, int *));
extern char *localeexpand __P((char *, int, int, int, int *));
/* Declarations for functions defined in list.c. */
extern void list_walk __P((GENERIC_LIST *, sh_glist_func_t *));
extern void wlist_walk __P((WORD_LIST *, sh_icpfunc_t *));
extern GENERIC_LIST *list_reverse ();
extern int list_length ();
extern GENERIC_LIST *list_append ();
extern GENERIC_LIST *list_remove ();
/* Declarations for functions defined in stringlib.c */
extern int find_string_in_alist __P((char *, STRING_INT_ALIST *, int));
extern char *find_token_in_alist __P((int, STRING_INT_ALIST *, int));
extern int find_index_in_alist __P((char *, STRING_INT_ALIST *, int));
extern char *substring __P((const char *, int, int));
extern char *strsub __P((char *, char *, char *, int));
extern char *strcreplace __P((char *, int, char *, int));
extern void strip_leading __P((char *));
extern void strip_trailing __P((char *, int, int));
extern void xbcopy __P((char *, char *, int));
/* Functions from version.c. */
extern char *shell_version_string __P((void));
extern void show_shell_version __P((int));
/* Functions from the bash library, lib/sh/libsh.a. These should really
go into a separate include file. */
/* declarations for functions defined in lib/sh/casemod.c */
extern char *sh_modcase __P((const char *, char *, int));
/* Defines for flags argument to sh_modcase. These need to agree with what's
in lib/sh/casemode.c */
#define CASE_LOWER 0x0001
#define CASE_UPPER 0x0002
#define CASE_CAPITALIZE 0x0004
#define CASE_UNCAP 0x0008
#define CASE_TOGGLE 0x0010
#define CASE_TOGGLEALL 0x0020
#define CASE_UPFIRST 0x0040
#define CASE_LOWFIRST 0x0080
#define CASE_USEWORDS 0x1000
/* declarations for functions defined in lib/sh/clktck.c */
extern long get_clk_tck __P((void));
/* declarations for functions defined in lib/sh/clock.c */
extern void clock_t_to_secs ();
extern void print_clock_t ();
/* Declarations for functions defined in lib/sh/dprintf.c */
#if !defined (HAVE_DPRINTF)
extern void dprintf __P((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
#endif
/* Declarations for functions defined in lib/sh/fmtulong.c */
#define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */
#define FL_ADDBASE 0x02 /* add base# prefix to converted value */
#define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */
#define FL_UNSIGNED 0x08 /* don't add any sign */
extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));
/* Declarations for functions defined in lib/sh/fmtulong.c */
#if defined (HAVE_LONG_LONG)
extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
#endif
/* Declarations for functions defined in lib/sh/fmtumax.c */
extern char *fmtumax __P((uintmax_t, int, char *, size_t, int));
/* Declarations for functions defined in lib/sh/fnxform.c */
extern char *fnx_fromfs __P((char *, size_t));
extern char *fnx_tofs __P((char *, size_t));
/* Declarations for functions defined in lib/sh/fpurge.c */
#if defined NEED_FPURGE_DECL
#if !HAVE_DECL_FPURGE
#if HAVE_FPURGE
# define fpurge _bash_fpurge
#endif
extern int fpurge __P((FILE *stream));
#endif /* HAVE_DECL_FPURGE */
#endif /* NEED_FPURGE_DECL */
/* Declarations for functions defined in lib/sh/getcwd.c */
#if !defined (HAVE_GETCWD)
extern char *getcwd __P((char *, size_t));
#endif
/* Declarations for functions defined in lib/sh/input_avail.c */
extern int input_avail __P((int));
/* Declarations for functions defined in lib/sh/itos.c */
extern char *inttostr __P((intmax_t, char *, size_t));
extern char *itos __P((intmax_t));
extern char *uinttostr __P((uintmax_t, char *, size_t));
extern char *uitos __P((uintmax_t));
/* declarations for functions defined in lib/sh/makepath.c */
#define MP_DOTILDE 0x01
#define MP_DOCWD 0x02
#define MP_RMDOT 0x04
#define MP_IGNDOT 0x08
extern char *sh_makepath __P((const char *, const char *, int));
/* declarations for functions defined in lib/sh/mbscasecmp.c */
#if !defined (HAVE_MBSCASECMP)
extern char *mbscasecmp __P((const char *, const char *));
#endif
/* declarations for functions defined in lib/sh/mbschr.c */
#if !defined (HAVE_MBSCHR)
extern char *mbschr __P((const char *, int));
#endif
/* declarations for functions defined in lib/sh/mbscmp.c */
#if !defined (HAVE_MBSCMP)
extern char *mbscmp __P((const char *, const char *));
#endif
/* declarations for functions defined in lib/sh/netconn.c */
extern int isnetconn __P((int));
/* declarations for functions defined in lib/sh/netopen.c */
extern int netopen __P((char *));
/* Declarations for functions defined in lib/sh/oslib.c */
#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN)
extern int dup2 __P((int, int));
#endif
#if !defined (HAVE_GETDTABLESIZE)
extern int getdtablesize __P((void));
#endif /* !HAVE_GETDTABLESIZE */
#if !defined (HAVE_GETHOSTNAME)
extern int gethostname __P((char *, int));
#endif /* !HAVE_GETHOSTNAME */
extern int getmaxgroups __P((void));
extern long getmaxchild __P((void));
/* declarations for functions defined in lib/sh/pathcanon.c */
#define PATH_CHECKDOTDOT 0x0001
#define PATH_CHECKEXISTS 0x0002
#define PATH_HARDPATH 0x0004
#define PATH_NOALLOC 0x0008
extern char *sh_canonpath __P((char *, int));
/* declarations for functions defined in lib/sh/pathphys.c */
extern char *sh_physpath __P((char *, int));
extern char *sh_realpath __P((const char *, char *));
/* declarations for functions defined in lib/sh/setlinebuf.c */
#ifdef NEED_SH_SETLINEBUF_DECL
extern int sh_setlinebuf __P((FILE *));
#endif
/* declarations for functions defined in lib/sh/shaccess.c */
extern int sh_eaccess __P((char *, int));
/* declarations for functions defined in lib/sh/shmatch.c */
extern int sh_regmatch __P((const char *, const char *, int));
/* defines for flags argument to sh_regmatch. */
#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */
#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */
/* declarations for functions defined in lib/sh/shmbchar.c */
extern size_t mbstrlen __P((const char *));
extern char *mbsmbchar __P((const char *));
extern int sh_mbsnlen __P((const char *, size_t, int));
/* declarations for functions defined in lib/sh/shquote.c */
extern char *sh_single_quote __P((const char *));
extern char *sh_double_quote __P((const char *));
extern char *sh_mkdoublequoted __P((const char *, int, int));
extern char *sh_un_double_quote __P((char *));
extern char *sh_backslash_quote __P((char *, const char *, int));
extern char *sh_backslash_quote_for_double_quotes __P((char *));
extern int sh_contains_shell_metas __P((char *));
/* declarations for functions defined in lib/sh/spell.c */
extern int spname __P((char *, char *));
extern char *dirspell __P((char *));
/* declarations for functions defined in lib/sh/strcasecmp.c */
#if !defined (HAVE_STRCASECMP)
extern int strncasecmp __P((const char *, const char *, int));
extern int strcasecmp __P((const char *, const char *));
#endif /* HAVE_STRCASECMP */
/* declarations for functions defined in lib/sh/strcasestr.c */
#if ! HAVE_STRCASESTR
extern char *strcasestr __P((const char *, const char *));
#endif
/* declarations for functions defined in lib/sh/strchrnul.c */
#if ! HAVE_STRCHRNUL
extern char *strchrnul __P((const char *, int));
#endif
/* declarations for functions defined in lib/sh/strerror.c */
#if !defined (HAVE_STRERROR) && !defined (strerror)
extern char *strerror __P((int));
#endif
/* declarations for functions defined in lib/sh/strftime.c */
#if !defined (HAVE_STRFTIME) && defined (NEED_STRFTIME_DECL)
extern size_t strftime __P((char *, size_t, const char *, const struct tm *));
#endif
/* declarations for functions and structures defined in lib/sh/stringlist.c */
/* This is a general-purpose argv-style array struct. */
typedef struct _list_of_strings {
char **list;
int list_size;
int list_len;
} STRINGLIST;
typedef int sh_strlist_map_func_t __P((char *));
extern STRINGLIST *strlist_create __P((int));
extern STRINGLIST *strlist_resize __P((STRINGLIST *, int));
extern void strlist_flush __P((STRINGLIST *));
extern void strlist_dispose __P((STRINGLIST *));
extern int strlist_remove __P((STRINGLIST *, char *));
extern STRINGLIST *strlist_copy __P((STRINGLIST *));
extern STRINGLIST *strlist_merge __P((STRINGLIST *, STRINGLIST *));
extern STRINGLIST *strlist_append __P((STRINGLIST *, STRINGLIST *));
extern STRINGLIST *strlist_prefix_suffix __P((STRINGLIST *, char *, char *));
extern void strlist_print __P((STRINGLIST *, char *));
extern void strlist_walk __P((STRINGLIST *, sh_strlist_map_func_t *));
extern void strlist_sort __P((STRINGLIST *));
/* declarations for functions defined in lib/sh/stringvec.c */
extern char **strvec_create __P((int));
extern char **strvec_resize __P((char **, int));
extern void strvec_flush __P((char **));
extern void strvec_dispose __P((char **));
extern int strvec_remove __P((char **, char *));
extern int strvec_len __P((char **));
extern int strvec_search __P((char **, char *));
extern char **strvec_copy __P((char **));
extern int strvec_strcmp __P((char **, char **));
extern void strvec_sort __P((char **));
extern char **strvec_from_word_list __P((WORD_LIST *, int, int, int *));
extern WORD_LIST *strvec_to_word_list __P((char **, int, int));
/* declarations for functions defined in lib/sh/strnlen.c */
#if !defined (HAVE_STRNLEN)
extern size_t strnlen __P((const char *, size_t));
#endif
/* declarations for functions defined in lib/sh/strpbrk.c */
#if !defined (HAVE_STRPBRK)
extern char *strpbrk __P((const char *, const char *));
#endif
/* declarations for functions defined in lib/sh/strtod.c */
#if !defined (HAVE_STRTOD)
extern double strtod __P((const char *, char **));
#endif
/* declarations for functions defined in lib/sh/strtol.c */
#if !HAVE_DECL_STRTOL
extern long strtol __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strtoll.c */
#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOLL
extern long long strtoll __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strtoul.c */
#if !HAVE_DECL_STRTOUL
extern unsigned long strtoul __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strtoull.c */
#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOULL
extern unsigned long long strtoull __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strimax.c */
#if !HAVE_DECL_STRTOIMAX
extern intmax_t strtoimax __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strumax.c */
#if !HAVE_DECL_STRTOUMAX
extern uintmax_t strtoumax __P((const char *, char **, int));
#endif
/* declarations for functions defined in lib/sh/strtrans.c */
extern char *ansicstr __P((char *, int, int, int *, int *));
extern char *ansic_quote __P((char *, int, int *));
extern int ansic_shouldquote __P((const char *));
extern char *ansiexpand __P((char *, int, int, int *));
/* declarations for functions defined in lib/sh/timeval.c. No prototypes
so we don't have to count on having a definition of struct timeval in
scope when this file is included. */
extern void timeval_to_secs ();
extern void print_timeval ();
/* declarations for functions defined in lib/sh/tmpfile.c */
#define MT_USETMPDIR 0x0001
#define MT_READWRITE 0x0002
#define MT_USERANDOM 0x0004
extern char *sh_mktmpname __P((char *, int));
extern int sh_mktmpfd __P((char *, int, char **));
/* extern FILE *sh_mktmpfp __P((char *, int, char **)); */
/* declarations for functions defined in lib/sh/uconvert.c */
extern int uconvert __P((char *, long *, long *));
/* declarations for functions defined in lib/sh/ufuncs.c */
extern unsigned int falarm __P((unsigned int, unsigned int));
extern unsigned int fsleep __P((unsigned int, unsigned int));
/* declarations for functions defined in lib/sh/unicode.c */
extern int u32cconv __P((unsigned long, char *));
extern void u32reset __P((void));
/* declarations for functions defined in lib/sh/winsize.c */
extern void get_new_window_size __P((int, int *, int *));
/* declarations for functions defined in lib/sh/zcatfd.c */
extern int zcatfd __P((int, int, char *));
/* declarations for functions defined in lib/sh/zgetline.c */
extern ssize_t zgetline __P((int, char **, size_t *, int));
/* declarations for functions defined in lib/sh/zmapfd.c */
extern int zmapfd __P((int, char **, char *));
/* declarations for functions defined in lib/sh/zread.c */
extern ssize_t zread __P((int, char *, size_t));
extern ssize_t zreadretry __P((int, char *, size_t));
extern ssize_t zreadintr __P((int, char *, size_t));
extern ssize_t zreadc __P((int, char *));
extern ssize_t zreadcintr __P((int, char *));
extern void zreset __P((void));
extern void zsyncfd __P((int));
/* declarations for functions defined in lib/sh/zwrite.c */
extern int zwrite __P((int, char *, size_t));
/* declarations for functions defined in lib/glob/gmisc.c */
extern int match_pattern_char __P((char *, char *));
extern int umatchlen __P((char *, size_t));
#if defined (HANDLE_MULTIBYTE)
extern int match_pattern_wchar __P((wchar_t *, wchar_t *));
extern int wmatchlen __P((wchar_t *, size_t));
#endif
#endif /* _EXTERNS_H_ */
+1 -1
View File
@@ -21,7 +21,7 @@
#include "config.h"
#include "bashtypes.h"
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include "posixstat.h"
+1166
View File
File diff suppressed because it is too large Load Diff
+7 -9
View File
@@ -45,7 +45,7 @@
#include "filecntl.h"
#include <sys/ioctl.h>
#ifdef HAVE_SYS_PARAM_H
#if defined (HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
@@ -1898,15 +1898,13 @@ make_child (command, async_p)
last_asynchronous_pid = 1;
#endif
if (pid_wrap > 0)
delete_old_job (pid);
/* Delete the saved status for any job containing this PID in case it's
been reused. */
delete_old_job (pid);
#if !defined (RECYCLES_PIDS)
/* Only check for saved status if we've saved more than CHILD_MAX
statuses, unless the system recycles pids. */
if ((js.c_reaped + bgpids.npid) >= js.c_childmax)
#endif
bgp_delete (pid); /* new process, discard any saved status */
/* Perform the check for pid reuse unconditionally. Some systems reuse
PIDs before giving a process CHILD_MAX/_SC_CHILD_MAX unique ones. */
bgp_delete (pid); /* new process, discard any saved status */
last_made_pid = pid;
+4312
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -32,7 +32,7 @@
#endif
#if !defined (getpagesize)
# ifndef _MINIX
# if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
# endif
# if defined (PAGESIZE)
+60
View File
@@ -0,0 +1,60 @@
/* Emulation of getpagesize() for systems that need it.
Copyright (C) 1991-2003 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/>.
*/
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
# if defined (_SC_PAGESIZE)
# define getpagesize() sysconf(_SC_PAGESIZE)
# else
# if defined (_SC_PAGE_SIZE)
# define getpagesize() sysconf(_SC_PAGE_SIZE)
# endif /* _SC_PAGE_SIZE */
# endif /* _SC_PAGESIZE */
#endif
#if !defined (getpagesize)
# ifndef _MINIX
# include <sys/param.h>
# endif
# if defined (PAGESIZE)
# define getpagesize() PAGESIZE
# else /* !PAGESIZE */
# if defined (EXEC_PAGESIZE)
# define getpagesize() EXEC_PAGESIZE
# else /* !EXEC_PAGESIZE */
# if defined (NBPG)
# if !defined (CLSIZE)
# define CLSIZE 1
# endif /* !CLSIZE */
# define getpagesize() (NBPG * CLSIZE)
# else /* !NBPG */
# if defined (NBPC)
# define getpagesize() NBPC
# endif /* NBPC */
# endif /* !NBPG */
# endif /* !EXEC_PAGESIZE */
# endif /* !PAGESIZE */
#endif /* !getpagesize */
#if !defined (getpagesize)
# define getpagesize() 4096 /* Just punt and use reasonable value */
#endif
+3 -1
View File
@@ -21,7 +21,9 @@
#include <config.h>
#include <bashtypes.h>
#include <sys/param.h>
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
+59
View File
@@ -0,0 +1,59 @@
/* clktck.c - get the value of CLK_TCK. */
/* Copyright (C) 1997 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>
#include <bashtypes.h>
#include <sys/param.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK)
# if !defined (CLK_TCK)
# if defined (HZ)
# define CLK_TCK HZ
# else
# define CLK_TCK 60
# endif
# endif /* !CLK_TCK */
#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */
long
get_clk_tck ()
{
static long retval = 0;
if (retval != 0)
return (retval);
#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK)
retval = sysconf (_SC_CLK_TCK);
#else /* !SYSCONF || !_SC_CLK_TCK */
retval = CLK_TCK;
#endif /* !SYSCONF || !_SC_CLK_TCK */
return (retval);
}
+2
View File
@@ -67,7 +67,9 @@ static char rcsid[] = "$Id: inet_addr.c,v 1.5 1996/08/14 03:48:37 drepper Exp $"
#if !defined (HAVE_INET_ATON) && defined (HAVE_NETWORK) && defined (HAVE_NETINET_IN_H) && defined (HAVE_ARPA_INET_H)
#include <sys/types.h>
#if defined (HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
+212
View File
@@ -0,0 +1,212 @@
/* inet_aton - convert string to numeric IP address */
/* Snagged from GNU C library, version 2.0.3. */
/*
* ++Copyright++ 1983, 1990, 1993
* -
* Copyright (c) 1983, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
* -
* --Copyright--
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
static char rcsid[] = "$Id: inet_addr.c,v 1.5 1996/08/14 03:48:37 drepper Exp $";
#endif /* LIBC_SCCS and not lint */
#include <config.h>
#if !defined (HAVE_INET_ATON) && defined (HAVE_NETWORK) && defined (HAVE_NETINET_IN_H) && defined (HAVE_ARPA_INET_H)
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <bashansi.h>
#include <ctype.h>
#include <stdc.h>
#ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
#endif
/* these are compatibility routines, not needed on recent BSD releases */
#if 0
/* Not used, not needed. */
/*
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
u_long
inet_addr(cp)
register const char *cp;
{
struct in_addr val;
if (inet_aton(cp, &val))
return (val.s_addr);
return (INADDR_NONE);
}
#endif
/*
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*/
int
inet_aton(cp, addr)
register const char *cp;
struct in_addr *addr;
{
register u_bits32_t val;
register int base, n;
register unsigned char c;
u_int parts[4];
register u_int *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
#if 0
if (!isdigit(c))
#else
if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' &&
c != '5' && c != '6' && c != '7' && c != '8' && c != '9')
#endif
return (0);
val = 0; base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X')
base = 16, c = *++cp;
else
base = 8;
}
for (;;) {
if (isascii(c) && isdigit(c)) {
val = (val * base) + (c - '0');
c = *++cp;
} else if (base == 16 && isascii(c) && isxdigit(c)) {
val = (val << 4) |
(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace(c)))
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffff)
return (0);
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
}
if (addr)
addr->s_addr = htonl(val);
return (1);
}
#endif /* !HAVE_INET_ATON */
+1 -1
View File
@@ -28,7 +28,7 @@
#include <posixdir.h>
#include <bashansi.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+159
View File
@@ -0,0 +1,159 @@
/* mailstat.c -- stat a mailbox file, handling maildir-type mail directories */
/* Copyright (C) 2001 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>
#include <stdio.h>
#include <errno.h>
#include <bashtypes.h>
#include <posixstat.h>
#include <posixdir.h>
#include <bashansi.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#include <maxpath.h>
/*
* Stat a file. If it's a maildir, check all messages
* in the maildir and present the grand total as a file.
* The fields in the 'struct stat' are from the mail directory.
* The following fields are emulated:
*
* st_nlink always 1, unless st_blocks is not present, in which case it's
* the total number of messages
* st_size total number of bytes in all files
* st_blocks total number of messages, if present in struct stat
* st_atime access time of newest file in maildir
* st_mtime modify time of newest file in maildir
* st_mode S_IFDIR changed to S_IFREG
*
* This is good enough for most mail-checking applications.
*/
int
mailstat(path, st)
const char *path;
struct stat *st;
{
static struct stat st_new_last, st_ret_last;
struct stat st_ret, st_tmp;
DIR *dd;
struct dirent *fn;
char dir[PATH_MAX * 2], file[PATH_MAX * 2];
int i, l;
time_t atime, mtime;
atime = mtime = 0;
/* First see if it's a directory. */
if ((i = stat(path, st)) != 0 || S_ISDIR(st->st_mode) == 0)
return i;
if (strlen(path) > sizeof(dir) - 5)
{
#ifdef ENAMETOOLONG
errno = ENAMETOOLONG;
#else
errno = EINVAL;
#endif
return -1;
}
st_ret = *st;
st_ret.st_nlink = 1;
st_ret.st_size = 0;
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
st_ret.st_blocks = 0;
#else
st_ret.st_nlink = 0;
#endif
st_ret.st_mode &= ~S_IFDIR;
st_ret.st_mode |= S_IFREG;
/* See if cur/ is present */
sprintf(dir, "%s/cur", path);
if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0)
return 0;
st_ret.st_atime = st_tmp.st_atime;
/* See if tmp/ is present */
sprintf(dir, "%s/tmp", path);
if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0)
return 0;
st_ret.st_mtime = st_tmp.st_mtime;
/* And new/ */
sprintf(dir, "%s/new", path);
if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0)
return 0;
st_ret.st_mtime = st_tmp.st_mtime;
/* Optimization - if new/ didn't change, nothing else did. */
if (st_tmp.st_dev == st_new_last.st_dev &&
st_tmp.st_ino == st_new_last.st_ino &&
st_tmp.st_atime == st_new_last.st_atime &&
st_tmp.st_mtime == st_new_last.st_mtime)
{
*st = st_ret_last;
return 0;
}
st_new_last = st_tmp;
/* Loop over new/ and cur/ */
for (i = 0; i < 2; i++)
{
sprintf(dir, "%s/%s", path, i ? "cur" : "new");
sprintf(file, "%s/", dir);
l = strlen(file);
if ((dd = opendir(dir)) == NULL)
return 0;
while ((fn = readdir(dd)) != NULL)
{
if (fn->d_name[0] == '.' || strlen(fn->d_name) + l >= sizeof(file))
continue;
strcpy(file + l, fn->d_name);
if (stat(file, &st_tmp) != 0)
continue;
st_ret.st_size += st_tmp.st_size;
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
st_ret.st_blocks++;
#else
st_ret.st_nlink++;
#endif
if (st_tmp.st_atime != st_tmp.st_mtime && st_tmp.st_atime > atime)
atime = st_tmp.st_atime;
if (st_tmp.st_mtime > mtime)
mtime = st_tmp.st_mtime;
}
closedir(dd);
}
/* if (atime) */ /* Set atime even if cur/ is empty */
st_ret.st_atime = atime;
if (mtime)
st_ret.st_mtime = mtime;
*st = st_ret_last = st_ret;
return 0;
}
+1 -1
View File
@@ -21,7 +21,7 @@
#include <config.h>
#include <bashtypes.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+301
View File
@@ -0,0 +1,301 @@
/* oslib.c - functions present only in some unix versions. */
/* Copyright (C) 1995,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/>.
*/
#include <config.h>
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#include <posixstat.h>
#include <filecntl.h>
#include <bashansi.h>
#if !defined (HAVE_KILLPG)
# include <signal.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <chartypes.h>
#include <shell.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* Make the functions strchr and strrchr if they do not exist. */
#if !defined (HAVE_STRCHR)
char *
strchr (string, c)
char *string;
int c;
{
register char *s;
for (s = string; s && *s; s++)
if (*s == c)
return (s);
return ((char *) NULL);
}
char *
strrchr (string, c)
char *string;
int c;
{
register char *s, *t;
for (s = string, t = (char *)NULL; s && *s; s++)
if (*s == c)
t = s;
return (t);
}
#endif /* !HAVE_STRCHR */
#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN)
/* Replacement for dup2 (), for those systems which either don't have it,
or supply one with broken behaviour. */
int
dup2 (fd1, fd2)
int fd1, fd2;
{
int saved_errno, r;
/* If FD1 is not a valid file descriptor, then return immediately with
an error. */
if (fcntl (fd1, F_GETFL, 0) == -1)
return (-1);
if (fd2 < 0 || fd2 >= getdtablesize ())
{
errno = EBADF;
return (-1);
}
if (fd1 == fd2)
return (0);
saved_errno = errno;
(void) close (fd2);
r = fcntl (fd1, F_DUPFD, fd2);
if (r >= 0)
errno = saved_errno;
else
if (errno == EINVAL)
errno = EBADF;
/* Force the new file descriptor to remain open across exec () calls. */
SET_OPEN_ON_EXEC (fd2);
return (r);
}
#endif /* !HAVE_DUP2 */
/*
* Return the total number of available file descriptors.
*
* On some systems, like 4.2BSD and its descendents, there is a system call
* that returns the size of the descriptor table: getdtablesize(). There are
* lots of ways to emulate this on non-BSD systems.
*
* On System V.3, this can be obtained via a call to ulimit:
* return (ulimit(4, 0L));
*
* On other System V systems, NOFILE is defined in /usr/include/sys/param.h
* (this is what we assume below), so we can simply use it:
* return (NOFILE);
*
* On POSIX systems, there are specific functions for retrieving various
* configuration parameters:
* return (sysconf(_SC_OPEN_MAX));
*
*/
#if !defined (HAVE_GETDTABLESIZE)
int
getdtablesize ()
{
# if defined (_POSIX_VERSION) && defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
return (sysconf(_SC_OPEN_MAX)); /* Posix systems use sysconf */
# else /* ! (_POSIX_VERSION && HAVE_SYSCONF && _SC_OPEN_MAX) */
# if defined (ULIMIT_MAXFDS)
return (ulimit (4, 0L)); /* System V.3 systems use ulimit(4, 0L) */
# else /* !ULIMIT_MAXFDS */
# if defined (NOFILE) /* Other systems use NOFILE */
return (NOFILE);
# else /* !NOFILE */
return (20); /* XXX - traditional value is 20 */
# endif /* !NOFILE */
# endif /* !ULIMIT_MAXFDS */
# endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */
}
#endif /* !HAVE_GETDTABLESIZE */
#if !defined (HAVE_BCOPY)
# if defined (bcopy)
# undef bcopy
# endif
void
bcopy (s,d,n)
char *d, *s;
int n;
{
FASTCOPY (s, d, n);
}
#endif /* !HAVE_BCOPY */
#if !defined (HAVE_BZERO)
# if defined (bzero)
# undef bzero
# endif
void
bzero (s, n)
char *s;
int n;
{
register int i;
register char *r;
for (i = 0, r = s; i < n; i++)
*r++ = '\0';
}
#endif
#if !defined (HAVE_GETHOSTNAME)
# if defined (HAVE_UNAME)
# include <sys/utsname.h>
int
gethostname (name, namelen)
char *name;
int namelen;
{
int i;
struct utsname ut;
--namelen;
uname (&ut);
i = strlen (ut.nodename) + 1;
strncpy (name, ut.nodename, i < namelen ? i : namelen);
name[namelen] = '\0';
return (0);
}
# else /* !HAVE_UNAME */
int
gethostname (name, namelen)
char *name;
int namelen;
{
strncpy (name, "unknown", namelen);
name[namelen] = '\0';
return 0;
}
# endif /* !HAVE_UNAME */
#endif /* !HAVE_GETHOSTNAME */
#if !defined (HAVE_KILLPG)
int
killpg (pgrp, sig)
pid_t pgrp;
int sig;
{
return (kill (-pgrp, sig));
}
#endif /* !HAVE_KILLPG */
#if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION)
int
mkfifo (path, mode)
char *path;
int mode;
{
#if defined (S_IFIFO)
return (mknod (path, (mode | S_IFIFO), 0));
#else /* !S_IFIFO */
return (-1);
#endif /* !S_IFIFO */
}
#endif /* !HAVE_MKFIFO && PROCESS_SUBSTITUTION */
#define DEFAULT_MAXGROUPS 64
int
getmaxgroups ()
{
static int maxgroups = -1;
if (maxgroups > 0)
return maxgroups;
#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
maxgroups = sysconf (_SC_NGROUPS_MAX);
#else
# if defined (NGROUPS_MAX)
maxgroups = NGROUPS_MAX;
# else /* !NGROUPS_MAX */
# if defined (NGROUPS)
maxgroups = NGROUPS;
# else /* !NGROUPS */
maxgroups = DEFAULT_MAXGROUPS;
# endif /* !NGROUPS */
# endif /* !NGROUPS_MAX */
#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
if (maxgroups <= 0)
maxgroups = DEFAULT_MAXGROUPS;
return maxgroups;
}
long
getmaxchild ()
{
static long maxchild = -1L;
if (maxchild > 0)
return maxchild;
#if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
maxchild = sysconf (_SC_CHILD_MAX);
#else
# if defined (CHILD_MAX)
maxchild = CHILD_MAX;
# else
# if defined (MAXUPRC)
maxchild = MAXUPRC;
# endif /* MAXUPRC */
# endif /* CHILD_MAX */
#endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
return (maxchild);
}
+1 -1
View File
@@ -21,7 +21,7 @@
#include <config.h>
#include <bashtypes.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include <posixstat.h>
+234
View File
@@ -0,0 +1,234 @@
/* pathcanon.c -- canonicalize and manipulate pathnames. */
/* Copyright (C) 2000 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>
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#include <posixstat.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <filecntl.h>
#include <bashansi.h>
#include <stdio.h>
#include <chartypes.h>
#include <errno.h>
#include "shell.h"
#if !defined (errno)
extern int errno;
#endif
#if defined (__CYGWIN__)
#include <sys/cygwin.h>
static int
_is_cygdrive (path)
char *path;
{
static char user[MAXPATHLEN];
static char system[MAXPATHLEN];
static int first_time = 1;
/* If the path is the first part of a network path, treat it as
existing. */
if (path[0] == '/' && path[1] == '/' && !strchr (path + 2, '/'))
return 1;
/* Otherwise check for /cygdrive prefix. */
if (first_time)
{
char user_flags[MAXPATHLEN];
char system_flags[MAXPATHLEN];
/* Get the cygdrive info */
cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags, system_flags);
first_time = 0;
}
return !strcasecmp (path, user) || !strcasecmp (path, system);
}
#endif /* __CYGWIN__ */
/* Return 1 if PATH corresponds to a directory. A function for debugging. */
static int
_path_isdir (path)
char *path;
{
int l;
struct stat sb;
/* This should leave errno set to the correct value. */
errno = 0;
l = stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
#if defined (__CYGWIN__)
if (l == 0)
l = _is_cygdrive (path);
#endif
return l;
}
/* Canonicalize PATH, and return a new path. The new path differs from PATH
in that:
Multple `/'s are collapsed to a single `/'.
Leading `./'s and trailing `/.'s are removed.
Trailing `/'s are removed.
Non-leading `../'s and trailing `..'s are handled by removing
portions of the path. */
/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */
#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/')
char *
sh_canonpath (path, flags)
char *path;
int flags;
{
char stub_char;
char *result, *p, *q, *base, *dotdot;
int rooted, double_slash_path;
/* The result cannot be larger than the input PATH. */
result = (flags & PATH_NOALLOC) ? path : savestring (path);
/* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any
leading `x:' (dos drive name). */
if (rooted = ROOTEDPATH(path))
{
stub_char = DIRSEP;
#if defined (__CYGWIN__)
base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 3 : result + 1;
#else
base = result + 1;
#endif
double_slash_path = DOUBLE_SLASH (path);
base += double_slash_path;
}
else
{
stub_char = '.';
#if defined (__CYGWIN__)
base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 2 : result;
#else
base = result;
#endif
double_slash_path = 0;
}
/*
* invariants:
* base points to the portion of the path we want to modify
* p points at beginning of path element we're considering.
* q points just past the last path element we wrote (no slash).
* dotdot points just past the point where .. cannot backtrack
* any further (no slash).
*/
p = q = dotdot = base;
while (*p)
{
if (ISDIRSEP(p[0])) /* null element */
p++;
else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */
p += 1; /* don't count the separator in case it is nul */
else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */
{
p += 2; /* skip `..' */
if (q > dotdot) /* can backtrack */
{
if (flags & PATH_CHECKDOTDOT)
{
char c;
/* Make sure what we have so far corresponds to a valid
path before we chop some of it off. */
c = *q;
*q = '\0';
if (_path_isdir (result) == 0)
{
if ((flags & PATH_NOALLOC) == 0)
free (result);
return ((char *)NULL);
}
*q = c;
}
while (--q > dotdot && ISDIRSEP(*q) == 0)
;
}
else if (rooted == 0)
{
/* /.. is / but ./../ is .. */
if (q != base)
*q++ = DIRSEP;
*q++ = '.';
*q++ = '.';
dotdot = q;
}
}
else /* real path element */
{
/* add separator if not at start of work portion of result */
if (q != base)
*q++ = DIRSEP;
while (*p && (ISDIRSEP(*p) == 0))
*q++ = *p++;
/* Check here for a valid directory with _path_isdir. */
if (flags & PATH_CHECKEXISTS)
{
char c;
/* Make sure what we have so far corresponds to a valid
path before we chop some of it off. */
c = *q;
*q = '\0';
if (_path_isdir (result) == 0)
{
if ((flags & PATH_NOALLOC) == 0)
free (result);
return ((char *)NULL);
}
*q = c;
}
}
}
/* Empty string is really ``.'' or `/', depending on what we started with. */
if (q == result)
*q++ = stub_char;
*q = '\0';
/* If the result starts with `//', but the original path does not, we
can turn the // into /. Because of how we set `base', this should never
be true, but it's a sanity check. */
if (DOUBLE_SLASH(result) && double_slash_path == 0)
{
if (result[2] == '\0') /* short-circuit for bare `//' */
result[1] = '\0';
else
strcpy (result, result + 1);
}
return (result);
}
+1 -1
View File
@@ -21,7 +21,7 @@
#include <config.h>
#include <bashtypes.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include <posixstat.h>
+296
View File
@@ -0,0 +1,296 @@
/* pathphys.c -- return pathname with all symlinks expanded. */
/* Copyright (C) 2000 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>
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#include <posixstat.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <filecntl.h>
#include <bashansi.h>
#include <stdio.h>
#include <chartypes.h>
#include <errno.h>
#include "shell.h"
#if !defined (MAXSYMLINKS)
# define MAXSYMLINKS 32
#endif
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern char *get_working_directory __P((char *));
static int
_path_readlink (path, buf, bufsiz)
char *path;
char *buf;
int bufsiz;
{
#ifdef HAVE_READLINK
return readlink (path, buf, bufsiz);
#else
errno = EINVAL;
return -1;
#endif
}
/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */
#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/')
/*
* Return PATH with all symlinks expanded in newly-allocated memory.
* This always gets an absolute pathname.
*/
char *
sh_physpath (path, flags)
char *path;
int flags;
{
char tbuf[PATH_MAX+1], linkbuf[PATH_MAX+1];
char *result, *p, *q, *qsave, *qbase, *workpath;
int double_slash_path, linklen, nlink;
linklen = strlen (path);
#if 0
/* First sanity check -- punt immediately if the name is too long. */
if (linklen >= PATH_MAX)
return (savestring (path));
#endif
nlink = 0;
q = result = (char *)xmalloc (PATH_MAX + 1);
/* Even if we get something longer than PATH_MAX, we might be able to
shorten it, so we try. */
if (linklen >= PATH_MAX)
workpath = savestring (path);
else
{
workpath = (char *)xmalloc (PATH_MAX + 1);
strcpy (workpath, path);
}
/* This always gets an absolute pathname. */
/* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any
leading `x:' (dos drive name). */
#if defined (__CYGWIN__)
qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
#else
qbase = workpath + 1;
#endif
double_slash_path = DOUBLE_SLASH (workpath);
qbase += double_slash_path;
for (p = workpath; p < qbase; )
*q++ = *p++;
qbase = q;
/*
* invariants:
* qbase points to the portion of the result path we want to modify
* p points at beginning of path element we're considering.
* q points just past the last path element we wrote (no slash).
*
* XXX -- need to fix error checking for too-long pathnames
*/
while (*p)
{
if (ISDIRSEP(p[0])) /* null element */
p++;
else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */
p += 1; /* don't count the separator in case it is nul */
else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */
{
p += 2; /* skip `..' */
if (q > qbase)
{
while (--q > qbase && ISDIRSEP(*q) == 0)
;
}
}
else /* real path element */
{
/* add separator if not at start of work portion of result */
qsave = q;
if (q != qbase)
*q++ = DIRSEP;
while (*p && (ISDIRSEP(*p) == 0))
{
if (q - result >= PATH_MAX)
{
#ifdef ENAMETOOLONG
errno = ENAMETOOLONG;
#else
errno = EINVAL;
#endif
goto error;
}
*q++ = *p++;
}
*q = '\0';
linklen = _path_readlink (result, linkbuf, PATH_MAX);
if (linklen < 0) /* if errno == EINVAL, it's not a symlink */
{
if (errno != EINVAL)
goto error;
continue;
}
/* It's a symlink, and the value is in LINKBUF. */
nlink++;
if (nlink > MAXSYMLINKS)
{
#ifdef ELOOP
errno = ELOOP;
#else
errno = EINVAL;
#endif
error:
free (result);
free (workpath);
return ((char *)NULL);
}
linkbuf[linklen] = '\0';
/* If the new path length would overrun PATH_MAX, punt now. */
if ((strlen (p) + linklen + 2) >= PATH_MAX)
{
#ifdef ENAMETOOLONG
errno = ENAMETOOLONG;
#else
errno = EINVAL;
#endif
goto error;
}
/* Form the new pathname by copying the link value to a temporary
buffer and appending the rest of `workpath'. Reset p to point
to the start of the rest of the path. If the link value is an
absolute pathname, reset p, q, and qbase. If not, reset p
and q. */
strcpy (tbuf, linkbuf);
tbuf[linklen] = '/';
strcpy (tbuf + linklen, p);
strcpy (workpath, tbuf);
if (ABSPATH(linkbuf))
{
q = result;
/* Duplicating some code here... */
#if defined (__CYGWIN__)
qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
#else
qbase = workpath + 1;
#endif
double_slash_path = DOUBLE_SLASH (workpath);
qbase += double_slash_path;
for (p = workpath; p < qbase; )
*q++ = *p++;
qbase = q;
}
else
{
p = workpath;
q = qsave;
}
}
}
*q = '\0';
free (workpath);
/* If the result starts with `//', but the original path does not, we
can turn the // into /. Because of how we set `qbase', this should never
be true, but it's a sanity check. */
if (DOUBLE_SLASH(result) && double_slash_path == 0)
{
if (result[2] == '\0') /* short-circuit for bare `//' */
result[1] = '\0';
else
strcpy (result, result + 1);
}
return (result);
}
char *
sh_realpath (pathname, resolved)
const char *pathname;
char *resolved;
{
char *tdir, *wd;
if (pathname == 0 || *pathname == '\0')
{
errno = (pathname == 0) ? EINVAL : ENOENT;
return ((char *)NULL);
}
if (ABSPATH (pathname) == 0)
{
wd = get_working_directory ("sh_realpath");
if (wd == 0)
return ((char *)NULL);
tdir = sh_makepath ((char *)pathname, wd, 0);
free (wd);
}
else
tdir = savestring (pathname);
wd = sh_physpath (tdir, 0);
free (tdir);
if (resolved == 0)
return (wd);
if (wd)
{
strncpy (resolved, wd, PATH_MAX - 1);
resolved[PATH_MAX - 1] = '\0';
free (wd);
return resolved;
}
else
{
resolved[0] = '\0';
return wd;
}
}
+1 -1
View File
@@ -30,7 +30,7 @@
#include <bashtypes.h>
#include <posixdir.h>
#include <posixstat.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
+212
View File
@@ -0,0 +1,212 @@
/* spell.c -- spelling correction for pathnames. */
/* Copyright (C) 2000 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 <bashtypes.h>
#include <posixdir.h>
#include <posixstat.h>
#ifndef _MINIX
#include <sys/param.h>
#endif
#include <stdio.h>
#include <bashansi.h>
#include <maxpath.h>
#include <stdc.h>
static int mindist __P((char *, char *, char *));
static int spdist __P((char *, char *));
/*
* `spname' and its helpers are inspired by the code in "The UNIX
* Programming Environment", Kernighan & Pike, Prentice-Hall 1984,
* pages 209 - 213.
*/
/*
* `spname' -- return a correctly spelled filename
*
* int spname(char * oldname, char * newname)
* Returns: -1 if no reasonable match found
* 0 if exact match found
* 1 if corrected
* Stores corrected name in `newname'.
*/
int
spname(oldname, newname)
char *oldname;
char *newname;
{
char *op, *np, *p;
char guess[PATH_MAX + 1], best[PATH_MAX + 1];
op = oldname;
np = newname;
for (;;)
{
while (*op == '/') /* Skip slashes */
*np++ = *op++;
*np = '\0';
if (*op == '\0') /* Exact or corrected */
{
/* `.' is rarely the right thing. */
if (oldname[1] == '\0' && newname[1] == '\0' &&
oldname[0] != '.' && newname[0] == '.')
return -1;
return strcmp(oldname, newname) != 0;
}
/* Copy next component into guess */
for (p = guess; *op != '/' && *op != '\0'; op++)
if (p < guess + PATH_MAX)
*p++ = *op;
*p = '\0';
if (mindist(newname, guess, best) >= 3)
return -1; /* Hopeless */
/*
* Add to end of newname
*/
for (p = best; *np = *p++; np++)
;
}
}
/*
* Search directory for a guess
*/
static int
mindist(dir, guess, best)
char *dir;
char *guess;
char *best;
{
DIR *fd;
struct dirent *dp;
int dist, x;
dist = 3; /* Worst distance */
if (*dir == '\0')
dir = ".";
if ((fd = opendir(dir)) == NULL)
return dist;
while ((dp = readdir(fd)) != NULL)
{
/*
* Look for a better guess. If the new guess is as
* good as the current one, we take it. This way,
* any single character match will be a better match
* than ".".
*/
x = spdist(dp->d_name, guess);
if (x <= dist && x != 3)
{
strcpy(best, dp->d_name);
dist = x;
if (dist == 0) /* Exact match */
break;
}
}
(void)closedir(fd);
/* Don't return `.' */
if (best[0] == '.' && best[1] == '\0')
dist = 3;
return dist;
}
/*
* `spdist' -- return the "distance" between two names.
*
* int spname(char * oldname, char * newname)
* Returns: 0 if strings are identical
* 1 if two characters are transposed
* 2 if one character is wrong, added or deleted
* 3 otherwise
*/
static int
spdist(cur, new)
char *cur, *new;
{
while (*cur == *new)
{
if (*cur == '\0')
return 0; /* Exact match */
cur++;
new++;
}
if (*cur)
{
if (*new)
{
if (cur[1] && new[1] && cur[0] == new[1] && cur[1] == new[0] && strcmp (cur + 2, new + 2) == 0)
return 1; /* Transposition */
if (strcmp (cur + 1, new + 1) == 0)
return 2; /* One character mismatch */
}
if (strcmp(&cur[1], &new[0]) == 0)
return 2; /* Extra character */
}
if (*new && strcmp(cur, new + 1) == 0)
return 2; /* Missing character */
return 3;
}
char *
dirspell (dirname)
char *dirname;
{
int n;
char *guess;
n = (strlen (dirname) * 3 + 1) / 2 + 1;
guess = (char *)malloc (n);
if (guess == 0)
return 0;
switch (spname (dirname, guess))
{
case -1:
default:
free (guess);
return (char *)NULL;
case 0:
case 1:
return guess;
}
}
+1 -1
View File
@@ -23,7 +23,7 @@
#if !defined (HAVE_STRERROR)
#include <bashtypes.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+74
View File
@@ -0,0 +1,74 @@
/* strerror.c - string corresponding to a particular value of errno. */
/* Copyright (C) 1995 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_STRERROR)
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <shell.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* Return a string corresponding to the error number E. From
the ANSI C spec. */
#if defined (strerror)
# undef strerror
#endif
static char *errbase = "Unknown system error ";
char *
strerror (e)
int e;
{
static char emsg[40];
#if defined (HAVE_SYS_ERRLIST)
extern int sys_nerr;
extern char *sys_errlist[];
if (e > 0 && e < sys_nerr)
return (sys_errlist[e]);
else
#endif /* HAVE_SYS_ERRLIST */
{
char *z;
z = itos (e);
strcpy (emsg, errbase);
strcat (emsg, z);
free (z);
return (&emsg[0]);
}
}
#endif /* HAVE_STRERROR */
+1 -1
View File
@@ -23,7 +23,7 @@
#include <stdio.h>
#include "bashtypes.h"
#include "posixstat.h"
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
+491
View File
@@ -0,0 +1,491 @@
/* mailcheck.c -- The check is in the mail... */
/* Copyright (C) 1987-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"
#include <stdio.h>
#include "bashtypes.h"
#include "posixstat.h"
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "posixtime.h"
#include "bashansi.h"
#include "bashintl.h"
#include "shell.h"
#include "execute_cmd.h"
#include "mailcheck.h"
#include <tilde/tilde.h>
/* Values for flags word in struct _fileinfo */
#define MBOX_INITIALIZED 0x01
extern time_t shell_start_time;
extern int mailstat __P((const char *, struct stat *));
typedef struct _fileinfo {
char *name;
char *msg;
time_t access_time;
time_t mod_time;
off_t file_size;
int flags;
} FILEINFO;
/* The list of remembered mail files. */
static FILEINFO **mailfiles = (FILEINFO **)NULL;
/* Number of mail files that we have. */
static int mailfiles_count;
/* The last known time that mail was checked. */
static time_t last_time_mail_checked = 0;
/* Non-zero means warn if a mail file has been read since last checked. */
int mail_warning;
static int find_mail_file __P((char *));
static void init_mail_file __P((int));
static void update_mail_file __P((int));
static int add_mail_file __P((char *, char *));
static FILEINFO *alloc_mail_file __P((char *, char *));
static void dispose_mail_file __P((FILEINFO *));
static int file_mod_date_changed __P((int));
static int file_access_date_changed __P((int));
static int file_has_grown __P((int));
static char *parse_mailpath_spec __P((char *));
/* Returns non-zero if it is time to check mail. */
int
time_to_check_mail ()
{
char *temp;
time_t now;
intmax_t seconds;
temp = get_string_value ("MAILCHECK");
/* Negative number, or non-numbers (such as empty string) cause no
checking to take place. */
if (temp == 0 || legal_number (temp, &seconds) == 0 || seconds < 0)
return (0);
now = NOW;
/* Time to check if MAILCHECK is explicitly set to zero, or if enough
time has passed since the last check. */
return (seconds == 0 || ((now - last_time_mail_checked) >= seconds));
}
/* Okay, we have checked the mail. Perhaps I should make this function
go away. */
void
reset_mail_timer ()
{
last_time_mail_checked = NOW;
}
/* Locate a file in the list. Return index of
entry, or -1 if not found. */
static int
find_mail_file (file)
char *file;
{
register int i;
for (i = 0; i < mailfiles_count; i++)
if (STREQ (mailfiles[i]->name, file))
return i;
return -1;
}
#define RESET_MAIL_FILE(i) \
do \
{ \
mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \
mailfiles[i]->file_size = 0; \
mailfiles[i]->flags = 0; \
} \
while (0)
#define UPDATE_MAIL_FILE(i, finfo) \
do \
{ \
mailfiles[i]->access_time = finfo.st_atime; \
mailfiles[i]->mod_time = finfo.st_mtime; \
mailfiles[i]->file_size = finfo.st_size; \
mailfiles[i]->flags |= MBOX_INITIALIZED; \
} \
while (0)
static void
init_mail_file (i)
int i;
{
mailfiles[i]->access_time = mailfiles[i]->mod_time = last_time_mail_checked ? last_time_mail_checked : shell_start_time;
mailfiles[i]->file_size = 0;
mailfiles[i]->flags = 0;
}
static void
update_mail_file (i)
int i;
{
char *file;
struct stat finfo;
file = mailfiles[i]->name;
if (mailstat (file, &finfo) == 0)
UPDATE_MAIL_FILE (i, finfo);
else
RESET_MAIL_FILE (i);
}
/* Add this file to the list of remembered files and return its index
in the list of mail files. */
static int
add_mail_file (file, msg)
char *file, *msg;
{
struct stat finfo;
char *filename;
int i;
filename = full_pathname (file);
i = find_mail_file (filename);
if (i >= 0)
{
if (mailstat (filename, &finfo) == 0)
UPDATE_MAIL_FILE (i, finfo);
free (filename);
return i;
}
i = mailfiles_count++;
mailfiles = (FILEINFO **)xrealloc
(mailfiles, mailfiles_count * sizeof (FILEINFO *));
mailfiles[i] = alloc_mail_file (filename, msg);
init_mail_file (i);
return i;
}
/* Reset the existing mail files access and modification times to zero. */
void
reset_mail_files ()
{
register int i;
for (i = 0; i < mailfiles_count; i++)
RESET_MAIL_FILE (i);
}
static FILEINFO *
alloc_mail_file (filename, msg)
char *filename, *msg;
{
FILEINFO *mf;
mf = (FILEINFO *)xmalloc (sizeof (FILEINFO));
mf->name = filename;
mf->msg = msg ? savestring (msg) : (char *)NULL;
mf->flags = 0;
return mf;
}
static void
dispose_mail_file (mf)
FILEINFO *mf;
{
free (mf->name);
FREE (mf->msg);
free (mf);
}
/* Free the information that we have about the remembered mail files. */
void
free_mail_files ()
{
register int i;
for (i = 0; i < mailfiles_count; i++)
dispose_mail_file (mailfiles[i]);
if (mailfiles)
free (mailfiles);
mailfiles_count = 0;
mailfiles = (FILEINFO **)NULL;
}
void
init_mail_dates ()
{
if (mailfiles == 0)
remember_mail_dates ();
}
/* Return non-zero if FILE's mod date has changed and it has not been
accessed since modified. If the size has dropped to zero, reset
the cached mail file info. */
static int
file_mod_date_changed (i)
int i;
{
time_t mtime;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
mtime = mailfiles[i]->mod_time;
if (mailstat (file, &finfo) != 0)
return (0);
if (finfo.st_size > 0)
return (mtime < finfo.st_mtime);
if (finfo.st_size == 0 && mailfiles[i]->file_size > 0)
UPDATE_MAIL_FILE (i, finfo);
return (0);
}
/* Return non-zero if FILE's access date has changed. */
static int
file_access_date_changed (i)
int i;
{
time_t atime;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
atime = mailfiles[i]->access_time;
if (mailstat (file, &finfo) != 0)
return (0);
if (finfo.st_size > 0)
return (atime < finfo.st_atime);
return (0);
}
/* Return non-zero if FILE's size has increased. */
static int
file_has_grown (i)
int i;
{
off_t size;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
size = mailfiles[i]->file_size;
return ((mailstat (file, &finfo) == 0) && (finfo.st_size > size));
}
/* Take an element from $MAILPATH and return the portion from
the first unquoted `?' or `%' to the end of the string. This is the
message to be printed when the file contents change. */
static char *
parse_mailpath_spec (str)
char *str;
{
char *s;
int pass_next;
for (s = str, pass_next = 0; s && *s; s++)
{
if (pass_next)
{
pass_next = 0;
continue;
}
if (*s == '\\')
{
pass_next++;
continue;
}
if (*s == '?' || *s == '%')
return s;
}
return ((char *)NULL);
}
char *
make_default_mailpath ()
{
#if defined (DEFAULT_MAIL_DIRECTORY)
char *mp;
get_current_user_info ();
mp = (char *)xmalloc (2 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name));
strcpy (mp, DEFAULT_MAIL_DIRECTORY);
mp[sizeof(DEFAULT_MAIL_DIRECTORY) - 1] = '/';
strcpy (mp + sizeof (DEFAULT_MAIL_DIRECTORY), current_user.user_name);
return (mp);
#else
return ((char *)NULL);
#endif
}
/* Remember the dates of the files specified by MAILPATH, or if there is
no MAILPATH, by the file specified in MAIL. If neither exists, use a
default value, which we randomly concoct from using Unix. */
void
remember_mail_dates ()
{
char *mailpaths;
char *mailfile, *mp;
int i = 0;
mailpaths = get_string_value ("MAILPATH");
/* If no $MAILPATH, but $MAIL, use that as a single filename to check. */
if (mailpaths == 0 && (mailpaths = get_string_value ("MAIL")))
{
add_mail_file (mailpaths, (char *)NULL);
return;
}
if (mailpaths == 0)
{
mailpaths = make_default_mailpath ();
if (mailpaths)
{
add_mail_file (mailpaths, (char *)NULL);
free (mailpaths);
}
return;
}
while (mailfile = extract_colon_unit (mailpaths, &i))
{
mp = parse_mailpath_spec (mailfile);
if (mp && *mp)
*mp++ = '\0';
add_mail_file (mailfile, mp);
free (mailfile);
}
}
/* check_mail () is useful for more than just checking mail. Since it has
the paranoids dream ability of telling you when someone has read your
mail, it can just as easily be used to tell you when someones .profile
file has been read, thus letting one know when someone else has logged
in. Pretty good, huh? */
/* Check for mail in some files. If the modification date of any
of the files in MAILPATH has changed since we last did a
remember_mail_dates () then mention that the user has mail.
Special hack: If the variable MAIL_WARNING is non-zero and the
mail file has been accessed since the last time we remembered, then
the message "The mail in <mailfile> has been read" is printed. */
void
check_mail ()
{
char *current_mail_file, *message;
int i, use_user_notification;
char *dollar_underscore, *temp;
dollar_underscore = get_string_value ("_");
if (dollar_underscore)
dollar_underscore = savestring (dollar_underscore);
for (i = 0; i < mailfiles_count; i++)
{
current_mail_file = mailfiles[i]->name;
if (*current_mail_file == '\0')
continue;
if (file_mod_date_changed (i))
{
int file_is_bigger;
use_user_notification = mailfiles[i]->msg != (char *)NULL;
message = mailfiles[i]->msg ? mailfiles[i]->msg : _("You have mail in $_");
bind_variable ("_", current_mail_file, 0);
#define atime mailfiles[i]->access_time
#define mtime mailfiles[i]->mod_time
/* Have to compute this before the call to update_mail_file, which
resets all the information. */
file_is_bigger = file_has_grown (i);
update_mail_file (i);
/* If the user has just run a program which manipulates the
mail file, then don't bother explaining that the mail
file has been manipulated. Since some systems don't change
the access time to be equal to the modification time when
the mail in the file is manipulated, check the size also. If
the file has not grown, continue. */
if ((atime >= mtime) && !file_is_bigger)
continue;
/* If the mod time is later than the access time and the file
has grown, note the fact that this is *new* mail. */
if (use_user_notification == 0 && (atime < mtime) && file_is_bigger)
message = _("You have new mail in $_");
#undef atime
#undef mtime
if (temp = expand_string_to_string (message, Q_DOUBLE_QUOTES))
{
puts (temp);
free (temp);
}
else
putchar ('\n');
}
if (mail_warning && file_access_date_changed (i))
{
update_mail_file (i);
printf (_("The mail in %s has been read\n"), current_mail_file);
}
}
if (dollar_underscore)
{
bind_variable ("_", dollar_underscore, 0);
free (dollar_underscore);
}
else
unbind_variable ("_");
}
+1 -1
View File
@@ -380,7 +380,7 @@ main(argc, argv)
#if !defined (HAVE_STRERROR)
#include <bashtypes.h>
#ifndef _MINIX
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+415
View File
@@ -0,0 +1,415 @@
/*
* mksyntax.c - construct shell syntax table for fast char attribute lookup.
*/
/* Copyright (C) 2000-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"
#include <stdio.h>
#include "bashansi.h"
#include "chartypes.h"
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "syntax.h"
extern int optind;
extern char *optarg;
#ifndef errno
extern int errno;
#endif
#ifndef HAVE_STRERROR
extern char *strerror();
#endif
struct wordflag {
int flag;
char *fstr;
} wordflags[] = {
{ CWORD, "CWORD" },
{ CSHMETA, "CSHMETA" },
{ CSHBRK, "CSHBRK" },
{ CBACKQ, "CBACKQ" },
{ CQUOTE, "CQUOTE" },
{ CSPECL, "CSPECL" },
{ CEXP, "CEXP" },
{ CBSDQUOTE, "CBSDQUOTE" },
{ CBSHDOC, "CBSHDOC" },
{ CGLOB, "CGLOB" },
{ CXGLOB, "CXGLOB" },
{ CXQUOTE, "CXQUOTE" },
{ CSPECVAR, "CSPECVAR" },
{ CSUBSTOP, "CSUBSTOP" },
{ CBLANK, "CBLANK" },
};
#define N_WFLAGS (sizeof (wordflags) / sizeof (wordflags[0]))
#define SYNSIZE 256
int lsyntax[SYNSIZE];
int debug;
char *progname;
char preamble[] = "\
/*\n\
* This file was generated by mksyntax. DO NOT EDIT.\n\
*/\n\
\n";
char includes[] = "\
#include \"config.h\"\n\
#include \"stdc.h\"\n\
#include \"syntax.h\"\n\n";
static void
usage()
{
fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname);
exit (2);
}
#ifdef INCLUDE_UNUSED
static int
getcflag (s)
char *s;
{
int i;
for (i = 0; i < N_WFLAGS; i++)
if (strcmp (s, wordflags[i].fstr) == 0)
return wordflags[i].flag;
return -1;
}
#endif
static char *
cdesc (i)
int i;
{
static char xbuf[16];
if (i == ' ')
return "SPC";
else if (ISPRINT (i))
{
xbuf[0] = i;
xbuf[1] = '\0';
return (xbuf);
}
else if (i == CTLESC)
return "CTLESC";
else if (i == CTLNUL)
return "CTLNUL";
else if (i == '\033') /* ASCII */
return "ESC";
xbuf[0] = '\\';
xbuf[2] = '\0';
switch (i)
{
#ifdef __STDC__
case '\a': xbuf[1] = 'a'; break;
case '\v': xbuf[1] = 'v'; break;
#else
case '\007': xbuf[1] = 'a'; break;
case 0x0B: xbuf[1] = 'v'; break;
#endif
case '\b': xbuf[1] = 'b'; break;
case '\f': xbuf[1] = 'f'; break;
case '\n': xbuf[1] = 'n'; break;
case '\r': xbuf[1] = 'r'; break;
case '\t': xbuf[1] = 't'; break;
default: sprintf (xbuf, "%d", i); break;
}
return xbuf;
}
static char *
getcstr (f)
int f;
{
int i;
for (i = 0; i < N_WFLAGS; i++)
if (f == wordflags[i].flag)
return (wordflags[i].fstr);
return ((char *)NULL);
}
static void
addcstr (str, flag)
char *str;
int flag;
{
char *s, *fstr;
unsigned char uc;
for (s = str; s && *s; s++)
{
uc = *s;
if (debug)
{
fstr = getcstr (flag);
fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc));
}
lsyntax[uc] |= flag;
}
}
static void
addcchar (c, flag)
unsigned char c;
int flag;
{
char *fstr;
if (debug)
{
fstr = getcstr (flag);
fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c));
}
lsyntax[c] |= flag;
}
static void
addblanks ()
{
register int i;
unsigned char uc;
for (i = 0; i < SYNSIZE; i++)
{
uc = i;
/* Since we don't call setlocale(), this defaults to the "C" locale, and
the default blank characters will be space and tab. */
if (isblank (uc))
lsyntax[uc] |= CBLANK;
}
}
/* load up the correct flag values in lsyntax */
static void
load_lsyntax ()
{
/* shell metacharacters */
addcstr (shell_meta_chars, CSHMETA);
/* shell word break characters */
addcstr (shell_break_chars, CSHBRK);
addcchar ('`', CBACKQ);
addcstr (shell_quote_chars, CQUOTE);
addcchar (CTLESC, CSPECL);
addcchar (CTLNUL, CSPECL);
addcstr (shell_exp_chars, CEXP);
addcstr (slashify_in_quotes, CBSDQUOTE);
addcstr (slashify_in_here_document, CBSHDOC);
addcstr (shell_glob_chars, CGLOB);
#if defined (EXTENDED_GLOB)
addcstr (ext_glob_chars, CXGLOB);
#endif
addcstr (shell_quote_chars, CXQUOTE);
addcchar ('\\', CXQUOTE);
addcstr ("@*#?-$!", CSPECVAR); /* omits $0...$9 and $_ */
addcstr ("-=?+", CSUBSTOP); /* OP in ${paramOPword} */
addblanks ();
}
static void
dump_lflags (fp, ind)
FILE *fp;
int ind;
{
int xflags, first, i;
xflags = lsyntax[ind];
first = 1;
if (xflags == 0)
fputs (wordflags[0].fstr, fp);
else
{
for (i = 1; i < N_WFLAGS; i++)
if (xflags & wordflags[i].flag)
{
if (first)
first = 0;
else
putc ('|', fp);
fputs (wordflags[i].fstr, fp);
}
}
}
static void
wcomment (fp, i)
FILE *fp;
int i;
{
fputs ("\t\t/* ", fp);
fprintf (fp, "%s", cdesc(i));
fputs (" */", fp);
}
static void
dump_lsyntax (fp)
FILE *fp;
{
int i;
fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE);
fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE);
for (i = 0; i < SYNSIZE; i++)
{
putc ('\t', fp);
dump_lflags (fp, i);
putc (',', fp);
wcomment (fp, i);
putc ('\n', fp);
}
fprintf (fp, "};\n");
}
int
main(argc, argv)
int argc;
char **argv;
{
int opt, i;
char *filename;
FILE *fp;
if ((progname = strrchr (argv[0], '/')) == 0)
progname = argv[0];
else
progname++;
filename = (char *)NULL;
debug = 0;
while ((opt = getopt (argc, argv, "do:")) != EOF)
{
switch (opt)
{
case 'd':
debug = 1;
break;
case 'o':
filename = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (filename)
{
fp = fopen (filename, "w");
if (fp == 0)
{
fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno));
exit (1);
}
}
else
{
filename = "stdout";
fp = stdout;
}
for (i = 0; i < SYNSIZE; i++)
lsyntax[i] = CWORD;
load_lsyntax ();
fprintf (fp, "%s\n", preamble);
fprintf (fp, "%s\n", includes);
dump_lsyntax (fp);
if (fp != stdout)
fclose (fp);
exit (0);
}
#if !defined (HAVE_STRERROR)
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
/* Return a string corresponding to the error number E. From
the ANSI C spec. */
#if defined (strerror)
# undef strerror
#endif
char *
strerror (e)
int e;
{
static char emsg[40];
#if defined (HAVE_SYS_ERRLIST)
extern int sys_nerr;
extern char *sys_errlist[];
if (e > 0 && e < sys_nerr)
return (sys_errlist[e]);
else
#endif /* HAVE_SYS_ERRLIST */
{
sprintf (emsg, "Unknown system error %d", e);
return (&emsg[0]);
}
}
#endif /* HAVE_STRERROR */
+2 -2
View File
@@ -1,6 +1,6 @@
/* patchlevel.h -- current bash patch level */
/* Copyright (C) 2001-2011 Free Software Foundation, Inc.
/* Copyright (C) 2001-2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 36
#define PATCHLEVEL 37
#endif /* _PATCHLEVEL_H_ */
+30
View File
@@ -0,0 +1,30 @@
/* patchlevel.h -- current bash patch level */
/* Copyright (C) 2001-2011 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/>.
*/
#if !defined (_PATCHLEVEL_H_)
#define _PATCHLEVEL_H_
/* It's important that there be no other strings in this file that match the
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 36
#endif /* _PATCHLEVEL_H_ */
+18
View File
@@ -957,6 +957,24 @@ sh_exit (s)
exit (s);
}
/* Exit a subshell, which includes calling the exit trap. We don't want to
do any more cleanup, since a subshell is created as an exact copy of its
parent. */
void
subshell_exit (s)
int s;
{
fflush (stdout);
fflush (stderr);
/* Do trap[0] if defined. Allow it to override the exit status
passed to us. */
if (signal_is_trapped (0))
s = run_exit_trap ();
sh_exit (s);
}
/* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey
the Posix.2 startup file rules: $ENV is expanded, and if the file it
names exists, that file is sourced. The Posix.2 rules are in effect
+1883
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -358,6 +358,8 @@ reset_terminating_signals ()
signal (XSIG (i), XHANDLER (i));
}
#endif /* !HAVE_POSIX_SIGNALS */
termsigs_initialized = 0;
}
#undef XSIG
#undef XHANDLER
+692
View File
@@ -0,0 +1,692 @@
/* sig.c - interface for shell signal handlers and signal initialization. */
/* Copyright (C) 1994-2012 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"
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include "bashintl.h"
#include "shell.h"
#if defined (JOB_CONTROL)
#include "jobs.h"
#endif /* JOB_CONTROL */
#include "siglist.h"
#include "sig.h"
#include "trap.h"
#include "builtins/common.h"
#if defined (READLINE)
# include "bashline.h"
# include <readline/readline.h>
#endif
#if defined (HISTORY)
# include "bashhist.h"
#endif
extern int last_command_exit_value;
extern int last_command_exit_signal;
extern int return_catch_flag;
extern int loop_level, continuing, breaking, funcnest;
extern int executing_list;
extern int comsub_ignore_return;
extern int parse_and_execute_level, shell_initialized;
#if defined (HISTORY)
extern int history_lines_this_session;
#endif
extern int no_line_editing;
extern void initialize_siglist ();
/* Non-zero after SIGINT. */
volatile int interrupt_state = 0;
/* Non-zero after SIGWINCH */
volatile int sigwinch_received = 0;
/* Set to the value of any terminating signal received. */
volatile int terminating_signal = 0;
/* The environment at the top-level R-E loop. We use this in
the case of error return. */
procenv_t top_level;
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
/* The signal masks that this shell runs with. */
sigset_t top_level_mask;
#endif /* JOB_CONTROL */
/* When non-zero, we throw_to_top_level (). */
int interrupt_immediately = 0;
/* When non-zero, we call the terminating signal handler immediately. */
int terminate_immediately = 0;
#if defined (SIGWINCH)
static SigHandler *old_winch = (SigHandler *)SIG_DFL;
#endif
static void initialize_shell_signals __P((void));
void
initialize_signals (reinit)
int reinit;
{
initialize_shell_signals ();
initialize_job_signals ();
#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
if (reinit == 0)
initialize_siglist ();
#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
}
/* A structure describing a signal that terminates the shell if not
caught. The orig_handler member is present so children can reset
these signals back to their original handlers. */
struct termsig {
int signum;
SigHandler *orig_handler;
int orig_flags;
};
#define NULL_HANDLER (SigHandler *)SIG_DFL
/* The list of signals that would terminate the shell if not caught.
We catch them, but just so that we can write the history file,
and so forth. */
static struct termsig terminating_signals[] = {
#ifdef SIGHUP
{ SIGHUP, NULL_HANDLER, 0 },
#endif
#ifdef SIGINT
{ SIGINT, NULL_HANDLER, 0 },
#endif
#ifdef SIGILL
{ SIGILL, NULL_HANDLER, 0 },
#endif
#ifdef SIGTRAP
{ SIGTRAP, NULL_HANDLER, 0 },
#endif
#ifdef SIGIOT
{ SIGIOT, NULL_HANDLER, 0 },
#endif
#ifdef SIGDANGER
{ SIGDANGER, NULL_HANDLER, 0 },
#endif
#ifdef SIGEMT
{ SIGEMT, NULL_HANDLER, 0 },
#endif
#ifdef SIGFPE
{ SIGFPE, NULL_HANDLER, 0 },
#endif
#ifdef SIGBUS
{ SIGBUS, NULL_HANDLER, 0 },
#endif
#ifdef SIGSEGV
{ SIGSEGV, NULL_HANDLER, 0 },
#endif
#ifdef SIGSYS
{ SIGSYS, NULL_HANDLER, 0 },
#endif
#ifdef SIGPIPE
{ SIGPIPE, NULL_HANDLER, 0 },
#endif
#ifdef SIGALRM
{ SIGALRM, NULL_HANDLER, 0 },
#endif
#ifdef SIGTERM
{ SIGTERM, NULL_HANDLER, 0 },
#endif
#ifdef SIGXCPU
{ SIGXCPU, NULL_HANDLER, 0 },
#endif
#ifdef SIGXFSZ
{ SIGXFSZ, NULL_HANDLER, 0 },
#endif
#ifdef SIGVTALRM
{ SIGVTALRM, NULL_HANDLER, 0 },
#endif
#if 0
#ifdef SIGPROF
{ SIGPROF, NULL_HANDLER, 0 },
#endif
#endif
#ifdef SIGLOST
{ SIGLOST, NULL_HANDLER, 0 },
#endif
#ifdef SIGUSR1
{ SIGUSR1, NULL_HANDLER, 0 },
#endif
#ifdef SIGUSR2
{ SIGUSR2, NULL_HANDLER, 0 },
#endif
};
#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
#define XSIG(x) (terminating_signals[x].signum)
#define XHANDLER(x) (terminating_signals[x].orig_handler)
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
static int termsigs_initialized = 0;
/* Initialize signals that will terminate the shell to do some
unwind protection. For non-interactive shells, we only call
this when a trap is defined for EXIT (0) or when trap is run
to display signal dispositions. */
void
initialize_terminating_signals ()
{
register int i;
#if defined (HAVE_POSIX_SIGNALS)
struct sigaction act, oact;
#endif
itrace("initialize_terminating_signals: termsigs_initialized = %d", termsigs_initialized);
if (termsigs_initialized)
return;
/* The following code is to avoid an expensive call to
set_signal_handler () for each terminating_signals. Fortunately,
this is possible in Posix. Unfortunately, we have to call signal ()
on non-Posix systems for each signal in terminating_signals. */
#if defined (HAVE_POSIX_SIGNALS)
act.sa_handler = termsig_sighandler;
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
sigemptyset (&oact.sa_mask);
for (i = 0; i < TERMSIGS_LENGTH; i++)
sigaddset (&act.sa_mask, XSIG (i));
for (i = 0; i < TERMSIGS_LENGTH; i++)
{
/* If we've already trapped it, don't do anything. */
if (signal_is_trapped (XSIG (i)))
continue;
sigaction (XSIG (i), &act, &oact);
XHANDLER(i) = oact.sa_handler;
XSAFLAGS(i) = oact.sa_flags;
/* Don't do anything with signals that are ignored at shell entry
if the shell is not interactive. */
/* XXX - should we do this for interactive shells, too? */
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
{
sigaction (XSIG (i), &oact, &act);
set_signal_ignored (XSIG (i));
}
#if defined (SIGPROF) && !defined (_MINIX)
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
#endif /* SIGPROF && !_MINIX */
}
#else /* !HAVE_POSIX_SIGNALS */
for (i = 0; i < TERMSIGS_LENGTH; i++)
{
/* If we've already trapped it, don't do anything. */
if (signal_is_trapped (XSIG (i)))
continue;
XHANDLER(i) = signal (XSIG (i), termsig_sighandler);
XSAFLAGS(i) = 0;
/* Don't do anything with signals that are ignored at shell entry
if the shell is not interactive. */
/* XXX - should we do this for interactive shells, too? */
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
{
signal (XSIG (i), SIG_IGN);
set_signal_ignored (XSIG (i));
}
#ifdef SIGPROF
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
signal (XSIG (i), XHANDLER (i));
#endif
}
#endif /* !HAVE_POSIX_SIGNALS */
termsigs_initialized = 1;
}
static void
initialize_shell_signals ()
{
if (interactive)
initialize_terminating_signals ();
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
/* All shells use the signal mask they inherit, and pass it along
to child processes. Children will never block SIGCHLD, though. */
sigemptyset (&top_level_mask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
# if defined (SIGCHLD)
sigdelset (&top_level_mask, SIGCHLD);
# endif
#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
/* And, some signals that are specifically ignored by the shell. */
set_signal_handler (SIGQUIT, SIG_IGN);
if (interactive)
{
set_signal_handler (SIGINT, sigint_sighandler);
set_signal_handler (SIGTERM, SIG_IGN);
set_sigwinch_handler ();
}
}
void
reset_terminating_signals ()
{
register int i;
#if defined (HAVE_POSIX_SIGNALS)
struct sigaction act;
#endif
if (termsigs_initialized == 0)
return;
#if defined (HAVE_POSIX_SIGNALS)
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
for (i = 0; i < TERMSIGS_LENGTH; i++)
{
/* Skip a signal if it's trapped or handled specially, because the
trap code will restore the correct value. */
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
continue;
act.sa_handler = XHANDLER (i);
act.sa_flags = XSAFLAGS (i);
sigaction (XSIG (i), &act, (struct sigaction *) NULL);
}
#else /* !HAVE_POSIX_SIGNALS */
for (i = 0; i < TERMSIGS_LENGTH; i++)
{
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
continue;
signal (XSIG (i), XHANDLER (i));
}
#endif /* !HAVE_POSIX_SIGNALS */
termsigs_initialized = 0;
}
#undef XSIG
#undef XHANDLER
/* Run some of the cleanups that should be performed when we run
jump_to_top_level from a builtin command context. XXX - might want to
also call reset_parser here. */
void
top_level_cleanup ()
{
/* Clean up string parser environment. */
while (parse_and_execute_level)
parse_and_execute_cleanup ();
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
run_unwind_protects ();
loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
}
/* What to do when we've been interrupted, and it is safe to handle it. */
void
throw_to_top_level ()
{
int print_newline = 0;
if (interrupt_state)
{
print_newline = 1;
DELINTERRUPT;
}
if (interrupt_state)
return;
last_command_exit_signal = (last_command_exit_value > 128) ?
(last_command_exit_value - 128) : 0;
last_command_exit_value |= 128;
/* Run any traps set on SIGINT. */
run_interrupt_trap ();
/* Clean up string parser environment. */
while (parse_and_execute_level)
parse_and_execute_cleanup ();
#if defined (JOB_CONTROL)
give_terminal_to (shell_pgrp, 0);
#endif /* JOB_CONTROL */
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
/* This should not be necessary on systems using sigsetjmp/siglongjmp. */
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
#endif
reset_parser ();
#if defined (READLINE)
if (interactive)
bashline_reset ();
#endif /* READLINE */
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
run_unwind_protects ();
loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
if (interactive && print_newline)
{
fflush (stdout);
fprintf (stderr, "\n");
fflush (stderr);
}
/* An interrupted `wait' command in a script does not exit the script. */
if (interactive || (interactive_shell && !shell_initialized) ||
(print_newline && signal_is_trapped (SIGINT)))
jump_to_top_level (DISCARD);
else
jump_to_top_level (EXITPROG);
}
/* This is just here to isolate the longjmp calls. */
void
jump_to_top_level (value)
int value;
{
longjmp (top_level, value);
}
sighandler
termsig_sighandler (sig)
int sig;
{
/* If we get called twice with the same signal before handling it,
terminate right away. */
if (
#ifdef SIGHUP
sig != SIGHUP &&
#endif
#ifdef SIGINT
sig != SIGINT &&
#endif
#ifdef SIGDANGER
sig != SIGDANGER &&
#endif
#ifdef SIGPIPE
sig != SIGPIPE &&
#endif
#ifdef SIGALRM
sig != SIGALRM &&
#endif
#ifdef SIGTERM
sig != SIGTERM &&
#endif
#ifdef SIGXCPU
sig != SIGXCPU &&
#endif
#ifdef SIGXFSZ
sig != SIGXFSZ &&
#endif
#ifdef SIGVTALRM
sig != SIGVTALRM &&
#endif
#ifdef SIGLOST
sig != SIGLOST &&
#endif
#ifdef SIGUSR1
sig != SIGUSR1 &&
#endif
#ifdef SIGUSR2
sig != SIGUSR2 &&
#endif
sig == terminating_signal)
terminate_immediately = 1;
terminating_signal = sig;
/* XXX - should this also trigger when interrupt_immediately is set? */
if (terminate_immediately)
{
#if defined (HISTORY)
/* XXX - will inhibit history file being written */
# if defined (READLINE)
if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0))
# endif
history_lines_this_session = 0;
#endif
terminate_immediately = 0;
termsig_handler (sig);
}
#if defined (READLINE)
if (interactive_shell && interactive && no_line_editing == 0)
bashline_set_event_hook ();
#endif
SIGRETURN (0);
}
void
termsig_handler (sig)
int sig;
{
static int handling_termsig = 0;
/* Simple semaphore to keep this function from being executed multiple
times. Since we no longer are running as a signal handler, we don't
block multiple occurrences of the terminating signals while running. */
if (handling_termsig)
return;
handling_termsig = 1;
terminating_signal = 0; /* keep macro from re-testing true. */
/* I don't believe this condition ever tests true. */
if (sig == SIGINT && signal_is_trapped (SIGINT))
run_interrupt_trap ();
#if 0
#if defined (HISTORY)
if (interactive_shell && (sig != SIGABRT && sig != SIGINT && sig != SIGHUP && sig != SIGTERM))
maybe_save_shell_history ();
#endif /* HISTORY */
#endif
#if defined (JOB_CONTROL)
if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
hangup_all_jobs ();
end_job_control ();
#endif /* JOB_CONTROL */
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
/* Reset execution context */
loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
run_exit_trap ();
set_signal_handler (sig, SIG_DFL);
kill (getpid (), sig);
}
/* What we really do when SIGINT occurs. */
sighandler
sigint_sighandler (sig)
int sig;
{
#if defined (MUST_REINSTALL_SIGHANDLERS)
signal (sig, sigint_sighandler);
#endif
/* interrupt_state needs to be set for the stack of interrupts to work
right. Should it be set unconditionally? */
if (interrupt_state == 0)
ADDINTERRUPT;
if (interrupt_immediately)
{
interrupt_immediately = 0;
last_command_exit_value = 128 + sig;
throw_to_top_level ();
}
SIGRETURN (0);
}
#if defined (SIGWINCH)
sighandler
sigwinch_sighandler (sig)
int sig;
{
#if defined (MUST_REINSTALL_SIGHANDLERS)
set_signal_handler (SIGWINCH, sigwinch_sighandler);
#endif /* MUST_REINSTALL_SIGHANDLERS */
sigwinch_received = 1;
SIGRETURN (0);
}
#endif /* SIGWINCH */
void
set_sigwinch_handler ()
{
#if defined (SIGWINCH)
old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
#endif
}
void
unset_sigwinch_handler ()
{
#if defined (SIGWINCH)
set_signal_handler (SIGWINCH, old_winch);
#endif
}
/* Signal functions used by the rest of the code. */
#if !defined (HAVE_POSIX_SIGNALS)
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
sigprocmask (operation, newset, oldset)
int operation, *newset, *oldset;
{
int old, new;
if (newset)
new = *newset;
else
new = 0;
switch (operation)
{
case SIG_BLOCK:
old = sigblock (new);
break;
case SIG_SETMASK:
old = sigsetmask (new);
break;
default:
internal_error (_("sigprocmask: %d: invalid operation"), operation);
}
if (oldset)
*oldset = old;
}
#else
#if !defined (SA_INTERRUPT)
# define SA_INTERRUPT 0
#endif
#if !defined (SA_RESTART)
# define SA_RESTART 0
#endif
SigHandler *
set_signal_handler (sig, handler)
int sig;
SigHandler *handler;
{
struct sigaction act, oact;
act.sa_handler = handler;
act.sa_flags = 0;
/* XXX - bash-4.2 */
/* We don't want a child death to interrupt interruptible system calls, even
if we take the time to reap children */
#if defined (SIGCHLD)
if (sig == SIGCHLD)
act.sa_flags |= SA_RESTART; /* XXX */
#endif
sigemptyset (&act.sa_mask);
sigemptyset (&oact.sa_mask);
sigaction (sig, &act, &oact);
return (oact.sa_handler);
}
#endif /* HAVE_POSIX_SIGNALS */
+2
View File
@@ -5332,6 +5332,8 @@ command_substitute (string, quoted)
sys_error (_("cannot make child for command substitution"));
error_exit:
last_made_pid = old_pid;
FREE (istring);
close (fildes[0]);
close (fildes[1]);
+9495
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -177,7 +177,9 @@ darwin[89]*|darwin1[012]*)
SHOBJ_CFLAGS='-fno-common'
SHOBJ_LD='MACOSX_DEPLOYMENT_TARGET=10.3 ${CC}'
# SHOBJ_LD='MACOSX_DEPLOYMENT_TARGET=10.3 ${CC}'
# we can finally kill Mac OS X 10.3
SHOBJ_LD='${CC}'
SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)'
SHLIB_LIBSUFF='dylib'
+1 -1
View File
@@ -32,7 +32,7 @@
#include "bashtypes.h"
#if !defined (HAVE_LIMITS_H)
#if !defined (HAVE_LIMITS_H) && defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
+852
View File
@@ -0,0 +1,852 @@
/* test.c - GNU test program (ksb and mjb) */
/* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
/* 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/>.
*/
/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching
binary operators. */
/* #define PATTERN_MATCHING */
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include "bashtypes.h"
#if !defined (HAVE_LIMITS_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif /* !_POSIX_VERSION */
#include "posixstat.h"
#include "filecntl.h"
#include "stat-time.h"
#include "bashintl.h"
#include "shell.h"
#include "pathexp.h"
#include "test.h"
#include "builtins/common.h"
#include <glob/strmatch.h>
#if !defined (STRLEN)
# define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
#endif
#if !defined (STREQ)
# define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
#endif /* !STREQ */
#define STRCOLLEQ(a, b) ((a)[0] == (b)[0] && strcoll ((a), (b)) == 0)
#if !defined (R_OK)
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
#endif /* R_OK */
#define EQ 0
#define NE 1
#define LT 2
#define GT 3
#define LE 4
#define GE 5
#define NT 0
#define OT 1
#define EF 2
/* The following few defines control the truth and false output of each stage.
TRUE and FALSE are what we use to compute the final output value.
SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */
#define TRUE 1
#define FALSE 0
#define SHELL_BOOLEAN(value) (!(value))
#define TEST_ERREXIT_STATUS 2
static procenv_t test_exit_buf;
static int test_error_return;
#define test_exit(val) \
do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0)
extern int sh_stat __P((const char *, struct stat *));
static int pos; /* The offset of the current argument in ARGV. */
static int argc; /* The number of arguments present in ARGV. */
static char **argv; /* The argument list. */
static int noeval;
static void test_syntax_error __P((char *, char *)) __attribute__((__noreturn__));
static void beyond __P((void)) __attribute__((__noreturn__));
static void integer_expected_error __P((char *)) __attribute__((__noreturn__));
static int unary_operator __P((void));
static int binary_operator __P((void));
static int two_arguments __P((void));
static int three_arguments __P((void));
static int posixtest __P((void));
static int expr __P((void));
static int term __P((void));
static int and __P((void));
static int or __P((void));
static int filecomp __P((char *, char *, int));
static int arithcomp __P((char *, char *, int, int));
static int patcomp __P((char *, char *, int));
static void
test_syntax_error (format, arg)
char *format, *arg;
{
builtin_error (format, arg);
test_exit (TEST_ERREXIT_STATUS);
}
/*
* beyond - call when we're beyond the end of the argument list (an
* error condition)
*/
static void
beyond ()
{
test_syntax_error (_("argument expected"), (char *)NULL);
}
/* Syntax error for when an integer argument was expected, but
something else was found. */
static void
integer_expected_error (pch)
char *pch;
{
test_syntax_error (_("%s: integer expression expected"), pch);
}
/* Increment our position in the argument list. Check that we're not
past the end of the argument list. This check is supressed if the
argument is FALSE. Made a macro for efficiency. */
#define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
#define unary_advance() do { advance (1); ++pos; } while (0)
/*
* expr:
* or
*/
static int
expr ()
{
if (pos >= argc)
beyond ();
return (FALSE ^ or ()); /* Same with this. */
}
/*
* or:
* and
* and '-o' or
*/
static int
or ()
{
int value, v2;
value = and ();
if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
{
advance (0);
v2 = or ();
return (value || v2);
}
return (value);
}
/*
* and:
* term
* term '-a' and
*/
static int
and ()
{
int value, v2;
value = term ();
if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
{
advance (0);
v2 = and ();
return (value && v2);
}
return (value);
}
/*
* term - parse a term and return 1 or 0 depending on whether the term
* evaluates to true or false, respectively.
*
* term ::=
* '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename
* '-'('G'|'L'|'O'|'S'|'N') filename
* '-t' [int]
* '-'('z'|'n') string
* '-o' option
* string
* string ('!='|'='|'==') string
* <int> '-'(eq|ne|le|lt|ge|gt) <int>
* file '-'(nt|ot|ef) file
* '(' <expr> ')'
* int ::=
* positive and negative integers
*/
static int
term ()
{
int value;
if (pos >= argc)
beyond ();
/* Deal with leading `not's. */
if (argv[pos][0] == '!' && argv[pos][1] == '\0')
{
value = 0;
while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')
{
advance (1);
value = 1 - value;
}
return (value ? !term() : term());
}
/* A paren-bracketed argument. */
if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */
{
advance (1);
value = expr ();
if (argv[pos] == 0) /* ( */
test_syntax_error (_("`)' expected"), (char *)NULL);
else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */
test_syntax_error (_("`)' expected, found %s"), argv[pos]);
advance (0);
return (value);
}
/* are there enough arguments left that this could be dyadic? */
if ((pos + 3 <= argc) && test_binop (argv[pos + 1]))
value = binary_operator ();
/* Might be a switch type argument */
else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
{
if (test_unop (argv[pos]))
value = unary_operator ();
else
test_syntax_error (_("%s: unary operator expected"), argv[pos]);
}
else
{
value = argv[pos][0] != '\0';
advance (0);
}
return (value);
}
static int
stat_mtime (fn, st, ts)
char *fn;
struct stat *st;
struct timespec *ts;
{
int r;
r = sh_stat (fn, st);
if (r < 0)
return r;
*ts = get_stat_mtime (st);
return 0;
}
static int
filecomp (s, t, op)
char *s, *t;
int op;
{
struct stat st1, st2;
struct timespec ts1, ts2;
int r1, r2;
if ((r1 = stat_mtime (s, &st1, &ts1)) < 0)
{
if (op == EF)
return (FALSE);
}
if ((r2 = stat_mtime (t, &st2, &ts2)) < 0)
{
if (op == EF)
return (FALSE);
}
switch (op)
{
case OT: return (r1 < r2 || (r2 == 0 && timespec_cmp (ts1, ts2) < 0));
case NT: return (r1 > r2 || (r1 == 0 && timespec_cmp (ts1, ts2) > 0));
case EF: return (same_file (s, t, &st1, &st2));
}
return (FALSE);
}
static int
arithcomp (s, t, op, flags)
char *s, *t;
int op, flags;
{
intmax_t l, r;
int expok;
if (flags & TEST_ARITHEXP)
{
l = evalexp (s, &expok);
if (expok == 0)
return (FALSE); /* should probably longjmp here */
r = evalexp (t, &expok);
if (expok == 0)
return (FALSE); /* ditto */
}
else
{
if (legal_number (s, &l) == 0)
integer_expected_error (s);
if (legal_number (t, &r) == 0)
integer_expected_error (t);
}
switch (op)
{
case EQ: return (l == r);
case NE: return (l != r);
case LT: return (l < r);
case GT: return (l > r);
case LE: return (l <= r);
case GE: return (l >= r);
}
return (FALSE);
}
static int
patcomp (string, pat, op)
char *string, *pat;
int op;
{
int m;
m = strmatch (pat, string, FNMATCH_EXTFLAG|FNMATCH_IGNCASE);
return ((op == EQ) ? (m == 0) : (m != 0));
}
int
binary_test (op, arg1, arg2, flags)
char *op, *arg1, *arg2;
int flags;
{
int patmatch;
patmatch = (flags & TEST_PATMATCH);
if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0')))
return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2));
else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0')
{
if (shell_compatibility_level > 40 && flags & TEST_LOCALE)
return ((op[0] == '>') ? (strcoll (arg1, arg2) > 0) : (strcoll (arg1, arg2) < 0));
else
return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0));
}
else if (op[0] == '!' && op[1] == '=' && op[2] == '\0')
return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0));
else if (op[2] == 't')
{
switch (op[1])
{
case 'n': return (filecomp (arg1, arg2, NT)); /* -nt */
case 'o': return (filecomp (arg1, arg2, OT)); /* -ot */
case 'l': return (arithcomp (arg1, arg2, LT, flags)); /* -lt */
case 'g': return (arithcomp (arg1, arg2, GT, flags)); /* -gt */
}
}
else if (op[1] == 'e')
{
switch (op[2])
{
case 'f': return (filecomp (arg1, arg2, EF)); /* -ef */
case 'q': return (arithcomp (arg1, arg2, EQ, flags)); /* -eq */
}
}
else if (op[2] == 'e')
{
switch (op[1])
{
case 'n': return (arithcomp (arg1, arg2, NE, flags)); /* -ne */
case 'g': return (arithcomp (arg1, arg2, GE, flags)); /* -ge */
case 'l': return (arithcomp (arg1, arg2, LE, flags)); /* -le */
}
}
return (FALSE); /* should never get here */
}
static int
binary_operator ()
{
int value;
char *w;
w = argv[pos + 1];
if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */
((w[0] == '>' || w[0] == '<') && w[1] == '\0') || /* <, > */
(w[0] == '!' && w[1] == '=' && w[2] == '\0')) /* != */
{
value = binary_test (w, argv[pos], argv[pos + 2], 0);
pos += 3;
return (value);
}
#if defined (PATTERN_MATCHING)
if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0')
{
value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE);
pos += 3;
return (value);
}
#endif
if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0)
{
test_syntax_error (_("%s: binary operator expected"), w);
/* NOTREACHED */
return (FALSE);
}
value = binary_test (w, argv[pos], argv[pos + 2], 0);
pos += 3;
return value;
}
static int
unary_operator ()
{
char *op;
intmax_t r;
op = argv[pos];
if (test_unop (op) == 0)
return (FALSE);
/* the only tricky case is `-t', which may or may not take an argument. */
if (op[1] == 't')
{
advance (0);
if (pos < argc)
{
if (legal_number (argv[pos], &r))
{
advance (0);
return (unary_test (op, argv[pos - 1]));
}
else
return (FALSE);
}
else
return (unary_test (op, "1"));
}
/* All of the unary operators take an argument, so we first call
unary_advance (), which checks to make sure that there is an
argument, and then advances pos right past it. This means that
pos - 1 is the location of the argument. */
unary_advance ();
return (unary_test (op, argv[pos - 1]));
}
int
unary_test (op, arg)
char *op, *arg;
{
intmax_t r;
struct stat stat_buf;
SHELL_VAR *v;
switch (op[1])
{
case 'a': /* file exists in the file system? */
case 'e':
return (sh_stat (arg, &stat_buf) == 0);
case 'r': /* file is readable? */
return (sh_eaccess (arg, R_OK) == 0);
case 'w': /* File is writeable? */
return (sh_eaccess (arg, W_OK) == 0);
case 'x': /* File is executable? */
return (sh_eaccess (arg, X_OK) == 0);
case 'O': /* File is owned by you? */
return (sh_stat (arg, &stat_buf) == 0 &&
(uid_t) current_user.euid == (uid_t) stat_buf.st_uid);
case 'G': /* File is owned by your group? */
return (sh_stat (arg, &stat_buf) == 0 &&
(gid_t) current_user.egid == (gid_t) stat_buf.st_gid);
case 'N':
return (sh_stat (arg, &stat_buf) == 0 &&
stat_buf.st_atime <= stat_buf.st_mtime);
case 'f': /* File is a file? */
if (sh_stat (arg, &stat_buf) < 0)
return (FALSE);
/* -f is true if the given file exists and is a regular file. */
#if defined (S_IFMT)
return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0);
#else
return (S_ISREG (stat_buf.st_mode));
#endif /* !S_IFMT */
case 'd': /* File is a directory? */
return (sh_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode)));
case 's': /* File has something in it? */
return (sh_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0);
case 'S': /* File is a socket? */
#if !defined (S_ISSOCK)
return (FALSE);
#else
return (sh_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode));
#endif /* S_ISSOCK */
case 'c': /* File is character special? */
return (sh_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode));
case 'b': /* File is block special? */
return (sh_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode));
case 'p': /* File is a named pipe? */
#ifndef S_ISFIFO
return (FALSE);
#else
return (sh_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode));
#endif /* S_ISFIFO */
case 'L': /* Same as -h */
case 'h': /* File is a symbolic link? */
#if !defined (S_ISLNK) || !defined (HAVE_LSTAT)
return (FALSE);
#else
return ((arg[0] != '\0') &&
(lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode));
#endif /* S_IFLNK && HAVE_LSTAT */
case 'u': /* File is setuid? */
return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0);
case 'g': /* File is setgid? */
return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0);
case 'k': /* File has sticky bit set? */
#if !defined (S_ISVTX)
/* This is not Posix, and is not defined on some Posix systems. */
return (FALSE);
#else
return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0);
#endif
case 't': /* File fd is a terminal? */
if (legal_number (arg, &r) == 0)
return (FALSE);
return ((r == (int)r) && isatty ((int)r));
case 'n': /* True if arg has some length. */
return (arg[0] != '\0');
case 'z': /* True if arg has no length. */
return (arg[0] == '\0');
case 'o': /* True if option `arg' is set. */
return (minus_o_option_value (arg) == 1);
case 'v':
v = find_variable (arg);
return (v && var_isset (v) ? TRUE : FALSE);
}
/* We can't actually get here, but this shuts up gcc. */
return (FALSE);
}
/* Return TRUE if OP is one of the test command's binary operators. */
int
test_binop (op)
char *op;
{
if (op[0] == '=' && op[1] == '\0')
return (1); /* '=' */
else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0') /* string <, > */
return (1);
else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0')
return (1); /* `==' and `!=' */
#if defined (PATTERN_MATCHING)
else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!'))
return (1);
#endif
else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0')
return (0);
else
{
if (op[2] == 't')
switch (op[1])
{
case 'n': /* -nt */
case 'o': /* -ot */
case 'l': /* -lt */
case 'g': /* -gt */
return (1);
default:
return (0);
}
else if (op[1] == 'e')
switch (op[2])
{
case 'q': /* -eq */
case 'f': /* -ef */
return (1);
default:
return (0);
}
else if (op[2] == 'e')
switch (op[1])
{
case 'n': /* -ne */
case 'g': /* -ge */
case 'l': /* -le */
return (1);
default:
return (0);
}
else
return (0);
}
}
/* Return non-zero if OP is one of the test command's unary operators. */
int
test_unop (op)
char *op;
{
if (op[0] != '-' || op[2] != 0)
return (0);
switch (op[1])
{
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'k': case 'n':
case 'o': case 'p': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'z':
case 'G': case 'L': case 'O': case 'S': case 'N':
return (1);
}
return (0);
}
static int
two_arguments ()
{
if (argv[pos][0] == '!' && argv[pos][1] == '\0')
return (argv[pos + 1][0] == '\0');
else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
{
if (test_unop (argv[pos]))
return (unary_operator ());
else
test_syntax_error (_("%s: unary operator expected"), argv[pos]);
}
else
test_syntax_error (_("%s: unary operator expected"), argv[pos]);
return (0);
}
#define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o'))
/* This could be augmented to handle `-t' as equivalent to `-t 1', but
POSIX requires that `-t' be given an argument. */
#define ONE_ARG_TEST(s) ((s)[0] != '\0')
static int
three_arguments ()
{
int value;
if (test_binop (argv[pos+1]))
{
value = binary_operator ();
pos = argc;
}
else if (ANDOR (argv[pos+1]))
{
if (argv[pos+1][1] == 'a')
value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]);
else
value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]);
pos = argc;
}
else if (argv[pos][0] == '!' && argv[pos][1] == '\0')
{
advance (1);
value = !two_arguments ();
}
else if (argv[pos][0] == '(' && argv[pos+2][0] == ')')
{
value = ONE_ARG_TEST(argv[pos+1]);
pos = argc;
}
else
test_syntax_error (_("%s: binary operator expected"), argv[pos+1]);
return (value);
}
/* This is an implementation of a Posix.2 proposal by David Korn. */
static int
posixtest ()
{
int value;
switch (argc - 1) /* one extra passed in */
{
case 0:
value = FALSE;
pos = argc;
break;
case 1:
value = ONE_ARG_TEST(argv[1]);
pos = argc;
break;
case 2:
value = two_arguments ();
pos = argc;
break;
case 3:
value = three_arguments ();
break;
case 4:
if (argv[pos][0] == '!' && argv[pos][1] == '\0')
{
advance (1);
value = !three_arguments ();
break;
}
/* FALLTHROUGH */
default:
value = expr ();
}
return (value);
}
/*
* [:
* '[' expr ']'
* test:
* test expr
*/
int
test_command (margc, margv)
int margc;
char **margv;
{
int value;
int code;
USE_VAR(margc);
code = setjmp (test_exit_buf);
if (code)
return (test_error_return);
argv = margv;
if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0')
{
--margc;
if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
test_syntax_error (_("missing `]'"), (char *)NULL);
if (margc < 2)
test_exit (SHELL_BOOLEAN (FALSE));
}
argc = margc;
pos = 1;
if (pos >= argc)
test_exit (SHELL_BOOLEAN (FALSE));
noeval = 0;
value = posixtest ();
if (pos != argc)
test_syntax_error (_("too many arguments"), (char *)NULL);
test_exit (SHELL_BOOLEAN (value));
}
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+9
View File
@@ -0,0 +1,9 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
export THIS_SH PATH
rm -f /tmp/xx
/bin/sh "$@"
+1 -1
View File
@@ -8,7 +8,7 @@ unalias: usage: unalias [-a] name [name ...]
declare -fr func
./errors.tests: line 36: func: readonly function
./errors.tests: line 39: unset: -x: invalid option
unset: usage: unset [-f] [-v] [name ...]
unset: usage: unset [-f] [-v] [-n] [name ...]
./errors.tests: line 42: unset: func: cannot unset: readonly function
./errors.tests: line 45: declare: func: readonly function
./errors.tests: line 49: unset: XPATH: cannot unset: readonly variable
+1151
View File
File diff suppressed because it is too large Load Diff