summaryrefslogtreecommitdiff
path: root/nojobs.c
diff options
context:
space:
mode:
Diffstat (limited to 'nojobs.c')
-rw-r--r--nojobs.c121
1 files changed, 110 insertions, 11 deletions
diff --git a/nojobs.c b/nojobs.c
index 77632835..df543ac8 100644
--- a/nojobs.c
+++ b/nojobs.c
@@ -52,6 +52,8 @@
# endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */
#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */
+#include "bashintl.h"
+
#include "shell.h"
#include "jobs.h"
@@ -63,9 +65,9 @@
# define killpg(pg, sig) kill(-(pg),(sig))
#endif /* USG || _POSIX_VERSION */
-#if !defined (HAVE_SIGINTERRUPT)
+#if !defined (HAVE_SIGINTERRUPT) && !defined (HAVE_POSIX_SIGNALS)
# define siginterrupt(sig, code)
-#endif /* !HAVE_SIGINTERRUPT */
+#endif /* !HAVE_SIGINTERRUPT && !HAVE_POSIX_SIGNALS */
#if defined (HAVE_WAITPID)
# define WAITPID(pid, statusp, options) waitpid (pid, statusp, options)
@@ -86,7 +88,7 @@ extern void rl_set_screen_size __P((int, int));
extern int interactive, interactive_shell, login_shell;
extern int subshell_environment;
-extern int last_command_exit_value;
+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)
@@ -120,6 +122,7 @@ struct proc_status {
#define PROC_RUNNING 0x01
#define PROC_NOTIFIED 0x02
#define PROC_ASYNC 0x04
+#define PROC_SIGNALED 0x10
/* Return values from find_status_by_pid */
#define PROC_BAD -1
@@ -136,20 +139,28 @@ static int find_proc_slot __P((void));
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 void get_new_window_size __P((int));
static sighandler sigwinch_sighandler __P((int));
static sighandler wait_sigint_handler __P((int));
+static char *j_strsignal __P((int));
#if defined (HAVE_WAITPID)
static void reap_zombie_children __P((void));
#endif
+#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS)
+static int siginterrupt __P((int, int));
+#endif
+
static void restore_sigint_handler __P((void));
/* Allocate new, or grow existing PID_LIST. */
@@ -225,6 +236,35 @@ process_exit_status (status)
return (WEXITSTATUS (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;
+{
+ int i;
+
+ i = find_index_by_pid (pid);
+ if (i == NO_PID)
+ return (0);
+ if (pid_list[i].flags & PROC_RUNNING)
+ return (0);
+ return (get_termsig (pid_list[i].status));
+}
+
+/* Set LAST_COMMAND_EXIT_SIGNAL depending on STATUS. If STATUS is -1, look
+ 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;
+{
+ if (WIFSTOPPED (status) == 0 && WIFSIGNALED (status))
+ return (WTERMSIG (status));
+ else
+ return (0);
+}
+
/* Give PID the status value STATUS in the PID_LIST array. */
static void
set_pid_status (pid, status)
@@ -239,6 +279,8 @@ set_pid_status (pid, status)
pid_list[slot].status = process_exit_status (status);
pid_list[slot].flags &= ~PROC_RUNNING;
+ if (WIFSIGNALED (status))
+ pid_list[slot].flags |= PROC_SIGNALED;
/* If it's not a background process, mark it as notified so it gets
cleaned up. */
if ((pid_list[slot].flags & PROC_ASYNC) == 0)
@@ -275,6 +317,20 @@ unset_pid_flags (pid, flags)
pid_list[slot].flags &= ~flags;
}
+/* Return the flags corresponding to PID in the PID_LIST array. */
+static int
+get_pid_flags (pid)
+ pid_t pid;
+{
+ int slot;
+
+ slot = find_index_by_pid (pid);
+ if (slot == NO_PID)
+ return 0;
+
+ return (pid_list[slot].flags);
+}
+
static void
add_pid (pid, async)
pid_t pid;
@@ -444,15 +500,33 @@ initialize_job_signals ()
static void
reap_zombie_children ()
{
-#if defined (WNOHANG)
+# if defined (WNOHANG)
pid_t pid;
WAIT status;
while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0)
set_pid_status (pid, status);
-#endif
+# endif /* WNOHANG */
}
-#endif /* WAITPID && WNOHANG */
+#endif /* WAITPID */
+
+#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS)
+static int
+siginterrupt (sig, flag)
+ int sig, flag;
+{
+ struct sigaction act;
+
+ sigaction (sig, (struct sigaction *)NULL, &act);
+
+ if (flag)
+ act.sa_flags &= ~SA_RESTART;
+ else
+ act.sa_flags |= SA_RESTART;
+
+ return (sigaction (sig, &act, (struct sigaction *)NULL));
+}
+#endif /* !HAVE_SIGINTERRUPT && HAVE_POSIX_SIGNALS */
/* Fork, handling errors. Returns the pid of the newly made child, or 0.
COMMAND is just for remembering the name of the command; we don't do
@@ -565,18 +639,22 @@ wait_for_single_pid (pid)
{
pid_t got_pid;
WAIT status;
- int pstatus;
+ int pstatus, flags;
pstatus = find_status_by_pid (pid);
if (pstatus == PROC_BAD)
{
- internal_error ("wait: pid %ld is not a child of this shell", (long)pid);
+ internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
return (127);
}
if (pstatus != PROC_STILL_ALIVE)
- return (pstatus);
+ {
+ if (pstatus > 128)
+ last_command_exit_signal = find_termsig_by_pid (pid);
+ return (pstatus);
+ }
siginterrupt (SIGINT, 1);
while ((got_pid = WAITPID (pid, &status, 0)) != pid)
@@ -688,6 +766,22 @@ wait_sigint_handler (sig)
SIGRETURN (0);
}
+static char *
+j_strsignal (s)
+ int s;
+{
+ static char retcode_name_buffer[64] = { '\0' };
+ char *x;
+
+ x = strsignal (s);
+ if (x == 0)
+ {
+ x = retcode_name_buffer;
+ sprintf (x, "Signal %d", s);
+ }
+ return x;
+}
+
/* Wait for pid (one of our children) to terminate. This is called only
by the execution code in execute_cmd.c. */
int
@@ -704,7 +798,11 @@ wait_for (pid)
return (0);
if (pstatus != PROC_STILL_ALIVE)
- return (pstatus);
+ {
+ if (pstatus > 128)
+ last_command_exit_signal = find_termsig_by_pid (pid);
+ return (pstatus);
+ }
/* If we are running a script, ignore SIGINT while we're waiting for
a child to exit. The loop below does some of this, but not all. */
@@ -762,6 +860,7 @@ wait_for (pid)
/* Default return value. */
/* ``a full 8 bits of status is returned'' */
return_val = process_exit_status (status);
+ last_command_exit_signal = get_termsig (status);
#if !defined (DONT_REPORT_SIGPIPE)
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
@@ -771,7 +870,7 @@ wait_for (pid)
(WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE))
#endif
{
- fprintf (stderr, "%s", strsignal (WTERMSIG (status)));
+ fprintf (stderr, "%s", j_strsignal (WTERMSIG (status)));
if (WIFCORED (status))
fprintf (stderr, " (core dumped)");
fprintf (stderr, "\n");