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
- 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
- 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 <auroralanes@protonmail.ch>
+
+ 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 <grishalevit@gmail.com> 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 <harald@gigawatt.nl> following up to a report
+ by Martijn Dekker <martijn@inlv.org>
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
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);
/* $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
# 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));
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:
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)
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)
cmp
wc
-mkfifo
paste
+
+cut
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include <errno.h>
+#include <stdio.h>
+#include "bashansi.h"
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#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
+};
*/
/*
- 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
WORD_LIST *list;
{
long sec, usec;
+ char *ep;
+ int r, mul;
+ time_t t;
if (list == 0) {
builtin_usage();
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);
}
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;
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));
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;
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
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 <deven@ties.org>. */
int
fprintf (fp, "%ldm%d%c%03ds", minutes, seconds, locale_decpoint (), seconds_fraction);
}
+
#endif /* HAVE_TIMEVAL */
/* 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.
do { \
if (ip) *ip = ipart * mult; \
if (up) *up = upart; \
+ if (ep) *ep = p; \
return (x); \
} while (0)
/* 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;
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');
}
if (n == 6 && p[6] >= '5' && p[6] <= '9')
upart++; /* round up 1 */
+ if (ep)
+ {
+ p += n;
+ while (DIGIT(*p))
+ p++;
+ }
+
RETURN(1);
}
#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);
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;
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. */
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 */
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 ();
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;
#endif
#define sighandler RETSIGTYPE
-typedef RETSIGTYPE SigHandler __P((int));
+typedef RETSIGTYPE SigHandler PARAMS((int));
#if defined (VOID_SIGHANDLER)
# define SIGRETURN(n) return
#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)
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_ */
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;
if (vc_isfuncenv (vc) && vc->scope == variable_context)
break;
goto set_local_var_flags;
-#endif
+
return (old_var);
}