bin/107171: systat(1) doesn't die when it's xterm is killed while it's running

Nate Eldredge nge at cs.hmc.edu
Thu Mar 8 10:40:10 UTC 2007


The following reply was made to PR bin/107171; it has been noted by GNATS.

From: Nate Eldredge <nge at cs.hmc.edu>
To: bug-followup at FreeBSD.org, josh at tcbug.org
Cc:  
Subject: Re: bin/107171: systat(1) doesn't die when it's xterm is killed
 while it's running
Date: Thu, 8 Mar 2007 02:06:35 -0800 (PST)

 The bug is in /usr/src/usr.bin/systat/keyboard.c, where an error return by 
 getch() is ignored.  When you close an xterm, it sends SIGHUP to all 
 processes running on that terminal, and all further terminal I/O by those 
 processes fails with ENXIO.  But a process running as a different user 
 (e.g. root) can't receive the SIGHUP, and systat ignores the ENXIO and 
 retries endlessly.
 
 I presume the retry is to cope with the case where getch() was interrupted 
 by a signal.  So probably it should only retry if errno = EINTR.  This is 
 essentially what top does.  Also, ferror(stdin) is a bogus test; getch() 
 does not go through stdio and so ferror(stdin) will never be set, and the 
 clearerr() is bogus too.
 
 EINTR is probably moot for FreeBSD anyway since it appears our ncurses 
 handles that transparently, but it doesn't hurt to check.
 
 Here is a patch which fixes the problem.  It still assumes the constant 
 ERR returned by getch() is -1 which is not great style, but I'll touch as 
 little as possible here.
 
 --- /usr/src/usr.bin/systat/keyboard.c.old	Thu Mar  8 02:00:35 2007
 +++ /usr/src/usr.bin/systat/keyboard.c	Thu Mar  8 02:00:40 2007
 @@ -42,6 +42,7 @@
   #include <ctype.h>
   #include <signal.h>
   #include <termios.h>
 +#include <errno.h>
 
   #include "systat.h"
   #include "extern.h"
 @@ -58,9 +59,11 @@
                   do {
                           refresh();
                           ch = getch() & 0177;
 -                        if (ch == 0177 && ferror(stdin)) {
 -                                clearerr(stdin);
 -                                continue;
 +                        if (ch == 0177) {
 +				if (errno == EINTR)
 +                                	continue;
 +				else
 +					die(0);
                           }
                           if (ch >= 'A' && ch <= 'Z')
                                   ch += 'a' - 'A';
 
 -- 
 Nate Eldredge
 nge at cs.hmc.edu


More information about the freebsd-bugs mailing list