summaryrefslogtreecommitdiff
path: root/data/bash/bash32-035
blob: 55506baef4a656e1a4cc523e812356da4fa7d1af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
			     BASH PATCH REPORT
			     =================

Bash-Release: 3.2
Patch-ID: bash32-035

Bug-Reported-by:	Ingo Molnar <mingo@elte.hu>
Bug-Reference-ID:	<20071205202901.GA25202@elte.hu>
Bug-Reference-URL:	http://lists.gnu.org/archive/html/bug-bash/2007-12/msg00014.html

Bug-Description:

Bash incorrectly puts the second and subsequent children spawned by a
shell forked to run a command substitution in the wrong process group.

Patch:

*** ../bash-3.2-patched/subst.c	2007-12-13 22:31:21.000000000 -0500
--- subst.c	2008-01-17 22:48:15.000000000 -0500
***************
*** 4621,4627 ****
  
  #if defined (JOB_CONTROL)
    set_sigchld_handler ();
    stop_making_children ();
!   pipeline_pgrp = old_pipeline_pgrp;
  #else
    stop_making_children ();
--- 4721,4728 ----
  
  #if defined (JOB_CONTROL)
    set_sigchld_handler ();
    stop_making_children ();
!   if (pid != 0)
!     pipeline_pgrp = old_pipeline_pgrp;
  #else
    stop_making_children ();
*** ../bash-3.2-patched/jobs.c	2007-08-25 13:46:59.000000000 -0400
--- jobs.c	2007-12-08 16:47:43.000000000 -0500
***************
*** 251,254 ****
--- 251,255 ----
  static int set_job_status_and_cleanup __P((int));
  
+ static WAIT job_signal_status __P((int));
  static WAIT raw_job_exit_status __P((int));
  
***************
*** 2220,2223 ****
--- 2238,2261 ----
  }
  
+ static WAIT
+ job_signal_status (job)
+      int job;
+ {
+   register PROCESS *p;
+   WAIT s;
+ 
+   p = jobs[job]->pipe;
+   do
+     {
+       s = p->status;
+       if (WIFSIGNALED(s) || WIFSTOPPED(s))
+ 	break;
+       p = p->next;
+     }
+   while (p != jobs[job]->pipe);
+ 
+   return s;
+ }
+   
  /* Return the exit status of the last process in the pipeline for job JOB.
     This is the exit status of the entire job. */
***************
*** 2302,2310 ****
       received, only if one of the jobs run is killed via SIGINT.  If
       job control is not set, the job will be run in the same pgrp as
!      the shell, and the shell will see any signals the job gets. */
  
    /* This is possibly a race condition -- should it go in stop_pipeline? */
    wait_sigint_received = 0;
!   if (job_control == 0)
      {
        old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
--- 2343,2354 ----
       received, only if one of the jobs run is killed via SIGINT.  If
       job control is not set, the job will be run in the same pgrp as
!      the shell, and the shell will see any signals the job gets.  In
!      fact, we want this set every time the waiting shell and the waited-
!      for process are in the same process group, including command
!      substitution. */
  
    /* This is possibly a race condition -- should it go in stop_pipeline? */
    wait_sigint_received = 0;
!   if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB))
      {
        old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
***************
*** 2452,2464 ****
  	     the last process in the pipeline.  If no process exits due to a
  	     signal, S is left as the status of the last job in the pipeline. */
! 	  p = jobs[job]->pipe;
! 	  do
! 	    {
! 	      s = p->status;
! 	      if (WIFSIGNALED(s) || WIFSTOPPED(s))
! 		break;
! 	      p = p->next;
! 	    }
! 	  while (p != jobs[job]->pipe);
  
  	  if (WIFSIGNALED (s) || WIFSTOPPED (s))
--- 2496,2500 ----
  	     the last process in the pipeline.  If no process exits due to a
  	     signal, S is left as the status of the last job in the pipeline. */
! 	  s = job_signal_status (job);
  
  	  if (WIFSIGNALED (s) || WIFSTOPPED (s))
***************
*** 2494,2497 ****
--- 2530,2551 ----
  	    }
  	}
+       else if ((subshell_environment & SUBSHELL_COMSUB) && wait_sigint_received)
+ 	{
+ 	  /* If waiting for a job in a subshell started to do command
+ 	     substitution, simulate getting and being killed by the SIGINT to
+ 	     pass the status back to our parent. */
+ 	  s = job_signal_status (job);
+ 	
+ 	  if (WIFSIGNALED (s) && WTERMSIG (s) == SIGINT && signal_is_trapped (SIGINT) == 0)
+ 	    {
+ 	      UNBLOCK_CHILD (oset);
+ 	      restore_sigint_handler ();
+ 	      old_sigint_handler = set_signal_handler (SIGINT, SIG_DFL);
+ 	      if (old_sigint_handler == SIG_IGN)
+ 		restore_sigint_handler ();
+ 	      else
+ 		kill (getpid (), SIGINT);
+ 	    }
+ 	}
  
        /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
*** ../bash-3.2/patchlevel.h	Thu Apr 13 08:31:04 2006
--- patchlevel.h	Mon Oct 16 14:22:54 2006
***************
*** 26,30 ****
     looks for to find the patch level (for the sccs version string). */
  
! #define PATCHLEVEL 34
  
  #endif /* _PATCHLEVEL_H_ */
--- 26,30 ----
     looks for to find the patch level (for the sccs version string). */
  
! #define PATCHLEVEL 35
  
  #endif /* _PATCHLEVEL_H_ */