aboutsummaryrefslogtreecommitdiffstats
path: root/jobs.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2004-07-27 13:29:18 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:56 +0000
commitb80f6443b6b7b620c7272664c66ecb0b120a0998 (patch)
tree9f71c98d8fe8fa0f41d95e1eb4227f32a09d43ca /jobs.c
parent7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (diff)
downloadandroid_external_bash-b80f6443b6b7b620c7272664c66ecb0b120a0998.tar.gz
android_external_bash-b80f6443b6b7b620c7272664c66ecb0b120a0998.tar.bz2
android_external_bash-b80f6443b6b7b620c7272664c66ecb0b120a0998.zip
Imported from ../bash-3.0.tar.gz.
Diffstat (limited to 'jobs.c')
-rw-r--r--jobs.c142
1 files changed, 104 insertions, 38 deletions
diff --git a/jobs.c b/jobs.c
index 2bcb3ac..8418267 100644
--- a/jobs.c
+++ b/jobs.c
@@ -3,7 +3,7 @@
/* This file works with both POSIX and BSD systems. It implements job
control. */
-/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -39,7 +39,10 @@
# include <sys/resource.h>
#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */
-#include <sys/file.h>
+#if defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+
#include "filecntl.h"
#include <sys/ioctl.h>
#include <sys/param.h>
@@ -72,6 +75,7 @@
#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */
#include "bashansi.h"
+#include "bashintl.h"
#include "shell.h"
#include "jobs.h"
#include "flags.h"
@@ -127,6 +131,8 @@ extern int errno;
/* Some systems let waitpid(2) tell callers about stopped children. */
#if !defined (WCONTINUED)
# define WCONTINUED 0
+#endif
+#if !defined (WIFCONTINUED)
# define WIFCONTINUED(s) (0)
#endif
@@ -142,7 +148,8 @@ extern void rl_set_screen_size __P((int, int));
/* Variables used here but defined in other files. */
extern int subshell_environment, line_number;
extern int posixly_correct, shell_level;
-extern int interrupt_immediately, last_command_exit_value;
+extern int interrupt_immediately;
+extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
extern sh_builtin_func_t *this_shell_builtin;
@@ -223,6 +230,7 @@ static PROCESS *find_pipeline __P((pid_t, int, int *));
static char *current_working_directory __P((void));
static char *job_working_directory __P((void));
+static char *j_strsignal __P((int));
static char *printable_job_status __P((int, PROCESS *, int));
static pid_t find_last_pid __P((int, int));
@@ -235,7 +243,9 @@ static int most_recent_job_in_state __P((int, JOB_STATE));
static int find_job __P((pid_t, int));
static int print_job __P((JOB *, int, int, int));
static int process_exit_status __P((WAIT));
+static int process_exit_signal __P((WAIT));
static int job_exit_status __P((int));
+static int job_exit_signal __P((int));
static int set_job_status_and_cleanup __P((int));
static WAIT raw_job_exit_status __P((int));
@@ -466,6 +476,7 @@ stop_pipeline (async, deferred)
}
/* Scan from the last slot backward, looking for the next free one. */
+ /* XXX - revisit this interactive assumption */
if (interactive)
{
for (i = job_slots; i; i--)
@@ -680,7 +691,7 @@ delete_job (job_index, warn_stopped)
return;
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
- internal_warning ("deleting stopped job %d with process group %ld", job_index+1, (long)jobs[job_index]->pgrp);
+ internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
if (job_index == current_job || job_index == previous_job)
@@ -988,12 +999,27 @@ describe_pid (pid)
if (job != NO_JOB)
printf ("[%d] %ld\n", job + 1, (long)pid);
else
- programming_error ("describe_pid: %ld: no such pid", (long)pid);
+ programming_error (_("describe_pid: %ld: no such pid"), (long)pid);
UNBLOCK_CHILD (oset);
}
static char *
+j_strsignal (s)
+ int s;
+{
+ char *x;
+
+ x = strsignal (s);
+ if (x == 0)
+ {
+ x = retcode_name_buffer;
+ sprintf (x, "Signal %d", s);
+ }
+ return x;
+}
+
+static char *
printable_job_status (j, p, format)
int j;
PROCESS *p;
@@ -1019,9 +1045,9 @@ printable_job_status (j, p, format)
else
{
if (WIFSTOPPED (p->status))
- temp = strsignal (WSTOPSIG (p->status));
+ temp = j_strsignal (WSTOPSIG (p->status));
else if (WIFSIGNALED (p->status))
- temp = strsignal (WTERMSIG (p->status));
+ temp = j_strsignal (WTERMSIG (p->status));
else if (WIFEXITED (p->status))
{
temp = retcode_name_buffer;
@@ -1333,22 +1359,19 @@ make_child (command, async_p)
shells. */
if (setpgid (mypid, pipeline_pgrp) < 0)
sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp);
-#if defined (PGRP_PIPE)
- if (pipeline_pgrp == mypid)
- {
-#endif
- /* By convention (and assumption above), if
- pipeline_pgrp == shell_pgrp, we are making a child for
- command substitution.
- In this case, we don't want to give the terminal to the
- shell's process group (we could be in the middle of a
- pipeline, for example). */
- if (async_p == 0 && pipeline_pgrp != shell_pgrp)
- give_terminal_to (pipeline_pgrp, 0);
+
+ /* By convention (and assumption above), if
+ pipeline_pgrp == shell_pgrp, we are making a child for
+ command substitution.
+ In this case, we don't want to give the terminal to the
+ shell's process group (we could be in the middle of a
+ pipeline, for example). */
+ if (async_p == 0 && pipeline_pgrp != shell_pgrp)
+ give_terminal_to (pipeline_pgrp, 0);
#if defined (PGRP_PIPE)
- pipe_read (pgrp_pipe);
- }
+ if (pipeline_pgrp == mypid)
+ pipe_read (pgrp_pipe);
#endif
}
else /* Without job control... */
@@ -1607,7 +1630,7 @@ wait_for_single_pid (pid)
if (child == 0)
{
- 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);
}
@@ -1725,6 +1748,13 @@ wait_sigint_handler (sig)
}
static int
+process_exit_signal (status)
+ WAIT status;
+{
+ return (WIFSIGNALED (status) ? WTERMSIG (status) : 0);
+}
+
+static int
process_exit_status (status)
WAIT status;
{
@@ -1743,6 +1773,16 @@ raw_job_exit_status (job)
int job;
{
register PROCESS *p;
+ int fail;
+
+ if (pipefail_opt)
+ {
+ fail = 0;
+ for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)
+ if (p->status != EXECUTION_SUCCESS) fail = p->status;
+ return fail;
+ }
+
for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)
;
return (p->status);
@@ -1758,6 +1798,13 @@ job_exit_status (job)
return (process_exit_status (raw_job_exit_status (job)));
}
+static int
+job_exit_signal (job)
+ int job;
+{
+ return (process_exit_signal (raw_job_exit_status (job)));
+}
+
#define FIND_CHILD(pid, child) \
do \
{ \
@@ -1766,7 +1813,7 @@ job_exit_status (job)
{ \
give_terminal_to (shell_pgrp, 0); \
UNBLOCK_CHILD (oset); \
- internal_error ("wait_for: No record of process %ld", (long)pid); \
+ internal_error (_("wait_for: No record of process %ld"), (long)pid); \
restore_sigint_handler (); \
return (termination_state = 127); \
} \
@@ -1885,11 +1932,12 @@ wait_for (pid)
/* The exit state of the command is either the termination state of the
child, or the termination state of the job. If a job, the status
- of the last child in the pipeline is the significant one. */
- if (job != NO_JOB)
- termination_state = job_exit_status (job);
- else
- termination_state = process_exit_status (child->status);
+ of the last child in the pipeline is the significant one. If the command
+ or job was terminated by a signal, note that value also. */
+ termination_state = (job != NO_JOB) ? job_exit_status (job)
+ : process_exit_status (child->status);
+ last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job)
+ : process_exit_signal (child->status);
if (job == NO_JOB || IS_JOBCONTROL (job))
{
@@ -1949,7 +1997,7 @@ if (job == NO_JOB)
/* If the current job was stopped or killed by a signal, and
the user has requested it, get a possibly new window size */
- if (check_window_size && job == current_job)
+ if (check_window_size && (job == current_job || IS_FOREGROUND (job)))
get_new_window_size (0);
}
else
@@ -2012,7 +2060,7 @@ wait_for_job (job)
BLOCK_CHILD(set, oset);
if (JOBSTATE (job) == JSTOPPED)
- internal_warning ("wait_for_job: job %d is stopped", job+1);
+ internal_warning (_("wait_for_job: job %d is stopped"), job+1);
pid = find_last_pid (job, 0);
UNBLOCK_CHILD(oset);
@@ -2234,7 +2282,7 @@ start_job (job, foreground)
if (DEADJOB (job))
{
- internal_error ("%s: job has terminated", this_command_name);
+ internal_error (_("%s: job has terminated"), this_command_name);
UNBLOCK_CHILD (oset);
return (-1);
}
@@ -2243,7 +2291,7 @@ start_job (job, foreground)
if (foreground == 0 && already_running)
{
- internal_error ("%s: bg background job?", this_command_name);
+ internal_error (_("%s: job %d already in background"), this_command_name, job + 1);
UNBLOCK_CHILD (oset);
return (-1);
}
@@ -2733,6 +2781,7 @@ run_sigchld_trap (nchild)
begin_unwind_frame ("SIGCHLD trap");
unwind_protect_int (last_command_exit_value);
+ unwind_protect_int (last_command_exit_signal);
unwind_protect_var (last_made_pid);
unwind_protect_int (interrupt_immediately);
unwind_protect_int (jobs_list_frozen);
@@ -2742,8 +2791,8 @@ run_sigchld_trap (nchild)
/* We have to add the commands this way because they will be run
in reverse order of adding. We don't want maybe_set_sigchld_trap ()
to reference freed memory. */
- add_unwind_protect ((Function *)xfree, trap_command);
- add_unwind_protect ((Function *)maybe_set_sigchld_trap, trap_command);
+ add_unwind_protect (xfree, trap_command);
+ add_unwind_protect (maybe_set_sigchld_trap, trap_command);
subst_assign_varlist = (WORD_LIST *)NULL;
the_pipeline = (PROCESS *)NULL;
@@ -2753,7 +2802,7 @@ run_sigchld_trap (nchild)
for (i = 0; i < nchild; i++)
{
interrupt_immediately = 1;
- parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST);
+ parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE);
}
run_unwind_frame ("SIGCHLD trap");
@@ -2800,11 +2849,21 @@ notify_of_job_status ()
((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
continue;
+#if 0
/* If job control is disabled, don't print the status messages.
Mark dead jobs as notified so that they get cleaned up. If
startup_state == 2, we were started to run `-c command', so
don't print anything. */
if ((job_control == 0 && interactive_shell) || startup_state == 2)
+#else
+ /* If job control is disabled, don't print the status messages.
+ Mark dead jobs as notified so that they get cleaned up. If
+ startup_state == 2 and subshell_environment has the
+ SUBSHELL_COMSUB bit turned on, we were started to run a command
+ substitution, so don't print anything. */
+ if ((job_control == 0 && interactive_shell) ||
+ (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB)))
+#endif
{
/* POSIX.2 compatibility: if the shell is not interactive,
hang onto the job corresponding to the last asynchronous
@@ -2828,7 +2887,8 @@ notify_of_job_status ()
#endif
signal_is_trapped (termsig) == 0)
{
- fprintf (stderr, "%s: line %d: ", get_name_for_error (), line_number);
+ /* Don't print `0' for a line number. */
+ fprintf (stderr, "%s: line %d: ", get_name_for_error (), (line_number == 0) ? 1 : line_number);
pretty_print_job (job, JLIST_NONINTERACTIVE, stderr);
}
else if (IS_FOREGROUND (job))
@@ -2839,7 +2899,7 @@ notify_of_job_status ()
if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE)
#endif
{
- fprintf (stderr, "%s", strsignal (termsig));
+ fprintf (stderr, "%s", j_strsignal (termsig));
if (WIFCORED (s))
fprintf (stderr, " (core dumped)");
@@ -2975,7 +3035,7 @@ initialize_job_control (force)
}
}
if (job_control == 0)
- internal_error ("no job control in this shell");
+ internal_error (_("no job control in this shell"));
}
if (shell_tty != fileno (stderr))
@@ -3374,6 +3434,12 @@ set_job_control (arg)
old = job_control;
job_control = arg;
+
+ /* If we're turning on job control, reset pipeline_pgrp so make_child will
+ put new child processes into the right pgrp */
+ if (job_control != old && job_control)
+ pipeline_pgrp = 0;
+
return (old);
}