]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - nojobs.c
allow quoted-insert while reading readline search strings; force filename argument...
[thirdparty/bash.git] / nojobs.c
index d8b85bfea96fcf1a50b47fdb3e4b1a4e97f332ba..6073d75a7991c131515fc4781a93651170d68dce 100644 (file)
--- a/nojobs.c
+++ b/nojobs.c
@@ -3,7 +3,7 @@
 /* This file works under BSD, System V, minix, and Posix systems.  It does
    not implement job control. */
 
-/* Copyright (C) 1987-2011 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -34,9 +34,7 @@
 #include <signal.h>
 #include <errno.h>
 
-#if defined (BUFFERED_INPUT)
-#  include "input.h"
-#endif
+#include "input.h"
 
 /* Need to include this up here for *_TTY_DRIVER definitions. */
 #include "shtty.h"
 #include "shell.h"
 #include "jobs.h"
 #include "execute_cmd.h"
+#include "trap.h"
 
 #include "builtins/builtext.h" /* for wait_builtin */
+#include "builtins/common.h"
 
-#define DEFAULT_CHILD_MAX 32
+#define DEFAULT_CHILD_MAX 4096
 
 #if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG)
 #  define killpg(pg, sig)              kill(-(pg),(sig))
 extern int errno;
 #endif /* !errno */
 
-extern int interactive, interactive_shell, login_shell;
-extern int subshell_environment;
-extern int last_command_exit_value, last_command_exit_signal;
-extern int interrupt_immediately;
-extern sh_builtin_func_t *this_shell_builtin;
-#if defined (HAVE_POSIX_SIGNALS)
-extern sigset_t top_level_mask;
-#endif
-extern procenv_t wait_intr_buf;
-extern int wait_intr_flag;
-extern int wait_signal_received;
+extern void set_original_signal (int, SigHandler *);
 
 volatile pid_t last_made_pid = NO_PID;
 volatile pid_t last_asynchronous_pid = NO_PID;
 
-static int queue_sigchld, waiting_for_child;   /* dummy declarations */
+static int queue_sigchld;              /* dummy declaration */
+int waiting_for_child;
 
 /* Call this when you start making children. */
 int already_making_children = 0;
@@ -128,36 +119,36 @@ static int wait_sigint_received;
 
 static long child_max = -1L;
 
-static void alloc_pid_list __P((void));
-static int find_proc_slot __P((pid_t));
-static int find_index_by_pid __P((pid_t));
-static int find_status_by_pid __P((pid_t));
-static int process_exit_status __P((WAIT));
-static int find_termsig_by_pid __P((pid_t));
-static int get_termsig __P((WAIT));
-static void set_pid_status __P((pid_t, WAIT));
-static void set_pid_flags __P((pid_t, int));
-static void unset_pid_flags __P((pid_t, int));
-static int get_pid_flags __P((pid_t));
-static void add_pid __P((pid_t, int));
-static void mark_dead_jobs_as_notified __P((int));
-
-static sighandler wait_sigint_handler __P((int));
-static char *j_strsignal __P((int));
+static void alloc_pid_list (void);
+static int find_proc_slot (pid_t);
+static int find_index_by_pid (pid_t);
+static int find_status_by_pid (pid_t);
+static int process_exit_status (WAIT);
+static int find_termsig_by_pid (pid_t);
+static int get_termsig (WAIT);
+static void set_pid_status (pid_t, WAIT);
+static void set_pid_flags (pid_t, int);
+static void unset_pid_flags (pid_t, int);
+static int get_pid_flags (pid_t);
+static void add_pid (pid_t, int);
+static void mark_dead_jobs_as_notified (int);
+
+static sighandler wait_sigint_handler (int);
+static char *j_strsignal (int);
 
 #if defined (HAVE_WAITPID)
-static void reap_zombie_children __P((void));
+static void reap_zombie_children (void);
 #endif
 
 #if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS)
-static int siginterrupt __P((int, int));
+static int siginterrupt (int, int);
 #endif
 
-static void restore_sigint_handler __P((void));
+static void restore_sigint_handler (void);
 
 /* Allocate new, or grow existing PID_LIST. */
 static void
-alloc_pid_list ()
+alloc_pid_list (void)
 {
   register int i;
   int old = pid_list_size;
@@ -167,14 +158,16 @@ alloc_pid_list ()
 
   /* None of the newly allocated slots have process id's yet. */
   for (i = old; i < pid_list_size; i++)
-    pid_list[i].pid = NO_PID;
+    {
+      pid_list[i].pid = NO_PID;
+      pid_list[i].status = pid_list[i].flags = 0;
+    }
 }
 
 /* Return the offset within the PID_LIST array of an empty slot.  This can
    create new slots if all of the existing slots are taken. */
 static int
-find_proc_slot (pid)
-     pid_t pid;
+find_proc_slot (pid_t pid)
 {
   register int i;
 
@@ -191,8 +184,7 @@ find_proc_slot (pid)
 /* Return the offset within the PID_LIST array of a slot containing PID,
    or the value NO_PID if the pid wasn't found. */
 static int
-find_index_by_pid (pid)
-     pid_t pid;
+find_index_by_pid (pid_t pid)
 {
   register int i;
 
@@ -206,8 +198,7 @@ find_index_by_pid (pid)
 /* Return the status of PID as looked up in the PID_LIST array.  A
    return value of PROC_BAD indicates that PID wasn't found. */
 static int
-find_status_by_pid (pid)
-     pid_t pid;
+find_status_by_pid (pid_t pid)
 {
   int i;
 
@@ -220,8 +211,7 @@ find_status_by_pid (pid)
 }
 
 static int
-process_exit_status (status)
-     WAIT status;
+process_exit_status (WAIT status)
 {
   if (WIFSIGNALED (status))
     return (128 + WTERMSIG (status));
@@ -232,8 +222,7 @@ process_exit_status (status)
 /* Return the status of PID as looked up in the PID_LIST array.  A
    return value of PROC_BAD indicates that PID wasn't found. */
 static int
-find_termsig_by_pid (pid)
-     pid_t pid;
+find_termsig_by_pid (pid_t pid)
 {
   int i;
 
@@ -249,8 +238,7 @@ find_termsig_by_pid (pid)
    up PID in the pid array and set LAST_COMMAND_EXIT_SIGNAL appropriately
    depending on its flags and exit status. */
 static int
-get_termsig (status)
-     WAIT status;
+get_termsig (WAIT status)
 {
   if (WIFSTOPPED (status) == 0 && WIFSIGNALED (status))
     return (WTERMSIG (status));
@@ -260,9 +248,7 @@ get_termsig (status)
 
 /* Give PID the status value STATUS in the PID_LIST array. */
 static void
-set_pid_status (pid, status)
-     pid_t pid;
-     WAIT status;
+set_pid_status (pid_t pid, WAIT status)
 {
   int slot;
 
@@ -270,6 +256,12 @@ set_pid_status (pid, status)
   coproc_pidchk (pid, status);
 #endif
 
+#if defined (PROCESS_SUBSTITUTION)
+  if ((slot = find_procsub_child (pid)) >= 0)
+    set_procsub_status (slot, pid, WSTATUS (status));
+    /* XXX - also saving in list below */
+#endif
+
   slot = find_index_by_pid (pid);
   if (slot == NO_PID)
     return;
@@ -286,9 +278,7 @@ set_pid_status (pid, status)
 
 /* Give PID the flags FLAGS in the PID_LIST array. */
 static void
-set_pid_flags (pid, flags)
-     pid_t pid;
-     int flags;
+set_pid_flags (pid_t pid, int flags)
 {
   int slot;
 
@@ -301,9 +291,7 @@ set_pid_flags (pid, flags)
 
 /* Unset FLAGS for PID in the pid list */
 static void
-unset_pid_flags (pid, flags)
-     pid_t pid;
-     int flags;
+unset_pid_flags (pid_t pid, int flags)
 {
   int slot;
 
@@ -316,8 +304,7 @@ unset_pid_flags (pid, flags)
 
 /* Return the flags corresponding to PID in the PID_LIST array. */
 static int
-get_pid_flags (pid)
-     pid_t pid;
+get_pid_flags (pid_t pid)
 {
   int slot;
 
@@ -329,9 +316,7 @@ get_pid_flags (pid)
 }
 
 static void
-add_pid (pid, async)
-     pid_t pid;
-     int async;
+add_pid (pid_t pid, int async)
 {
   int slot;
 
@@ -345,8 +330,7 @@ add_pid (pid, async)
 }
 
 static void
-mark_dead_jobs_as_notified (force)
-     int force;
+mark_dead_jobs_as_notified (int force)
 {
   register int i, ndead;
 
@@ -386,7 +370,7 @@ mark_dead_jobs_as_notified (force)
 
 /* Remove all dead, notified jobs from the pid_list. */
 int
-cleanup_dead_jobs ()
+cleanup_dead_jobs (void)
 {
   register int i;
 
@@ -396,8 +380,9 @@ cleanup_dead_jobs ()
 
   for (i = 0; i < pid_list_size; i++)
     {
-      if ((pid_list[i].flags & PROC_RUNNING) == 0 &&
-         (pid_list[i].flags & PROC_NOTIFIED))
+      if (pid_list[i].pid != NO_PID &&
+           (pid_list[i].flags & PROC_RUNNING) == 0 &&
+           (pid_list[i].flags & PROC_NOTIFIED))
        pid_list[i].pid = NO_PID;
     }
 
@@ -409,25 +394,26 @@ cleanup_dead_jobs ()
 }
 
 void
-reap_dead_jobs ()
+reap_dead_jobs (void)
 {
   mark_dead_jobs_as_notified (0);
   cleanup_dead_jobs ();
 }
 
 /* Initialize the job control mechanism, and set up the tty stuff. */
-initialize_job_control (force)
-     int force;
+int
+initialize_job_control (int force)
 {
   shell_tty = fileno (stderr);
 
   if (interactive)
     get_tty_state ();
+  return 0;
 }
 
 /* Setup this shell to handle C-C, etc. */
 void
-initialize_job_signals ()
+initialize_job_signals (void)
 {
   set_signal_handler (SIGINT, sigint_sighandler);
 
@@ -441,7 +427,7 @@ initialize_job_signals ()
 /* Collect the status of all zombie children so that their system
    resources can be deallocated. */
 static void
-reap_zombie_children ()
+reap_zombie_children (void)
 {
 #  if defined (WNOHANG)
   pid_t pid;
@@ -464,8 +450,7 @@ reap_zombie_children ()
 #endif
 
 static int
-siginterrupt (sig, flag)
-     int sig, flag;
+siginterrupt (int sig, int flag)
 {
   struct sigaction act;
 
@@ -485,38 +470,42 @@ siginterrupt (sig, flag)
    anything else with it.  ASYNC_P says what to do with the tty.  If
    non-zero, then don't give it away. */
 pid_t
-make_child (command, async_p)
-     char *command;
-     int async_p;
+make_child (char *command, int flags)
 {
   pid_t pid;
-  int forksleep;
+  int async_p, forksleep;
+  sigset_t set, oset;
 
   /* Discard saved memory. */
   if (command)
     free (command);
 
+  async_p = (flags & FORK_ASYNC);
   start_pipeline ();
 
-#if defined (BUFFERED_INPUT)
   /* If default_buffered_input is active, we are reading a script.  If
      the command is asynchronous, we have already duplicated /dev/null
      as fd 0, but have not changed the buffered stream corresponding to
      the old fd 0.  We don't want to sync the stream in this case. */
   if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0))
     sync_buffered_stream (default_buffered_input);
-#endif /* BUFFERED_INPUT */
 
-  /* XXX - block SIGTERM here and unblock in child after fork resets the
-     set of pending signals? */
-  RESET_SIGTERM;
+  /* Block SIGTERM here and unblock in child after fork resets the
+     set of pending signals */
+  if (interactive_shell)
+    {
+      sigemptyset (&set);
+      sigaddset (&set, SIGTERM);
+      sigemptyset (&oset);
+      sigprocmask (SIG_BLOCK, &set, &oset);
+      set_signal_handler (SIGTERM, SIG_DFL);
+    }
 
   /* Create the child, handle severe errors.  Retry on EAGAIN. */
   forksleep = 1;
   while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX)
     {
       sys_error ("fork: retry");
-      RESET_SIGTERM;
 
 #if defined (HAVE_WAITPID)
       /* Posix systems with a non-blocking waitpid () system call available
@@ -532,7 +521,11 @@ make_child (command, async_p)
     }
 
   if (pid != 0)
-    RESET_SIGTERM;
+    if (interactive_shell)
+      {
+       set_signal_handler (SIGTERM, SIG_IGN);
+       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+      }
 
   if (pid < 0)
     {
@@ -543,16 +536,12 @@ make_child (command, async_p)
 
   if (pid == 0)
     {
-#if defined (BUFFERED_INPUT)
       unset_bash_input (0);
-#endif /* BUFFERED_INPUT */
 
       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. */
@@ -560,6 +549,8 @@ make_child (command, async_p)
        last_asynchronous_pid = getpid ();
 #endif
 
+      subshell_environment |= SUBSHELL_IGNTRAP;
+
       default_tty_job_signals ();
     }
   else
@@ -577,7 +568,7 @@ make_child (command, async_p)
 }
 
 void
-ignore_tty_job_signals ()
+ignore_tty_job_signals (void)
 {
 #if defined (SIGTSTP)
   set_signal_handler (SIGTSTP, SIG_IGN);
@@ -587,7 +578,7 @@ ignore_tty_job_signals ()
 }
 
 void
-default_tty_job_signals ()
+default_tty_job_signals (void)
 {
 #if defined (SIGTSTP)
   if (signal_is_trapped (SIGTSTP) == 0 && signal_is_hard_ignored (SIGTSTP))
@@ -607,16 +598,25 @@ default_tty_job_signals ()
 
 /* Called once in a parent process. */
 void
-get_original_tty_job_signals ()
+get_original_tty_job_signals (void)
 {
   static int fetched = 0;
 
   if (fetched == 0)
     {
 #if defined (SIGTSTP)
-      get_original_signal (SIGTSTP);
-      get_original_signal (SIGTTIN);
-      get_original_signal (SIGTTOU);
+      if (interactive_shell)
+       {
+         set_original_signal (SIGTSTP, SIG_DFL);
+         set_original_signal (SIGTTIN, SIG_DFL);
+         set_original_signal (SIGTTOU, SIG_DFL);
+       }
+      else
+       {
+         get_original_signal (SIGTSTP);
+         get_original_signal (SIGTTIN);
+         get_original_signal (SIGTTOU);
+       }
 #endif
       fetched = 1;
     }
@@ -625,19 +625,18 @@ get_original_tty_job_signals ()
 /* Wait for a single pid (PID) and return its exit status.  Called by
    the wait builtin. */
 int
-wait_for_single_pid (pid)
-     pid_t pid;
+wait_for_single_pid (pid_t pid, int flags)
 {
   pid_t got_pid;
   WAIT status;
-  int pstatus, flags;
+  int pstatus;
 
   pstatus = find_status_by_pid (pid);
 
   if (pstatus == PROC_BAD)
     {
       internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
-      return (127);
+      return (257);
     }
 
   if (pstatus != PROC_STILL_ALIVE)
@@ -673,28 +672,44 @@ wait_for_single_pid (pid)
 
   siginterrupt (SIGINT, 0);
   QUIT;
+  CHECK_WAIT_INTR;
 
   return (got_pid > 0 ? process_exit_status (status) : -1);
 }
 
 /* Wait for all of the shell's children to exit.  Called by the `wait'
    builtin. */
-void
-wait_for_background_pids ()
+int
+wait_for_background_pids (struct procstat *ps)
 {
   pid_t got_pid;
   WAIT status;
+  int njobs;
 
   /* If we aren't using job control, we let the kernel take care of the
      bookkeeping for us.  wait () will return -1 and set errno to ECHILD
      when there are no more unwaited-for child processes on both
      4.2 BSD-based and System V-based systems. */
 
+  njobs = 0;
   siginterrupt (SIGINT, 1);
 
   /* Wait for ECHILD */
+  waiting_for_child = 1;
   while ((got_pid = WAITPID (-1, &status, 0)) != -1)
-    set_pid_status (got_pid, status);
+    {
+      waiting_for_child = 0;
+      njobs++;
+      set_pid_status (got_pid, status);
+      if (ps)
+       {
+         ps->pid = got_pid;
+         ps->status = process_exit_status (status);
+       }
+      waiting_for_child = 1;
+      CHECK_WAIT_INTR;
+    }
+  waiting_for_child = 0;
 
   if (errno != EINTR && errno != ECHILD)
     {
@@ -704,13 +719,16 @@ wait_for_background_pids ()
 
   siginterrupt (SIGINT, 0);
   QUIT;
+  CHECK_WAIT_INTR;
 
   mark_dead_jobs_as_notified (1);
   cleanup_dead_jobs ();
+
+  return njobs;
 }
 
 void
-wait_sigint_cleanup ()
+wait_sigint_cleanup (void)
 {
 }
 
@@ -719,7 +737,7 @@ wait_sigint_cleanup ()
 static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER;
 
 static void
-restore_sigint_handler ()
+restore_sigint_handler (void)
 {
   if (old_sigint_handler != INVALID_SIGNAL_HANDLER)
     {
@@ -732,8 +750,7 @@ restore_sigint_handler ()
    All interrupts are effectively ignored by the shell, but allowed to
    kill a running job. */
 static sighandler
-wait_sigint_handler (sig)
-     int sig;
+wait_sigint_handler (int sig)
 {
   SigHandler *sigint_handler;
 
@@ -745,28 +762,18 @@ wait_sigint_handler (sig)
     {
       last_command_exit_value = 128+SIGINT;
       restore_sigint_handler ();
-      interrupt_immediately = 0;
       trap_handler (SIGINT);   /* set pending_traps[SIGINT] */
       wait_signal_received = SIGINT;
       SIGRETURN (0);
     }
 
-  if (interrupt_immediately)
-    {
-      last_command_exit_value = EXECUTION_FAILURE;
-      restore_sigint_handler ();
-      ADDINTERRUPT;
-      QUIT;
-    }
-
   wait_sigint_received = 1;
 
   SIGRETURN (0);
 }
 
 static char *
-j_strsignal (s)
-     int s;
+j_strsignal (int s)
 {
   static char retcode_name_buffer[64] = { '\0' };
   char *x;
@@ -783,8 +790,7 @@ j_strsignal (s)
 /* Wait for pid (one of our children) to terminate.  This is called only
    by the execution code in execute_cmd.c. */
 int
-wait_for (pid)
-     pid_t pid;
+wait_for (pid_t pid, int flags)
 {
   int return_val, pstatus;
   pid_t got_pid;
@@ -808,8 +814,11 @@ wait_for (pid)
   if (interactive_shell == 0)
     old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
 
+  waiting_for_child = 1;  
+  CHECK_WAIT_INTR;
   while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */
     {
+      waiting_for_child = 0;
       CHECK_TERMSIG;
       CHECK_WAIT_INTR;
       if (got_pid < 0 && errno == ECHILD)
@@ -825,7 +834,9 @@ wait_for (pid)
        programming_error ("wait_for(%ld): %s", (long)pid, strerror(errno));
       else if (got_pid > 0)
        set_pid_status (got_pid, status);
+      waiting_for_child = 1;
     }
+  waiting_for_child = 0;
 
   if (got_pid > 0)
     set_pid_status (got_pid, status);
@@ -899,9 +910,7 @@ wait_for (pid)
 /* Send PID SIGNAL.  Returns -1 on failure, 0 on success.  If GROUP is non-zero,
    or PID is less than -1, then kill the process group associated with PID. */
 int
-kill_pid (pid, signal, group)
-     pid_t pid;
-     int signal, group;
+kill_pid (pid_t pid, int signal, int group)
 {
   int result;
 
@@ -918,7 +927,8 @@ static TTYSTRUCT shell_tty_info;
 static int got_tty_state;
 
 /* Fill the contents of shell_tty_info with the current tty info. */
-get_tty_state ()
+int
+get_tty_state (void)
 {
   int tty;
 
@@ -930,11 +940,12 @@ get_tty_state ()
       if (check_window_size)
        get_new_window_size (0, (int *)0, (int *)0);
     }
+  return 0;
 }
 
 /* Make the current tty use the state in shell_tty_info. */
 int
-set_tty_state ()
+set_tty_state (void)
 {
   int tty;
 
@@ -949,38 +960,42 @@ set_tty_state ()
 }
 
 /* Give the terminal to PGRP.  */
-give_terminal_to (pgrp, force)
-     pid_t pgrp;
-     int force;
+int
+give_terminal_to (pid_t pgrp, int force)
 {
+  return 0;
 }
 
 /* Stop a pipeline. */
 int
-stop_pipeline (async, ignore)
-     int async;
-     COMMAND *ignore;
+stop_pipeline (int async, COMMAND *ignore)
 {
   already_making_children = 0;
   return 0;
 }
 
 void
-start_pipeline ()
+start_pipeline (void)
 {
   already_making_children = 1;
 }
 
 void
-stop_making_children ()
+stop_making_children (void)
 {
   already_making_children = 0;
 }
 
+/* The name is kind of a misnomer, but it's what the job control code uses. */
+void
+without_job_control (void)
+{
+  stop_making_children ();
+  last_made_pid = NO_PID;      /* XXX */
+}
+
 int
-get_job_by_pid (pid, block)
-     pid_t pid;
-     int block;
+get_job_by_pid (pid_t pid, int block, PROCESS **ignore)
 {
   int i;
 
@@ -990,24 +1005,42 @@ get_job_by_pid (pid, block)
 
 /* Print descriptive information about the job with leader pid PID. */
 void
-describe_pid (pid)
-     pid_t pid;
+describe_pid (pid_t pid)
 {
   fprintf (stderr, "%ld\n", (long) pid);
 }
 
 int
-freeze_jobs_list ()
+freeze_jobs_list (void)
 {
+  return 0;
+}
+
+int
+unfreeze_jobs_list (void)
+{
+  return 0;
 }
 
 void
-unfreeze_jobs_list ()
+set_jobs_list_frozen (int s)
+{
+}
+
+int
+jobs_list_frozen_status (void)
 {
+  return 0;
+}
+
+int
+count_all_jobs (void)
+{
+  return 0;
 }
 
 int
-count_all_jobs ()
+job_control_active_p (void)
 {
   return 0;
 }