token. This lets the higher layers deal with quoted newlines after
the command substitution. Fixes bug reported by EmanueL Czirai
<amanual@riseup.net>
+
+ 8/11
+ ----
+execute_cmd.c
+ - execute_pipeline: check whether lastpipe_jid corresponds to a valid
+ job before calling append_process, for the same reason as fix from
+ 6/19. Fixes bug reported by <lolilolicon@gmail.com>
+
+ 8/12
+ ----
+lib/sh/unicode.c
+ - stub_charset: use strncpy instead of strcpy because we are copying
+ into a local fixed-length buffer. Fixes vulnerability reported by
+ <romerox.adrian@gmail.com>
+
+execute_cmd.c
+ - execute_pipeline: if we don't call append_process, call
+ wait_for_single_pid to get the status of `lastpid', since that will
+ check the status of already-reaped processes. Fixes spurious error
+ message about non-existent process from fix of 8/11
+
+ 8/15
+ ----
+jobs.c
+ - running_in_background: new variable, keeps track of whether or not we
+ are running in the background (not perfect yet)
+ - initialize_job_control: even if we are not turning on job control,
+ get the terminal pgrp so we can use it later
+ - {set_job_control,initialize_job_control}: set running_in_background
+ to 1 if terminal pgrp != shell pgrp
+ - {stop_pipeline,make_child,wait_for}: if we are running in the
+ background, don't mess with the terminal's process group; assume that
+ the parent shell will do that. Fixes bug reprted by Greg Wooledge
+ <wooledg@eeg.ccf.org>
+
+shell.c
+ - shell_reinitialize: reset running_in_background back to 0
login_shell = interactive = 0;
if (user_subshell)
- subshell_environment = SUBSHELL_PAREN;
+ subshell_environment = SUBSHELL_PAREN; /* XXX */
else
{
subshell_environment = 0; /* XXX */
if (lastpipe_flag)
{
#if defined (JOB_CONTROL)
- append_process (savestring (the_printed_command), dollar_dollar_pid, exec_result, lastpipe_jid);
-#endif
+ if (INVALID_JOB (lastpipe_jid) == 0)
+ {
+ append_process (savestring (the_printed_command_except_trap), dollar_dollar_pid, exec_result, lastpipe_jid);
+ lstdin = wait_for (lastpid);
+ }
+ else
+ lstdin = wait_for_single_pid (lastpid); /* checks bgpids list */
+#else
lstdin = wait_for (lastpid);
+#endif
+
#if defined (JOB_CONTROL)
/* If wait_for removes the job from the jobs table, use result of last
command as pipeline's exit status as usual. The jobs list can get
already_forked = 1;
simple_command->flags |= CMD_NO_FORK;
- subshell_environment = SUBSHELL_FORK;
+ subshell_environment = SUBSHELL_FORK; /* XXX */
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
subshell_environment |= SUBSHELL_PIPE;
if (async)
if (async)
interactive = 0;
- subshell_environment = SUBSHELL_FORK;
+ subshell_environment = SUBSHELL_FORK; /* XXX */
if (redirects && (do_redirections (redirects, RX_ACTIVE) != 0))
{
/* If this is non-zero, do job control. */
int job_control = 1;
+/* Are we running in background? (terminal_pgrp != shell_pgrp) */
+int running_in_background = 0;
+
/* Call this when you start making children. */
int already_making_children = 0;
* the parent gives it away.
*
* Don't give the terminal away if this shell is an asynchronous
- * subshell.
+ * subshell or if we're a (presumably non-interactive) shell running
+ * in the background.
*
*/
- if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0)
+ if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0 && running_in_background == 0)
maybe_give_terminal_to (shell_pgrp, newjob->pgrp, 0);
}
}
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 && ((subshell_environment&SUBSHELL_ASYNC) == 0))
+ if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0) && running_in_background == 0)
give_terminal_to (pipeline_pgrp, 0);
#if defined (PGRP_PIPE)
if (job == NO_JOB)
itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);
#endif
- give_terminal_to (shell_pgrp, 0);
+ /* Don't modify terminal pgrp if we are running in the background */
+ if (running_in_background == 0)
+ give_terminal_to (shell_pgrp, 0);
}
/* If the command did not exit cleanly, or the job is just
job_control = 0;
original_pgrp = NO_PID;
shell_tty = fileno (stderr);
+ terminal_pgrp = tcgetpgrp (shell_tty); /* for checking later */
}
else
{
internal_error (_("no job control in this shell"));
}
+ running_in_background = terminal_pgrp != shell_pgrp;
+
if (shell_tty != fileno (stderr))
SET_CLOSE_ON_EXEC (shell_tty);
else if (tpgrp != opgrp)
{
#if defined (DEBUG)
- internal_warning ("maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d", tpgrp, opgrp, npgrp);
+ internal_warning ("%d: maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d in_background = %d", (int)getpid(), tpgrp, opgrp, npgrp, running_in_background);
#endif
return -1;
}
old = job_control;
job_control = arg;
+ if (terminal_pgrp == NO_PID)
+ terminal_pgrp = tcgetpgrp (shell_tty);
+
+ running_in_background = (terminal_pgrp != shell_pgrp);
+
+#if 0
+ if (interactive_shell == 0 && running_in_background == 0 && job_control != old)
+ {
+ if (job_control)
+ initialize_job_signals ();
+ else
+ default_tty_job_signals ();
+ }
+#endif
+
/* 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)
s = strrchr (locale, '.');
if (s)
{
- strcpy (charsetbuf, s+1);
+ strncpy (charsetbuf, s+1, sizeof (charsetbuf) - 1);
+ charsetbuf[sizeof (charsetbuf) - 1] = '\0';
t = strchr (charsetbuf, '@');
if (t)
*t = 0;
return charsetbuf;
}
- strcpy (charsetbuf, locale);
+ strncpy (charsetbuf, locale, sizeof (charsetbuf) - 1);
+ charsetbuf[sizeof (charsetbuf) - 1] = '\0';
return charsetbuf;
}
#endif
/* We don't have job control. */
int job_control = 0;
+int running_in_background = 0; /* can't tell without job control */
+
/* STATUS and FLAGS are only valid if pid != NO_PID
STATUS is only valid if (flags & PROC_RUNNING) == 0 */
struct proc_status {
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 22
+#define PATCHLEVEL 24
#endif /* _PATCHLEVEL_H_ */
extern int patch_level, build_version;
extern int shell_level;
extern int subshell_environment;
+extern int running_in_background;
extern int last_command_exit_value;
extern int line_number;
extern int expand_aliases;
/* Things that get 0. */
login_shell = make_login_shell = interactive = executing = 0;
debugging = do_version = line_number = last_command_exit_value = 0;
- forced_interactive = interactive_shell = subshell_environment = 0;
+ forced_interactive = interactive_shell = 0;
+ subshell_environment = running_in_background = 0;
expand_aliases = 0;
/* XXX - should we set jobs_m_flag to 0 here? */