[gnu.bash.bug] Bash 1.04 patch: 'union wait' for SysV

chip@ateng.ateng.com (Chip Salzenberg) (01/23/90)

As distributed, Bash 1.04 includes a SysV emulation of the BSD "union wait".
This emulation is slightly broken.  It is also unnecessarily complex and
non-portable.  This patch fixes the bugs and implements the wait() call in a
way that should be portable even to BSD.  (After all, "union wait" is an
optional sugar-coating on the raw V7 semantics of wait().)

Index: jobs.h
***************
*** 6,73 ****
  #include <sys/wait.h>
  #else
- 
- #if defined (i386) || defined (ATT3B) || defined (ATT386)
- 
- union wait {
-   struct {
-     unsigned char low;
-     unsigned char high;
-   }
-   bytes;
-   short word;
- };
- 
- #define WSTOPPED 0177
- #define w_status word
- #define w_termsig bytes.low & 0x7f
- #define w_stopsig bytes.high
- #define w_retcode bytes.high
- #define w_coredump w_termsig & ~0x7f
- #define WIFEXITED(wstat) ((wstat).bytes.low == 0)
- #define WIFSTOPPED(wstat) ((wstat).bytes.low == 0177)
- #define WIFTERMINATED(wstat) ((wstat).bytes.high == 0)
- 
- #else  /* i386 || ATT3B || ATT386 */
- 
- #ifdef NO_WAIT_H
  union wait
    {
!     int	w_status;		/* used in syscall */
! 
!     /* Terminated process status. */
!     struct
!       {
! 	unsigned short
! 	  w_Fill1    : 16,	/* high 16 bits unused */
! 	  w_Retcode  : 8,	/* exit code if w_termsig==0 */
! 	  w_Coredump : 1,	/* core dump indicator */
! 	  w_Termsig  : 7;	/* termination signal */
!       } w_T;
! 
!     /* Stopped process status.  Returned
!        only for traced children unless requested
!        with the WUNTRACED option bit. */
!     struct
!       {
! 	unsigned short
! 	  w_Fill2   : 16,	/* high 16 bits unused */
! 	  w_Stopsig : 8,	/* signal that stopped us */
! 	  w_Stopval : 8;	/* == W_STOPPED if stopped */
!       } w_S;
    };
- 
- #define	w_termsig w_T.w_Termsig
- #define w_coredump w_T.w_Coredump
- #define w_retcode w_T.w_Retcode
- #define w_stopval w_S.w_Stopval
- #define w_stopsig w_S.w_Stopsig
- 
- #define	WSTOPPED 0177
- #define WIFSTOPPED(x) (((x) . w_stopval) == WSTOPPED)
- #define WIFEXITED(x) ((! (WIFSTOPPED (x))) && (((x) . w_termsig) == 0))
- #define WIFSIGNALED(x) ((! (WIFSTOPPED (x))) && (((x) . w_termsig) != 0))
- 
- #endif  /* HPUX */
- #endif  /* i386 || ATT3B || ATT386 */
  #endif  /* !defined (SYSV) || defined (UNIXPC) */
  
--- 6,13 ----
  #include <sys/wait.h>
  #else
  union wait
    {
!     int w_status;
    };
  #endif  /* !defined (SYSV) || defined (UNIXPC) */
  

Index: nojobs.c
***************
*** 150,154 ****
       int pid;
  {
!   int got_pid, return_val, oldmask;
    union wait status;
  #ifndef SYSV
--- 150,154 ----
       int pid;
  {
!   int got_pid, retcode, coredump, termsig, return_val, oldmask;
    union wait status;
  #ifndef SYSV
***************
*** 162,170 ****
  #endif
  
!   while ((got_pid = wait (&status)) != pid)
      {
        if (got_pid < 0 && errno == ECHILD)
  	{
! 	  status.w_termsig = status.w_retcode = 0;
  	  break;
  	}
--- 162,170 ----
  #endif
  
!   while ((got_pid = wait (&status.w_status)) != pid)
      {
        if (got_pid < 0 && errno == ECHILD)
  	{
! 	  status.w_status = 0;
  	  break;
  	}
***************
*** 181,194 ****
  
    /* Default return value. */
!   return_val = status.w_retcode & 0x7f;
  
!   if (status.w_termsig != 0 && status.w_termsig != WSTOPPED)
      {
        extern char *sys_siglist[];
!       fprintf (stderr, "%s", sys_siglist[status.w_termsig]);
!       if (status.w_coredump)
  	fprintf (stderr, " (core dumped)");
        fprintf (stderr, "\n");
!       return_val = status.w_termsig + 128;
        get_tty_state ();
      }
--- 181,208 ----
  
    /* Default return value. */
! #ifdef WSTOPPED
!   retcode  = status.w_retcode;
!   coredump = status.w_coredump
!   termsig  = status.w_termsig;
! #else
!   retcode  = (status.w_status >> 8) & 0xff;
!   coredump = (status.w_status & 0x80) ? 1 : 0;
!   termsig  = status.w_status & 0x7f;
! #endif
  
!   return_val = retcode & 0x7f;
! 
!   if (termsig
! #ifdef WSTOPPED
!       && termsig != WSTOPPED
! #endif
!      )
      {
        extern char *sys_siglist[];
!       fprintf (stderr, "%s", sys_siglist[termsig]);
!       if (coredump)
  	fprintf (stderr, " (core dumped)");
        fprintf (stderr, "\n");
!       return_val = termsig + 128;
        get_tty_state ();
      }