From: Chet Ramey Date: Mon, 10 Feb 2020 14:19:37 +0000 (-0500) Subject: commit bash-20200207 snapshot X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f65f3d54581b4e91f51cc7c02b03f8d698377aaa;p=thirdparty%2Fbash.git commit bash-20200207 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 75d0725f6..e12e95b39 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -6891,7 +6891,7 @@ builtins/wait.def variables.c - check_unbind_variable: return -2 if the variable name is readonly (change) or non-unsettable (new) to differentiate the return value - from -1 from makunboud (which means variable not found) + from -1 from makunbound (which means variable not found) builtins/common.[ch] - builtin_unbind_variable: identical to check_unbind_variable but calls @@ -7249,6 +7249,9 @@ bashline.c - bash_execute_unix_command: bind READLINE_MARK variable, exposing the value of rl_mark to `bind -x' functions +doc/{bash.1,bashref.texi} + - READLINE_MARK: document new variable set by the shell + 1/31 ---- examples/loadables/accept.c @@ -7261,3 +7264,53 @@ lib/readline/histfile.c - history_do_write,history_truncate_file: translate the return value rv to errno when histfile_restore returns -1 (e.g., if rename() fails). Report and fix from A + + 2/3 + --- +lib/sh/ufuncs.c + - fsleep: if pselect/select is interrupted by a signal, return -1 and + let the caller deal with it + +lib/sh/timeval.c + - multimeval: new function, multiply a timeval by a constant integer + - divtimeval: new function, divide a timeval by a constant integer + +lib/sh/uconvert.c + - uconvert: new additional argument: EP. If non-null, it gets the + address of the first non-digit that ends conversion (like strtod); + we try to do as much of the conversion as possible if EP is set so + the caller can clean up + + 2/4 + --- +examples/loadables/mkfifo.c + - mkfifo: new loadable builtin + + 2/6 + --- +variables.c + - make_local_variable: make sure local variables that have the same + names as variables found in the temporary environment are marked as + local. From Grisha Levit back in 12/2018 + + 2/7 + --- +sig.[ch] + - restore_sigmask: function to restore top-level signal mask using + sigprocmask + +{sig,eval,jobs,nojobs}.c + - replace calls to sigprocmask with restore_sigmask(); remove extern + declarations of top_level_mask + +sig.c + - initialize_shell_signals: if SIGCHLD is blocked at shell startup, + not only remove it from top_level_mask but make sure it's unblocked + +execute_cmd.c + - execute_pipeline: if lastpipe is enabled and we're executing the + rightmost pipeline element in the current shell, make sure to unblock + SIGCHLD before calling execute_command, in case `return' or `exec' + is run and that call doesn't return. From a report by + Harald van Dijk following up to a report + by Martijn Dekker diff --git a/MANIFEST b/MANIFEST index 988cf2243..8588d50ed 100644 --- a/MANIFEST +++ b/MANIFEST @@ -740,6 +740,7 @@ examples/loadables/whoami.c f examples/loadables/uname.c f examples/loadables/sync.c f examples/loadables/mkdir.c f +examples/loadables/mkfifo.c f examples/loadables/mktemp.c f examples/loadables/ln.c f examples/loadables/mypid.c f diff --git a/builtins/read.def b/builtins/read.def index 45b3ac1e4..c74d40bb3 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -274,7 +274,7 @@ read_builtin (list) break; #endif case 't': - code = uconvert (list_optarg, &ival, &uval); + code = uconvert (list_optarg, &ival, &uval, (char **)NULL); if (code == 0 || ival < 0 || uval < 0) { builtin_error (_("%s: invalid timeout specification"), list_optarg); @@ -377,7 +377,7 @@ read_builtin (list) /* $TMOUT, if set, is the default timeout for read. */ if (have_timeout == 0 && (e = get_string_value ("TMOUT"))) { - code = uconvert (e, &ival, &uval); + code = uconvert (e, &ival, &uval, (char **)NULL); if (code == 0 || ival < 0 || uval < 0) tmsec = tmusec = 0; else diff --git a/eval.c b/eval.c index 87cc2b9e7..fa3b1534d 100644 --- a/eval.c +++ b/eval.c @@ -48,10 +48,6 @@ # include "bashhist.h" #endif -#if defined (HAVE_POSIX_SIGNALS) -extern sigset_t top_level_mask; -#endif - static void send_pwd_to_eterm __P((void)); static sighandler alrm_catcher __P((int)); @@ -121,9 +117,8 @@ reader_loop () dispose_command (current_command); current_command = (COMMAND *)NULL; } -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif + + restore_sigmask (); break; default: diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in index d6ee581dd..9f84509fa 100644 --- a/examples/loadables/Makefile.in +++ b/examples/loadables/Makefile.in @@ -101,9 +101,10 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \ ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \ - tty pathchk tee head mkdir rmdir mktemp printenv id whoami \ - uname sync push ln unlink realpath strftime mypid setpgid seq rm -OTHERPROG = necho hello cat pushd stat accept + tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \ + uname sync push ln unlink realpath strftime mypid setpgid seq rm \ + accept +OTHERPROG = necho hello cat pushd stat all: $(SHOBJ_STATUS) @@ -178,6 +179,9 @@ mkdir: mkdir.o rmdir: rmdir.o $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS) +mkfifo: mkfifo.o + $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkfifo.o $(SHOBJ_LIBS) + mktemp: mktemp.o $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mktemp.o $(SHOBJ_LIBS) diff --git a/examples/loadables/TODO b/examples/loadables/TODO index b498bdbc9..12767acd4 100644 --- a/examples/loadables/TODO +++ b/examples/loadables/TODO @@ -1,4 +1,5 @@ cmp wc -mkfifo paste + +cut diff --git a/examples/loadables/mkfifo.c b/examples/loadables/mkfifo.c new file mode 100644 index 000000000..2bc4e98ac --- /dev/null +++ b/examples/loadables/mkfifo.c @@ -0,0 +1,146 @@ +/* mkfifo - make FIFOs */ + +/* See Makefile for compilation details. */ + +/* + Copyright (C) 1999-2020 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 . +*/ + +#include + +#include "bashtypes.h" +#include "posixstat.h" +#include +#include +#include "bashansi.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" +#include "common.h" + +#if !defined (errno) +extern int errno; +#endif + +#define ISOCTAL(c) ((c) >= '0' && (c) <= '7') + +extern int parse_symbolic_mode (); + +static int original_umask; + +int +mkfifo_builtin (list) + WORD_LIST *list; +{ + int opt, mflag, omode, rval, nmode, basemode; + char *mode; + WORD_LIST *l; + + mflag = 0; + mode = (char *)NULL; + + reset_internal_getopt (); + while ((opt = internal_getopt(list, "m:")) != -1) + switch (opt) + { + case 'm': + mflag = 1; + mode = list_optarg; + break; + CASE_HELPOPT; + default: + builtin_usage(); + return (EX_USAGE); + } + list = loptend; + + if (list == 0) + { + builtin_usage (); + return (EX_USAGE); + } + + basemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + if (mode == NULL) + omode = basemode; + else if (ISOCTAL (*mode)) /* octal number */ + { + omode = read_octal (mode); + if (omode < 0) + { + builtin_error ("invalid file mode: %s", mode); + return (EXECUTION_FAILURE); + } + } + else /* symbolic mode */ + { + /* initial bits are a=rwx; the mode argument modifies them */ + omode = parse_symbolic_mode (mode, basemode); + if (omode < 0) + { + builtin_error ("invalid file mode: %s", mode); + return (EXECUTION_FAILURE); + } + } + + /* Make the new mode */ + original_umask = umask (0); + umask (original_umask); + + nmode = basemode & ~original_umask; + /* Adjust new mode based on mode argument */ + nmode &= omode; + + for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next) + { + if (mkfifo (l->word->word, nmode) < 0) + { + builtin_error ("cannot create FIFO `%s': %s", l->word->word, strerror (errno)); + rval = EXECUTION_FAILURE; + } + } + return rval; +} + + +char *mkfifo_doc[] = { + "Create FIFOs (named pipes).", + "", + "Make FIFOs. Create the FIFOs named as arguments, in", + "the order specified, using mode a=rw as modified by the current", + "umask (see `help umask'). The -m option causes the file permission", + "bits of the final FIFO to be MODE. The MODE argument may be", + "an octal number or a symbolic mode like that used by chmod(1). If", + "a symbolic mode is used, the operations are interpreted relative to", + "an initial mode of \"a=rw\". mkfifo returns 0 if the FIFOs are", + "umask, plus write and search permissions for the owner. mkdir", + "created successfully, and non-zero if an error occurs.", + (char *)NULL +}; + +struct builtin mkfifo_struct = { + "mkfifo", + mkfifo_builtin, + BUILTIN_ENABLED, + mkfifo_doc, + "mkfifo [-m mode] fifo_name [fifo_name ...]", + 0 +}; diff --git a/examples/loadables/sleep.c b/examples/loadables/sleep.c index 92b1a8fa1..fc2203d4a 100644 --- a/examples/loadables/sleep.c +++ b/examples/loadables/sleep.c @@ -5,7 +5,7 @@ */ /* - Copyright (C) 1999-2009 Free Software Foundation, Inc. + Copyright (C) 1999-2020 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -53,6 +53,9 @@ sleep_builtin (list) WORD_LIST *list; { long sec, usec; + char *ep; + int r, mul; + time_t t; if (list == 0) { builtin_usage(); @@ -68,8 +71,12 @@ WORD_LIST *list; return (EX_USAGE); } - if (uconvert(list->word->word, &sec, &usec)) { + r = uconvert(list->word->word, &sec, &usec, &ep); + /* Maybe postprocess conversion failures here based on EP */ + + if (r) { fsleep(sec, usec); + QUIT; return(EXECUTION_SUCCESS); } diff --git a/execute_cmd.c b/execute_cmd.c index e0950e624..e937e6cfe 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -2563,6 +2563,9 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) old_frozen = freeze_jobs_list (); lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ add_unwind_protect (lastpipe_cleanup, old_frozen); +#if defined (JOB_CONTROL) + UNBLOCK_CHILD (oset); /* XXX */ +#endif } if (cmd) cmd->flags |= CMD_LASTPIPE; diff --git a/externs.h b/externs.h index d9f89fff3..1484a9392 100644 --- a/externs.h +++ b/externs.h @@ -481,7 +481,7 @@ extern int sh_mktmpfd __P((char *, int, char **)); extern char *sh_mktmpdir __P((char *, int)); /* declarations for functions defined in lib/sh/uconvert.c */ -extern int uconvert __P((char *, long *, long *)); +extern int uconvert __P((char *, long *, long *, char **)); /* declarations for functions defined in lib/sh/ufuncs.c */ extern unsigned int falarm __P((unsigned int, unsigned int)); diff --git a/jobs.c b/jobs.c index f1e255ed4..1f2391718 100644 --- a/jobs.c +++ b/jobs.c @@ -165,7 +165,6 @@ extern int killpg PARAMS((pid_t, int)); typedef int sh_job_map_func_t PARAMS((JOB *, int, int, int)); /* Variables used here but defined in other files. */ -extern sigset_t top_level_mask; extern WORD_LIST *subst_assign_varlist; extern SigHandler **original_signals; @@ -2210,8 +2209,8 @@ make_child (command, async_p) CLRINTERRUPT; /* XXX - children have their own interrupt state */ /* Restore top-level signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); - + restore_sigmask (); + if (job_control) { /* All processes in this pipeline belong in the same diff --git a/lib/sh/timeval.c b/lib/sh/timeval.c index c4b61dc8a..f2ca7624a 100644 --- a/lib/sh/timeval.c +++ b/lib/sh/timeval.c @@ -67,6 +67,32 @@ addtimeval (d, t1, t2) return d; } +struct timeval * +multimeval (d, m) + struct timeval *d; + int m; +{ + time_t t; + + t = d->tv_usec * m; + d->tv_sec = d->tv_sec * m + t / 1000000; + d->tv_usec = t % 1000000; + return d; +} + +struct timeval * +divtimeval (d, m) + struct timeval *d; + int m; +{ + time_t t; + + t = d->tv_sec; + d->tv_sec = t / m; + d->tv_usec = (d->tv_usec + 1000000 * (t % m)) / m; + return d; +} + /* Do "cpu = ((user + sys) * 10000) / real;" with timevals. Barely-tested code from Deven T. Corzine . */ int @@ -149,4 +175,5 @@ print_timeval (fp, tvp) fprintf (fp, "%ldm%d%c%03ds", minutes, seconds, locale_decpoint (), seconds_fraction); } + #endif /* HAVE_TIMEVAL */ diff --git a/lib/sh/uconvert.c b/lib/sh/uconvert.c index 3d656df09..d04530794 100644 --- a/lib/sh/uconvert.c +++ b/lib/sh/uconvert.c @@ -1,7 +1,7 @@ /* uconvert - convert string representations of decimal numbers into whole number/fractional value pairs. */ -/* Copyright (C) 2008,2009 Free Software Foundation, Inc. +/* Copyright (C) 2008,2009,2020 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -50,6 +50,7 @@ do { \ if (ip) *ip = ipart * mult; \ if (up) *up = upart; \ + if (ep) *ep = p; \ return (x); \ } while (0) @@ -61,12 +62,14 @@ static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 }; /* Take a decimal number int-part[.[micro-part]] and convert it to the whole and fractional portions. The fractional portion is returned in millionths (micro); callers are responsible for multiplying appropriately. + EP, if non-null, gets the address of the character where conversion stops. Return 1 if value converted; 0 if invalid integer for either whole or fractional parts. */ int -uconvert(s, ip, up) +uconvert(s, ip, up, ep) char *s; long *ip, *up; + char **ep; { int n, mult; long ipart, upart; @@ -102,7 +105,14 @@ uconvert(s, ip, up) for (n = 0; n < 6 && p[n]; n++) { if (DIGIT(p[n]) == 0) - RETURN(0); + { + if (ep) + { + upart *= multiplier[n]; + p += n; /* To set EP */ + } + RETURN(0); + } upart = (upart * 10) + (p[n] - '0'); } @@ -112,5 +122,12 @@ uconvert(s, ip, up) if (n == 6 && p[6] >= '5' && p[6] <= '9') upart++; /* round up 1 */ + if (ep) + { + p += n; + while (DIGIT(*p)) + p++; + } + RETURN(1); } diff --git a/lib/sh/ufuncs.c b/lib/sh/ufuncs.c index ad9284ccb..c1251395c 100644 --- a/lib/sh/ufuncs.c +++ b/lib/sh/ufuncs.c @@ -130,7 +130,7 @@ fsleep(sec, usec) #endif e = errno; if (r < 0 && errno == EINTR) - QUIT; /* just signals, no traps */ + return -1; /* caller will handle */ errno = e; } while (r < 0 && errno == EINTR); diff --git a/nojobs.c b/nojobs.c index 923d0c9d8..82a99bf54 100644 --- a/nojobs.c +++ b/nojobs.c @@ -74,10 +74,6 @@ extern int errno; #endif /* !errno */ -#if defined (HAVE_POSIX_SIGNALS) -extern sigset_t top_level_mask; -#endif - extern void set_original_signal __P((int, SigHandler *)); volatile pid_t last_made_pid = NO_PID; @@ -557,10 +553,8 @@ make_child (command, async_p) CLRINTERRUPT; /* XXX - children have their own interrupt state */ -#if defined (HAVE_POSIX_SIGNALS) /* Restore top-level signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif + restore_sigmask (); #if 0 /* Ignore INT and QUIT in asynchronous children. */ diff --git a/sig.c b/sig.c index 9e5581f1a..d3bb9e679 100644 --- a/sig.c +++ b/sig.c @@ -309,7 +309,11 @@ initialize_shell_signals () sigemptyset (&top_level_mask); sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); # if defined (SIGCHLD) - sigdelset (&top_level_mask, SIGCHLD); + if (sigismember (&top_level_mask, SIGCHLD)) + { + sigdelset (&top_level_mask, SIGCHLD); + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); + } # endif #endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ @@ -425,11 +429,9 @@ throw_to_top_level () give_terminal_to (shell_pgrp, 0); #endif /* JOB_CONTROL */ -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) /* This needs to stay because jobs.c:make_child() uses it without resetting the signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif + restore_sigmask (); reset_parser (); @@ -469,6 +471,14 @@ jump_to_top_level (value) sh_longjmp (top_level, value); } +void +restore_sigmask () +{ +#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); +#endif +} + sighandler termsig_sighandler (sig) int sig; diff --git a/sig.h b/sig.h index 4e5b46442..30ce99896 100644 --- a/sig.h +++ b/sig.h @@ -32,7 +32,7 @@ #endif #define sighandler RETSIGTYPE -typedef RETSIGTYPE SigHandler __P((int)); +typedef RETSIGTYPE SigHandler PARAMS((int)); #if defined (VOID_SIGHANDLER) # define SIGRETURN(n) return @@ -46,7 +46,7 @@ typedef RETSIGTYPE SigHandler __P((int)); #if !defined (HAVE_POSIX_SIGNALS) # define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler) #else -extern SigHandler *set_signal_handler __P((int, SigHandler *)); /* in sig.c */ +extern SigHandler *set_signal_handler PARAMS((int, SigHandler *)); /* in sig.c */ #endif /* _POSIX_VERSION */ #if !defined (SIGCHLD) && defined (SIGCLD) @@ -113,25 +113,26 @@ extern int interrupt_immediately; /* no longer used */ extern int terminate_immediately; /* Functions from sig.c. */ -extern sighandler termsig_sighandler __P((int)); -extern void termsig_handler __P((int)); -extern sighandler sigint_sighandler __P((int)); -extern void initialize_signals __P((int)); -extern void initialize_terminating_signals __P((void)); -extern void reset_terminating_signals __P((void)); -extern void top_level_cleanup __P((void)); -extern void throw_to_top_level __P((void)); -extern void jump_to_top_level __P((int)) __attribute__((__noreturn__)); - -extern sighandler sigwinch_sighandler __P((int)); -extern void set_sigwinch_handler __P((void)); -extern void unset_sigwinch_handler __P((void)); - -extern sighandler sigterm_sighandler __P((int)); +extern sighandler termsig_sighandler PARAMS((int)); +extern void termsig_handler PARAMS((int)); +extern sighandler sigint_sighandler PARAMS((int)); +extern void initialize_signals PARAMS((int)); +extern void initialize_terminating_signals PARAMS((void)); +extern void reset_terminating_signals PARAMS((void)); +extern void top_level_cleanup PARAMS((void)); +extern void throw_to_top_level PARAMS((void)); +extern void jump_to_top_level PARAMS((int)) __attribute__((__noreturn__)); +extern void restore_sigmask PARAMS((void)); + +extern sighandler sigwinch_sighandler PARAMS((int)); +extern void set_sigwinch_handler PARAMS((void)); +extern void unset_sigwinch_handler PARAMS((void)); + +extern sighandler sigterm_sighandler PARAMS((int)); /* Functions defined in trap.c. */ -extern SigHandler *set_sigint_handler __P((void)); -extern SigHandler *trap_to_sighandler __P((int)); -extern sighandler trap_handler __P((int)); +extern SigHandler *set_sigint_handler PARAMS((void)); +extern SigHandler *trap_to_sighandler PARAMS((int)); +extern sighandler trap_handler PARAMS((int)); #endif /* _SIG_H_ */ diff --git a/variables.c b/variables.c index 276b3d44c..f2b15c894 100644 --- a/variables.c +++ b/variables.c @@ -2771,7 +2771,6 @@ make_local_variable (name, flags) if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) { VUNSETATTR (old_var, att_invisible); /* XXX */ -#if 0 /* TAG:bash-5.1 */ /* We still want to flag this variable as local, though, and set things up so that it gets treated as a local variable. */ new_var = old_var; @@ -2781,7 +2780,7 @@ make_local_variable (name, flags) if (vc_isfuncenv (vc) && vc->scope == variable_context) break; goto set_local_var_flags; -#endif + return (old_var); }