commit bash-20161028 snapshot

This commit is contained in:
Chet Ramey
2016-11-03 17:28:23 -04:00
parent 628bb7b79b
commit 553a7d66e4
30 changed files with 1077 additions and 74 deletions
+127
View File
@@ -12013,3 +12013,130 @@ variables.c
doc/{bash.1,bashref.texi}
- BASHPID: note that assignments are ignored and unsetting BASHPID
causes it to lose its special properties
10/28
-----
builtins/pushd.def
- popd_builtin: make sure to check the normalized stack offset
(i.e., negatives counting back from the end of the stack) is within
bounds before trying to free that stack entry. Report from
Fernando Muñoz <fernando@null-life.com>
lib/readline/histfile.c
- chown: protect calls with HAVE_CHOWN. Fixes for MinGW{64,32} from
J. Peter Mugaas <jpmugaas@suddenlink.net>
lib/readline/colors.c
- S_ISDIR: add define if missing
- S_ISUID, S_ISGID, S_ISLNK, S_ISSOCK: don't use unless defined.
Fixes for MinGW{64,32} from J. Peter Mugaas <jpmugaas@suddenlink.net>
bashhist.c
- current_command_line_comment: set to the most recent line in a
possibly multi-line command that contains a shell comment; set in
maybe_add_history and bash_add_history to either the current
command number or -2
- maybe_add_history: set current_command_line_comment for first line
of command
- bash_add_history: chars_to_add set to "\n" if the current command line
is one greater than the previous line containing a comment
(current_command_line_comment). Fixes complaint from back in
January, 2016 from Dave Rutherford <dave@evilpettingzoo.com>
array.h
- lastref: move last-referenced pointer into each array struct, so all
arrays can have reference locality
array.c
- array_create: set lastref element to 0
- array_copy: if copying the lastref in array a, set the new lastref
in the copy to the same element
- IS_LASTREF, LASTREF_START, LASTREF, INVALIDATE_LASTREF, SET_LASTREF,
UNSET_LASTREF: change to use new array `lastref' member
pathexp.c
- quote_string_for_globbing: if quoting for a regexp, make sure to
skip and copy a leading `^' in a bracket expression, and skip and
copy a subsequent `]' (after an optional `^'), so that leading
bracket doesn't close the bracket expression. Report from
Stephane Chazelas <stephane.chazelas@gmail.com>
10/29
-----
subst.c
- extract_delimited_string: add calls to CHECK_STRING_OVERRUN for
$( inside $((, nested OPENERs, nested ALT_OPENERs, and backquotes
- skip_to_delim: add calls to CHECK_STRING_OVERRUN for $(, ${,
process substitution
- extract_dollar_brace_string: add calls to CHECK_STRING_OVERRUN for
$(
- extract_dollar_brace_string: use skipsubscript to skip over the
array subscript in ${var[sub]} (non-quoted case uses string_extract,
which already uses skipsubscript). Tagged for bash-5.0
10/30
-----
variables.c
- EPOCHSECONDS: new dynamic variable, time in seconds since Unix
epoch; assignments are ignored. Can be used on systems where
strftime() doesn't support '%s'
- EPOCHREALTIME: new dynamic variable, time in seconds since Unix
epoch with microsecond granularity
doc/{bash.1,bashref.texi}
- EPOCHSECONDS documentation
- EPOCHREALTIME documentation
execute_cmd.c
- decpoint: moved to locale.c, renamed locale_decpoint; changed callers
{bashintl,externs}.h
- locale_decpoint: extern declaration or #define if support for
localeconv() not there
10/31
-----
lib/malloc/malloc.c
- posix_memalign: add new posix-mandated interface
examples/loadables/rm.c
- rm: minimal loadable builtin, removes files and directories, only
handles -r and -f options. Original from Tim Ruehsen
<tim.ruehsen@gmx.de>, heavily rewritten for inclusion as loadable
examples/loadables/Makefile.in
- rm: add rules to build rm as one of the standard targets
examples/loadables/stat.c
- stat: new loadable builtin that takes a filename and loads the info
returned by stat(2) into an associative array specified by the -A
argument (default STAT)
11/1
----
variables.c
- BASH_ARGV0: new dynamic variable, returns $0 on reference and sets
$0 on assignment. From a suggestion from Rocky Bernstein <rocky@gnu.org>
a few years ago
doc/{bash.1,bashref.texi}
- BASH_ARGV0: document
11/2
----
lib/glob/sm_loop.c
- parse_collsym: make sure to not return an out-of-bounds read if a
collating symbol is unterminated. Fixes OOB read reported by
op7ic \x00 <op7ica@gmail.com>
- brackmatch: after incrementing p, before checking whether it's a
character range, check whether *p was NULL before the increment
and short-circuit the bracket expression if it is
jobs.c
- discard_last_procsub_child: new function, safely discards
last_procsub_child and sets it to NULL
subst.c
- process_substitute: call discard_last_procsub_child instead of
calling discard_pipeline directly. Fixes bug reported by
Christian Weisgerber <naddy@mips.inka.de>
+2
View File
@@ -681,6 +681,7 @@ examples/loadables/dirname.c f
examples/loadables/tty.c f
examples/loadables/pathchk.c f
examples/loadables/tee.c f
examples/loadables/rm.c f
examples/loadables/rmdir.c f
examples/loadables/head.c f
examples/loadables/printenv.c f
@@ -693,6 +694,7 @@ examples/loadables/mkdir.c f
examples/loadables/ln.c f
examples/loadables/mypid.c f
examples/loadables/unlink.c f
examples/loadables/stat.c f
examples/loadables/perl/Makefile.in f
examples/loadables/perl/README f
examples/loadables/perl/bperl.c f
+11 -30
View File
@@ -63,39 +63,17 @@
static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int));
/* lastref should be moved into the array structure so each array can be
optimized separately */
static ARRAY *lastarray = 0;
static ARRAY_ELEMENT *lastref = 0;
#define IS_LASTREF(a) (lastarray && (a) == lastarray)
#define IS_LASTREF(a) (a->lastref)
#define LASTREF_START(a, i) \
(IS_LASTREF(a) && i >= element_index(lastref)) ? lastref \
: element_forw(a->head)
(IS_LASTREF(a) && i >= element_index(a->lastref)) ? a->lastref \
: element_forw(a->head)
#define LASTREF(a) IS_LASTREF(a) ? lastref : element_forw(a->head)
#define LASTREF(a) (a->lastref ? a->lastref : element_forw(a->head))
#define INVALIDATE_LASTREF(a) \
do { \
if ((a) == lastarray) { \
lastarray = 0; \
lastref = 0; \
} \
} while (0)
#define SET_LASTREF(a, e) \
do { \
lastarray = (a); \
lastref = (e); \
} while (0)
#define UNSET_LASTREF(a) \
do { \
lastarray = 0; \
lastref = 0; \
} while (0)
#define INVALIDATE_LASTREF(a) a->lastref = 0
#define SET_LASTREF(a, e) a->lastref = (e)
#define UNSET_LASTREF(a) a->lastref = 0;
ARRAY *
array_create()
@@ -107,6 +85,7 @@ array_create()
r->type = array_indexed;
r->max_index = -1;
r->num_elements = 0;
r->lastref = (ARRAY_ELEMENT *)0;
head = array_create_element(-1, (char *)NULL); /* dummy head */
head->prev = head->next = head;
r->head = head;
@@ -159,6 +138,8 @@ ARRAY *a;
for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
new = array_create_element(element_index(ae), element_value(ae));
ADD_BEFORE(a1->head, new);
if (ae == LASTREF(a))
SET_LASTREF(a1, new);
}
return(a1);
}
@@ -722,7 +703,7 @@ arrayind_t i;
if (a == 0 || array_empty(a))
return((ARRAY_ELEMENT *) NULL);
if (i > array_max_index(a) || i < array_first_index(a))
return((char *)NULL); /* Keep roving pointer into array to optimize sequential access */
return((ARRAY_ELEMENT *)NULL); /* Keep roving pointer into array to optimize sequential access */
start = LASTREF(a);
/* Use same strategy as array_reference to avoid paying large penalty
for semi-random assignment pattern. */
+1
View File
@@ -33,6 +33,7 @@ typedef struct array {
enum atype type;
arrayind_t max_index;
int num_elements;
struct array_element *lastref;
struct array_element *head;
} ARRAY;
+4 -2
View File
@@ -1086,15 +1086,17 @@ array_value_internal (s, quoted, flags, rtype, indp)
return ((char *) NULL);
}
/* Caller of array_value takes care of inspecting rtype and duplicating
retval if rtype == 0, so this is not a memory leak */
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
{
temp = string_list_dollar_star (l);
retval = quote_string (temp); /* XXX - leak here */
retval = quote_string (temp);
free (temp);
}
else /* ${name[@]} or unquoted ${name[*]} */
/* XXX - bash-4.4/bash-5.0 test AV_ASSIGNRHS and pass PF_ASSIGNRHS */
retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); /* XXX - leak here */
retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
dispose_words (l);
}
+24 -4
View File
@@ -140,6 +140,11 @@ int command_oriented_history = 1;
the history-manipluating builtins can see it. */
int current_command_first_line_saved = 0;
/* Set to the number of the most recent line of a possibly-multi-line command
that contains a shell comment. Used by bash_add_history() to determine
whether to add a newline or a semicolon. */
int current_command_line_comment = 0;
/* Non-zero means to store newlines in the history list when using
command_oriented_history rather than trying to use semicolons. */
int literal_history;
@@ -597,16 +602,24 @@ pre_process_line (line, print_changes, addit)
}
/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
* that the line is a shell comment. */
that the line is a shell comment. Return 2 if there is a comment after the
first non-whitespace character. Return 0 if the line does not contain a
comment. */
static int
shell_comment (line)
char *line;
{
char *p;
int n;
if (line == 0)
return 0;
for (p = line; p && *p && whitespace (*p); p++)
;
return (p && *p == '#');
if (p && *p == '#')
return 1;
n = skip_to_delim (line, p - line, "#", SD_NOJMP|SD_GLOB|SD_EXTGLOB|SD_COMPLETE);
return (line[n] == '#') ? 2 : 0;
}
#ifdef INCLUDE_UNUSED
@@ -708,13 +721,14 @@ maybe_add_history (line)
if (current_command_line_count > 1)
{
if (current_command_first_line_saved &&
((parser_state & PST_HEREDOC) || literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
((parser_state & PST_HEREDOC) || literal_history || dstack.delimiter_depth != 0 || shell_comment (line) != 1))
bash_add_history (line);
return;
}
/* This is the first line of a (possible multi-line) command. Note whether
or not we should save the first line and remember it. */
current_command_line_comment = shell_comment (line) ? current_command_line_count : -2;
current_command_first_line_saved = check_add_history (line, 0);
}
@@ -803,12 +817,18 @@ bash_add_history (line)
so we have to duplicate some of what that function does here. */
if ((parser_state & PST_HEREDOC) && literal_history && current_command_line_count > 2 && line[strlen (line) - 1] == '\n')
chars_to_add = "";
else if (current_command_line_count == current_command_line_comment+1)
chars_to_add = "\n";
else if (literal_history)
chars_to_add = "\n";
else
chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
chars_to_add = history_delimiting_chars (line);
using_history ();
current = previous_history ();
current_command_line_comment = shell_comment (line) ? current_command_line_count : -2;
if (current)
{
/* If the previous line ended with an escaped newline (escaped
+4
View File
@@ -47,4 +47,8 @@
# define setlocale(cat, loc)
#endif
#if !defined (HAVE_LOCALE_H) || !defined (HAVE_LOCALECONV)
# define locale_decpoint() '.'
#endif
#endif /* !_BASHINTL_H_ */
-6
View File
@@ -139,19 +139,13 @@ optimize_subshell_command (command)
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0))
{
itrace("optimize_subshell_command: optimizing simple command");
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
else if (command->type == cm_connection &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR))
{
itrace("optimize_subshell_command: attempting to optimize connection");
optimize_subshell_command (command->value.Connection->second);
}
else
itrace("optimize_subshell_command: command type = %d", command->type);
}
/* How to force parse_and_execute () to clean up after itself. */
void
+6 -1
View File
@@ -365,7 +365,7 @@ popd_builtin (list)
break;
}
if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
if (which > directory_list_offset || (which < -directory_list_offset) || (directory_list_offset == 0 && which == 0))
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
@@ -387,6 +387,11 @@ popd_builtin (list)
remove that directory from the list and shift the remainder
of the list into place. */
i = (direction == '+') ? directory_list_offset - which : which;
if (i < 0 || i > directory_list_offset)
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
free (pushd_directory_list[i]);
directory_list_offset--;
+45 -2
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Tue Sep 27 14:02:28 EDT 2016
.\" Last Change: Tue Nov 1 16:05:17 EDT 2016
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2016 September 27" "GNU Bash 4.4"
.TH BASH 1 "2016 November 1" "GNU Bash 4.4"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -1509,6 +1509,19 @@ option to the
.B shopt
builtin below)
.TP
.B BASH_ARGV0
When referenced, this variable expands to the name of the shell or shell
script (identical to
.BR $0 ;
see the description of special parameter 0 above).
Assignment to
.B BASH_ARGV0
causes the value assigned to also be assigned to \fB$0\fP.
If
.B BASH_ARGV0
is unset, it loses its special properties, even if it is
subsequently reset.
.TP
.B BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the \fBhash\fP builtin.
@@ -1695,6 +1708,33 @@ If
is unset, it loses its special properties, even if it is
subsequently reset.
.TP
.B EPOCHREALTIME
Each time this parameter is referenced, it expands to the number of seconds
since the Unix Epoch (see \fItime\fP\fR(3)\fP) as a floating point value
with micro-second granularity.
Assignments to
.SM
.B EPOCHREALTIME
are ignored.
If
.SM
.B EPOCHREALTIME
is unset, it loses its special properties, even if it is
subsequently reset.
.TP
.B EPOCHSECONDS
Each time this parameter is referenced, it expands to the number of seconds
since the Unix Epoch (see \fItime\fP\fR(3)\fP).
Assignments to
.SM
.B EPOCHSECONDS
are ignored.
If
.SM
.B EPOCHSECONDS
is unset, it loses its special properties, even if it is
subsequently reset.
.TP
.B EUID
Expands to the effective user ID of the current user, initialized at
shell startup. This variable is readonly.
@@ -3704,6 +3744,9 @@ than or equal to 10 and assign it to \fIvarname\fP.
If >&- or <&- is preceded
by {\fIvarname\fP}, the value of \fIvarname\fP defines the file
descriptor to close.
If {\fIvarname\fP} is supplied, the redirection persists beyond
the scope of the command, allowing the shell programmer to manage
the file descriptor himself.
.PP
In the following descriptions, if the file descriptor number is
omitted, and the first character of the redirection operator is
+30
View File
@@ -2567,6 +2567,9 @@ In this case, for each redirection operator except
than 10 and assign it to @{@var{varname}@}. If >&- or <&- is preceded
by @{@var{varname}@}, the value of @var{varname} defines the file
descriptor to close.
If @{@var{varname}@} is supplied, the redirection persists beyond
the scope of the command, allowing the shell programmer to manage
the file descriptor himself.
In the following descriptions, if the file descriptor number is
omitted, and the first character of the redirection operator is
@@ -5519,6 +5522,16 @@ The shell sets @code{BASH_ARGV} only when in extended debugging mode
for a description of the @code{extdebug} option to the @code{shopt}
builtin).
@item BASH_ARGV0
When referenced, this variable expands to the name of the shell or shell
script (identical to @code{$0}; @xref{Special Parameters},
for the description of special parameter 0).
Assignment to @code{BASH_ARGV0}
causes the value assigned to also be assigned to @code{$0}.
If @code{BASH_ARGV0}
is unset, it loses its special properties, even if it is
subsequently reset.
@item BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the @code{hash} builtin
@@ -5734,6 +5747,23 @@ Emacs shell buffer and disables line editing.
Similar to @code{BASH_ENV}; used when the shell is invoked in
@sc{posix} Mode (@pxref{Bash POSIX Mode}).
@item EPOCHREALTIME
Each time this parameter is referenced, it expands to the number of seconds
since the Unix Epoch as a floating point value with micro-second granularity
(see the documentation for the C library function @var{time} for the
definition of Epoch).
Assignments to @env{EPOCHREALTIME} are ignored.
If @env{EPOCHREALTIME} is unset, it loses its special properties, even if
it is subsequently reset.
@item EPOCHSECONDS
Each time this parameter is referenced, it expands to the number of seconds
since the Unix Epoch (see the documentation for the C library function
@var{time} for the definition of Epoch).
Assignments to @env{EPOCHSECONDS} are ignored.
If @env{EPOCHSECONDS} is unset, it loses its special properties, even if
it is subsequently reset.
@item EUID
The numeric effective user id of the current user. This variable
is readonly.
+3 -3
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2016 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Tue Sep 27 14:02:09 EDT 2016
@set LASTCHANGE Tue Nov 1 16:08:43 EDT 2016
@set EDITION 4.4
@set VERSION 4.4
@set UPDATED 27 September 2016
@set UPDATED-MONTH September 2016
@set UPDATED 1 November 2016
@set UPDATED-MONTH November 2016
+8 -2
View File
@@ -103,7 +103,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid
OTHERPROG = necho hello cat pushd
OTHERPROG = necho hello cat pushd stat rm
all: $(SHOBJ_STATUS)
@@ -142,6 +142,9 @@ finfo: finfo.o
cat: cat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
rm: rm.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rm.o $(SHOBJ_LIBS)
logname: logname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
@@ -202,10 +205,12 @@ strftime: strftime.o
mypid: mypid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS)
setpgid: setpgid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ setpgid.o $(SHOBJ_LIBS)
stat: stat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ stat.o $(SHOBJ_LIBS)
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -283,3 +288,4 @@ mkdir.o: mkdir.c
realpath.o: realpath.c
strftime.o: strftime.c
setpgid.o: setpgid.c
stat.o: stat.c
+1
View File
@@ -52,6 +52,7 @@ printenv.c Minimal builtin clone of BSD printenv(1).
push.c Anyone remember TOPS-20?
README README
realpath.c Canonicalize pathnames, resolving symlinks.
rm.c Remove files and directories.
rmdir.c Remove directory.
sleep.c sleep for fractions of a second.
strftime.c Loadable builtin interface to strftime(3).
+2
View File
@@ -56,6 +56,7 @@ int fd;
return 0;
}
int
cat_main (argc, argv)
int argc;
char **argv;
@@ -88,6 +89,7 @@ char **argv;
return (r);
}
int
cat_builtin(list)
WORD_LIST *list;
{
+175
View File
@@ -0,0 +1,175 @@
/* rm - remove files and directories with -r */
/* See Makefile for compilation details. */
/*
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Bash.
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 <dirent.h>
#include "builtins.h"
#include "shell.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
static int rm_file(const char *fname);
static int force, recursive;
static int
_remove_directory(const char *dirname)
{
DIR *dir;
struct dirent *dp;
size_t dirlen;
int err;
dirlen = strlen (dirname);
err = 0;
if ((dir = opendir(dirname)))
{
while ((dp = readdir(dir)))
{
#ifdef __GNUC__
char fname[dirlen + 1 + strlen (dp->d_name) + 1];
#else
char *fname;
int fnsize;
#endif
if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
continue;
#ifdef __GNUC__
snprintf(fname, sizeof (fname), "%s/%s", dirname, dp->d_name);
#else
fnsize = dirlen + 1 + strlen (dp->d_name) + 1;
fname = xmalloc (fnsize);
snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);
#endif
if (rm_file (fname) && force == 0)
err = 1;
#ifndef __GNUC__
free (fname);
#endif
}
closedir(dir);
if (err == 0 && rmdir (dirname) && force == 0)
err = 1;
}
else if (force == 0)
err = 1;
if (err)
builtin_error ("%s: %s", dirname, strerror (errno));
return err;
}
static int
rm_file(const char *fname)
{
if (unlink (fname) == 0)
return 0;
/* If FNAME is a directory glibc returns EISDIR but correct POSIX value
would be EPERM. If we get that error and FNAME is a directory and -r
was supplied, recursively remove the directory and its contents */
if ((errno == EISDIR || errno == EPERM) && recursive && file_isdir (fname))
return _remove_directory(fname);
else if (force)
return 0;
builtin_error ("%s: %s", fname, strerror (errno));
return 1;
}
int
rm_builtin (list)
WORD_LIST *list;
{
const char *name;
WORD_LIST *l;
int rval, opt;
recursive = force = 0;
rval = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "Rrf")) != -1)
{
switch (opt)
{
case 'R':
case 'r':
recursive = 1;
break;
case 'f':
force = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
}
for (l = list; l; l = l->next)
{
if (rm_file(l->word->word) && force == 0)
rval = EXECUTION_FAILURE;
}
return rval;
}
char *rm_doc[] = {
"Remove files.",
"",
"rm removes the files specified as arguments.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin rm_struct = {
"rm", /* builtin name */
rm_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
rm_doc, /* array of long documentation strings. */
"rm [-rf] file ...", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+430
View File
@@ -0,0 +1,430 @@
/* stat - load up an associative array with stat information about a file */
/* See Makefile for compilation details. */
/*
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Bash.
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)
# include <unistd.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include "posixstat.h"
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include "posixtime.h"
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "common.h"
#include "bashgetopt.h"
#ifndef errno
extern int errno;
#endif
#define ST_NAME 0
#define ST_DEV 1
#define ST_INO 2
#define ST_MODE 3
#define ST_NLINK 4
#define ST_UID 5
#define ST_GID 6
#define ST_RDEV 7
#define ST_SIZE 8
#define ST_ATIME 9
#define ST_MTIME 10
#define ST_CTIME 11
#define ST_BLKSIZE 12
#define ST_BLOCKS 13
#define ST_CHASELINK 14
#define ST_PERMS 15
#define ST_END 16
static char *arraysubs[] =
{
"name", "device", "inode", "type", "nlink", "uid", "gid", "rdev",
"size", "atime", "mtime", "ctime", "blksize", "blocks", "link", "perms",
0
};
static int
getstat (fname, flags, sp)
const char *fname;
int flags;
struct stat *sp;
{
intmax_t lfd;
int fd, r;
if (strncmp (fname, "/dev/fd/", 8) == 0)
{
if ((legal_number(fname + 8, &lfd) == 0) || (int)lfd != lfd)
{
errno = EINVAL;
return -1;
}
fd = lfd;
r = fstat(fd, sp);
}
#ifdef HAVE_LSTAT
else if (flags & 1)
r = lstat(fname, sp);
#endif
else
r = stat(fname, sp);
return r;
}
static char *
statlink (fname, sp)
char *fname;
struct stat *sp;
{
#if defined (HAVE_READLINK)
char linkbuf[PATH_MAX];
int n;
if (fname && S_ISLNK (sp->st_mode) && (n = readlink (fname, linkbuf, PATH_MAX)) > 0)
{
linkbuf[n] = '\0';
return (savestring (linkbuf));
}
else
#endif
return (savestring (fname));
}
static char *
octalperms (m)
int m;
{
int operms;
char *ret;
operms = 0;
if (m & S_IRUSR)
operms |= 0400;
if (m & S_IWUSR)
operms |= 0200;
if (m & S_IXUSR)
operms |= 0100;
if (m & S_IRGRP)
operms |= 0040;
if (m & S_IWGRP)
operms |= 0020;
if (m & S_IXGRP)
operms |= 0010;
if (m & S_IROTH)
operms |= 0004;
if (m & S_IWOTH)
operms |= 0002;
if (m & S_IXOTH)
operms |= 0001;
if (m & S_ISUID)
operms |= 04000;
if (m & S_ISGID)
operms |= 02000;
if (m & S_ISVTX)
operms |= 01000;
ret = (char *)xmalloc (16);
snprintf (ret, 16, "%04o", operms);
return ret;
}
static char *
statperms (m)
int m;
{
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
int i;
char *ret;
i = 0;
if (m & S_IRUSR)
ubits[i++] = 'r';
if (m & S_IWUSR)
ubits[i++] = 'w';
if (m & S_IXUSR)
ubits[i++] = 'x';
ubits[i] = '\0';
i = 0;
if (m & S_IRGRP)
gbits[i++] = 'r';
if (m & S_IWGRP)
gbits[i++] = 'w';
if (m & S_IXGRP)
gbits[i++] = 'x';
gbits[i] = '\0';
i = 0;
if (m & S_IROTH)
obits[i++] = 'r';
if (m & S_IWOTH)
obits[i++] = 'w';
if (m & S_IXOTH)
obits[i++] = 'x';
obits[i] = '\0';
if (m & S_ISUID)
ubits[2] = (m & S_IXUSR) ? 's' : 'S';
if (m & S_ISGID)
gbits[2] = (m & S_IXGRP) ? 's' : 'S';
if (m & S_ISVTX)
obits[2] = (m & S_IXOTH) ? 't' : 'T';
ret = (char *)xmalloc (32);
snprintf (ret, 32, "u=%s,g=%s,o=%s", ubits, gbits, obits);
return ret;
}
static char *
statmode(mode)
int mode;
{
char *modestr, *m;
modestr = m = (char *)xmalloc (8);
if (S_ISBLK (mode))
*m++ = 'b';
if (S_ISCHR (mode))
*m++ = 'c';
if (S_ISDIR (mode))
*m++ = 'd';
if (S_ISREG(mode))
*m++ = '-';
if (S_ISFIFO(mode))
*m++ = 'p';
if (S_ISLNK(mode))
*m++ = 'l';
if (S_ISSOCK(mode))
*m++ = 's';
#ifdef S_ISDOOR
if (S_ISDOOR (mode))
*m++ = 'D';
#endif
#ifdef S_ISWHT
if (S_ISWHT(mode))
*m++ = 'W';
#endif
#ifdef S_ISNWK
if (S_ISNWK(mode))
*m++ = 'n';
#endif
#ifdef S_ISMPC
if (S_ISMPC (mode))
*m++ = 'm';
#endif
*m = '\0';
return (modestr);
}
static char *
stattime (t)
time_t t;
{
char *tbuf, *ret;
size_t tlen;
tbuf = ctime (&t);
tlen = strlen (tbuf);
ret = savestring (tbuf);
ret[tlen-1] = '\0';
return ret;
}
static char *
statval (which, fname, flags, sp)
int which;
char *fname;
int flags;
struct stat *sp;
{
int temp;
switch (which)
{
case ST_NAME:
return savestring (fname);
case ST_DEV:
return itos (sp->st_dev);
case ST_INO:
return itos (sp->st_ino);
case ST_MODE:
return (statmode (sp->st_mode));
case ST_NLINK:
return itos (sp->st_nlink);
case ST_UID:
return itos (sp->st_uid);
case ST_GID:
return itos (sp->st_gid);
case ST_RDEV:
return itos (sp->st_rdev);
case ST_SIZE:
return itos (sp->st_size);
case ST_ATIME:
return ((flags & 2) ? stattime (sp->st_atime) : itos (sp->st_atime));
case ST_MTIME:
return ((flags & 2) ? stattime (sp->st_mtime) : itos (sp->st_mtime));
case ST_CTIME:
return ((flags & 2) ? stattime (sp->st_ctime) : itos (sp->st_ctime));
case ST_BLKSIZE:
return itos (sp->st_blksize);
case ST_BLOCKS:
return itos (sp->st_blocks);
case ST_CHASELINK:
return (statlink (fname, sp));
case ST_PERMS:
temp = sp->st_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID);
return (flags & 2) ? statperms (temp) : octalperms (temp);
default:
return savestring ("42");
}
}
static int
loadstat (vname, var, fname, flags, sp)
char *vname;
SHELL_VAR *var;
char *fname;
int flags;
struct stat *sp;
{
int i;
char *key, *value;
SHELL_VAR *v;
for (i = 0; arraysubs[i]; i++)
{
key = savestring (arraysubs[i]);
value = statval (i, fname, flags, sp);
v = bind_assoc_variable (var, vname, key, value, ASS_FORCE);
}
return 0;
}
int
stat_builtin (list)
WORD_LIST *list;
{
int opt, flags;
char *aname, *fname;
struct stat st;
SHELL_VAR *v;
aname = "STAT";
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "A:Ll")) != -1)
{
switch (opt)
{
case 'A':
aname = list_optarg;
break;
case 'L':
flags |= 1; /* operate on links rather than resolving them */
break;
case 'l':
flags |= 2;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
fname = list->word->word;
if (getstat (fname, flags, &st) < 0)
{
builtin_error ("%s: cannot stat: %s", fname, strerror (errno));
return (EXECUTION_FAILURE);
}
unbind_variable (aname);
v = make_new_assoc_variable (aname);
if (v == 0)
{
builtin_error ("%s: cannot create variable", aname);
return (EXECUTION_FAILURE);
}
if (loadstat (aname, v, fname, flags, &st) < 0)
{
builtin_error ("%s: cannot assign file status information", aname);
unbind_variable (aname);
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
/* An array of strings forming the `long' documentation for a builtin xxx,
which is printed by `help xxx'. It must end with a NULL. By convention,
the first line is a short description. */
char *stat_doc[] = {
"Load an associative array with file status information.",
"",
"Take a filename and load the status information returned by a",
"stat(2) call on that file into the associative array specified",
"by the -A option. The default array name is STAT. If the -L",
"option is supplied, stat does not resolve symbolic links and",
"reports information about the link itself. The -l option results",
"in longer-form listings for some of the fields. The exit status is 0",
"unless the stat fails or assigning the array is unsuccessful.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. The flags must include BUILTIN_ENABLED so the
builtin can be used. */
struct builtin stat_struct = {
"stat", /* builtin name */
stat_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
stat_doc, /* array of long documentation strings. */
"stat [-lL] [-A aname] file", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+1 -14
View File
@@ -1110,19 +1110,6 @@ extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeva
static const int precs[] = { 0, 100, 10, 1 };
#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)
static int
decpoint ()
{
struct lconv *lv;
lv = localeconv ();
return (lv && lv->decimal_point && lv->decimal_point[0]) ? lv->decimal_point[0] : '.';
}
#else
# define decpoint() '.'
#endif
/* Expand one `%'-prefixed escape sequence from a time format string. */
static int
mkfmt (buf, prec, lng, sec, sec_fraction)
@@ -1167,7 +1154,7 @@ mkfmt (buf, prec, lng, sec, sec_fraction)
and 999. */
if (prec != 0)
{
buf[ind++] = decpoint ();
buf[ind++] = locale_decpoint ();
for (aind = 1; aind <= prec; aind++)
{
buf[ind++] = (sec_fraction / precs[aind]) + '0';
+3
View File
@@ -137,6 +137,9 @@ 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 *));
#ifndef locale_decpoint
extern int locale_decpoint __P((void));
#endif
/* Declarations for functions defined in list.c. */
extern void list_walk __P((GENERIC_LIST *, sh_glist_func_t *));
+15
View File
@@ -453,6 +453,21 @@ cleanup_the_pipeline ()
discard_pipeline (disposer);
}
void
discard_last_procsub_child ()
{
PROCESS *disposer;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
disposer = last_procsub_child;
last_procsub_child = (PROCESS *)NULL;
UNBLOCK_CHILD (oset);
if (disposer)
discard_pipeline (disposer);
}
struct pipeline_saver *
alloc_pipeline_saver ()
{
+1
View File
@@ -190,6 +190,7 @@ extern JOB **jobs;
extern void making_children __P((void));
extern void stop_making_children __P((void));
extern void cleanup_the_pipeline __P((void));
extern void discard_last_procsub_child __P((void));
extern void save_pipeline __P((int));
extern PROCESS *restore_pipeline __P((int));
extern void start_pipeline __P((void));
+9
View File
@@ -330,6 +330,12 @@ PARSE_COLLSYM (p, vp)
for (pc = 0; p[pc]; pc++)
if (p[pc] == L('.') && p[pc+1] == L(']'))
break;
if (p[pc] == 0)
{
if (vp)
*vp = INVALID;
return (p + pc);
}
val = COLLSYM (p, pc);
if (vp)
*vp = val;
@@ -483,6 +489,9 @@ BRACKMATCH (p, test, flags)
c = *p++;
c = FOLD (c);
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
if ((flags & FNM_PATHNAME) && c == L('/'))
/* [/] can never match when matching a pathname. */
return (CHAR *)0;
+28
View File
@@ -100,6 +100,12 @@
# include "watch.h"
#endif
#ifdef powerof2
# undef powerof2
#endif
/* Could also use (((x) & -(x)) == (x)) */
#define powerof2(x) ((((x) - 1) & (x)) == 0)
/* System-specific omissions. */
#ifdef HPUX
# define NO_VALLOC
@@ -1125,6 +1131,28 @@ internal_memalign (alignment, size, file, line, flags)
return aligned;
}
int
posix_memalign (memptr, alignment, size)
void **memptr;
size_t alignment, size;
{
void *mem;
/* Perform posix-mandated error checking here */
if ((alignment % sizeof (void *) != 0) || alignment == 0)
return EINVAL;
else if (powerof2 (alignment) == 0)
return EINVAL;
mem = internal_memalign (alignment, size, (char *)0, 0, 0);
if (mem != 0)
{
*memptr = mem;
return 0;
}
return ENOMEM;
}
#if !defined (NO_VALLOC)
/* This runs into trouble with getpagesize on HPUX, and Multimax machines.
Patching out seems cleaner than the ugly fix needed. */
+16 -2
View File
@@ -37,6 +37,10 @@
#include "posixstat.h" // stat related macros (S_ISREG, ...)
#include <fcntl.h> // S_ISUID
#ifndef S_ISDIR
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
// strlen()
#if defined (HAVE_STRING_H)
# include <string.h>
@@ -183,11 +187,17 @@ _rl_print_color_indicator (const char *f)
{
colored_filetype = C_FILE;
#if defined (S_ISUID)
if ((mode & S_ISUID) != 0 && is_colored (C_SETUID))
colored_filetype = C_SETUID;
else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
else
#endif
#if defined (S_ISGID)
if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
colored_filetype = C_SETGID;
else if (is_colored (C_CAP) && 0) //f->has_capability)
else
#endif
if (is_colored (C_CAP) && 0) //f->has_capability)
colored_filetype = C_CAP;
else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC))
colored_filetype = C_EXEC;
@@ -211,12 +221,16 @@ _rl_print_color_indicator (const char *f)
colored_filetype = C_STICKY;
#endif
}
#if defined (S_ISLNK)
else if (S_ISLNK (mode))
colored_filetype = C_LINK;
#endif
else if (S_ISFIFO (mode))
colored_filetype = C_FIFO;
#if defined (S_ISSOCK)
else if (S_ISSOCK (mode))
colored_filetype = C_SOCK;
#endif
else if (S_ISBLK (mode))
colored_filetype = C_BLK;
else if (S_ISCHR (mode))
+4
View File
@@ -606,12 +606,14 @@ history_truncate_file (fname, lines)
history_lines_written_to_file = 0;
}
#if defined (HAVE_CHOWN)
/* Make sure the new filename is owned by the same user as the old. If one
user is running this, it's a no-op. If the shell is running after sudo
with a shared history file, we don't want to leave the history file
owned by root. */
if (rv == 0 && exists)
r = chown (filename, finfo.st_uid, finfo.st_gid);
#endif
xfree (filename);
FREE (tempname);
@@ -753,12 +755,14 @@ mmap_error:
history_lines_written_to_file = 0;
}
#if defined (HAVE_CHOWN)
/* Make sure the new filename is owned by the same user as the old. If one
user is running this, it's a no-op. If the shell is running after sudo
with a shared history file, we don't want to leave the history file
owned by root. */
if (rv == 0 && exists)
mode = chown (histname, finfo.st_uid, finfo.st_gid);
#endif
FREE (histname);
FREE (tempname);
+18
View File
@@ -561,3 +561,21 @@ locale_isutf8 (lspec)
return (strstr (lspec, "UTF-8") || strstr (lspec, "utf8"));
#endif
}
#if defined (HAVE_LOCALECONV)
int
locale_decpoint ()
{
struct lconv *lv;
lv = localeconv ();
return (lv && lv->decimal_point && lv->decimal_point[0]) ? lv->decimal_point[0] : '.';
}
#else
# undef locale_decpoint
int
locale_decpoint ()
{
return '.';
}
#endif
+8 -3
View File
@@ -2816,6 +2816,9 @@ mk_alexpansion (s)
strcpy (r, s);
/* If the last character in the alias is a newline, don't add a trailing
space to the expansion. Works with shell_getc above. */
/* Need to do something about the case where the alias expansion contains
an unmatched quoted string, since appending this space affects the
subsequent output. */
if (r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0)
r[l++] = ' ';
r[l] = '\0';
@@ -2839,9 +2842,11 @@ alias_expand_token (tokstr)
return (NO_EXPANSION);
/* mk_alexpansion puts an extra space on the end of the alias expansion,
so the lookahead by the parser works right. If this gets changed,
make sure the code in shell_getc that deals with reaching the end of
an expanded alias is changed with it. */
so the lookahead by the parser works right (the alias needs to remain
`in use' while parsing its last word to avoid alias recursion for
something like "alias echo=echo"). If this gets changed, make sure
the code in shell_getc that deals with reaching the end of an
expanded alias is changed with it. */
expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL;
if (expanded)
+10
View File
@@ -230,6 +230,16 @@ quote_string_for_globbing (pathname, qflags)
savej = j;
savei = i;
c = pathname[i++]; /* c == char after open bracket */
if (c == '^') /* ignore pattern negation */
{
temp[j++] = c;
c = pathname[i++];
}
if (c == ']') /* ignore right bracket if first char */
{
temp[j++] = c;
c = pathname[i++];
}
do
{
if (c == 0)
+25 -5
View File
@@ -1383,6 +1383,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
{
si = i + 2;
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1392,6 +1393,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
{
si = i + len_opener;
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1401,6 +1403,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
{
si = i + len_alt_opener;
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1420,6 +1423,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
{
si = i + 1;
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1473,6 +1477,8 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
it should point to just after the first `{' found. On exit, SINDEX
gets the position of the matching `}'. QUOTED is non-zero if this
occurs inside double quotes. */
/* XXX -- should this use skipsubscript to handle ${word[sub]}? (only do it
if dolbrace_state == DOLBRACE_PARAM) */
/* XXX -- this is very similar to extract_delimited_string -- XXX */
static char *
extract_dollar_brace_string (string, sindex, quoted, flags)
@@ -1539,7 +1545,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1550,6 +1556,9 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
{
si = i + 2;
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si + 1;
continue;
}
@@ -1577,6 +1586,17 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
continue;
}
#if defined (ARRAY_VARS)
/* XXX - bash-5.0 */
if (c == '[' && dolbrace_state == DOLBRACE_PARAM)
{
si = skipsubscript (string, i, 0);
CHECK_STRING_OVERRUN (i, si, slen, c);
if (string[si] == ']')
c = string[i = si];
}
#endif
/* move past this character, which was not special. */
ADVANCE_CHAR (string, slen, i);
@@ -1905,6 +1925,7 @@ skip_to_delim (string, start, delims, flags)
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
@@ -1923,6 +1944,7 @@ skip_to_delim (string, start, delims, flags)
temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si, 0);
free (temp); /* XXX - not using SX_NOALLOC here yet */
#endif
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si;
if (string[i] == '\0')
break;
@@ -1942,6 +1964,7 @@ skip_to_delim (string, start, delims, flags)
open[2] = '\0';
temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
CHECK_STRING_OVERRUN (i, si, slen, c);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
@@ -5810,10 +5833,7 @@ process_substitute (string, open_for_read_in_child)
{
#if defined (JOB_CONTROL)
if (last_procsub_child)
{
discard_pipeline (last_procsub_child);
last_procsub_child = (PROCESS *)NULL;
}
discard_last_procsub_child ();
last_procsub_child = restore_pipeline (0);
#endif
+66
View File
@@ -221,6 +221,9 @@ static SHELL_VAR *get_lineno __P((SHELL_VAR *));
static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_subshell __P((SHELL_VAR *));
static SHELL_VAR *get_epochseconds __P((SHELL_VAR *));
static SHELL_VAR *get_epochrealtime __P((SHELL_VAR *));
static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
#if defined (HISTORY)
@@ -1451,6 +1454,40 @@ get_subshell (var)
return (var);
}
static SHELL_VAR *
get_epochseconds (var)
SHELL_VAR *var;
{
intmax_t now;
char *p;
now = NOW;
p = itos (now);
FREE (value_cell (var));
var_setvalue (var, p);
return (var);
}
static SHELL_VAR *
get_epochrealtime (var)
SHELL_VAR *var;
{
char buf[32];
char *p;
struct timeval tv;
gettimeofday (&tv, NULL);
snprintf (buf, sizeof (buf), "%u%c%06u", (unsigned)tv.tv_sec,
locale_decpoint (),
(unsigned)tv.tv_usec);
p = savestring (buf);
FREE (value_cell (var));
var_setvalue (var, p);
return (var);
}
static SHELL_VAR *
get_bashpid (var)
SHELL_VAR *var;
@@ -1467,6 +1504,30 @@ get_bashpid (var)
return (var);
}
static SHELL_VAR *
get_bash_argv0 (var)
SHELL_VAR *var;
{
char *p;
p = savestring (dollar_vars[0]);
FREE (value_cell (var));
var_setvalue (var, p);
return var;
}
static SHELL_VAR *
assign_bash_argv0 (var, value, unused, key)
SHELL_VAR *var;
char *value;
arrayind_t unused;
char *key;
{
FREE (dollar_vars[0]);
dollar_vars[0] = savestring (value);
return var;
}
static SHELL_VAR *
get_bash_command (var)
SHELL_VAR *var;
@@ -1758,6 +1819,8 @@ initialize_dynamic_variables ()
v = init_seconds_var ();
INIT_DYNAMIC_VAR ("BASH_ARGV0", (char *)NULL, get_bash_argv0, assign_bash_argv0);
INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
@@ -1769,6 +1832,9 @@ initialize_dynamic_variables ()
INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
VSETATTR (v, att_integer);
INIT_DYNAMIC_VAR ("EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign);
INIT_DYNAMIC_VAR ("EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign);
#if defined (HISTORY)
INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
VSETATTR (v, att_integer);