NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/54514: script(1) sometimes swallows last line(s) of output



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

From: Harold Gutch <logix%foobar.franken.de@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: bin/54514: script(1) sometimes swallows last line(s) of output
Date: Sun, 1 Sep 2019 21:42:52 +0200

 Hi,
 
 On Sat, Aug 31, 2019 at 02:00:02AM +0000, Robert Elz wrote:
 > The following reply was made to PR bin/54514; it has been noted by GNATS.
 > 
 > From: Robert Elz <kre%munnari.OZ.AU@localhost>
 > To: gnats-bugs%netbsd.org@localhost
 > Cc: 
 > Subject: Re: bin/54514: script(1) sometimes swallows last line(s) of output
 > Date: Sat, 31 Aug 2019 08:58:18 +0700
 > 
 >  I don't believe that is the correct fix.   Your first change
 >  (moving the signal(SIGCHLD, finish) later) opens a possible
 >  (if unlikely) race if the child exits very quickly (before the
 >  signal is established) - which would result in the parent
 >  hanging until it reads EOF from stdin (which for your tests would
 >  be essentially forever - until manually killed).
 
 Good catch, you're right - thanks!
 
 
 >  The correct way to handle this is to leave the initial signal() call
 >  catching SIGCHLD where it is currently, and insert
 >  	(void)signal(SIGCHLD, SIG_DFL);
 >  in the
 >  	if (child == 0) {
 >  case, before the subsequent (second) fork().   (An alternative would be
 >  to save the result of the initial signal call, and use that instead of
 >  SIG_DFL in the one to be added - but that should make no real difference.)
 >  
 >  Your second change is wrong (setting SIGCHLD to SIG_IGN is almost
 >  never the right thing to do), and in any case unnecessary, both
 >  because after your first change (or after the version of it I
 >  suggest above) when dooutput() is called the state of SIGCHLD will
 >  be SIG_DFL (which results in what I suspect you wanted to achieve
 >  by setting it to SIG_IGN) and also because dooutput() is called in the
 >  grandchild process, which never forks, so never has any children
 >  and so will never receive a SIGCHLD in any case.   This change can
 >  simply be deleted.
 
 Thanks for pointing this out.  I wasn't aware of the difference
 between SIG_IGN and SIG_DFL for the SIGCHILD case.
 
 
 >  Please try again with the changes as suggested, and let us know
 >  if my suggested variation for your patch fixes the problem.
 
 Yes, your suggestion fixes the problem for me.
 
 --- src/usr.bin/script/script.c	2011-09-06 18:29:56.000000000 +0000
 +++ src/usr.bin/script/script.c	2019-08-31 12:41:26.368033644 +0000
 @@ -173,6 +173,7 @@
  		fail();
  	}
  	if (child == 0) {
 +		(void)signal(SIGCHLD, SIG_DFL);
  		subchild = child = fork();
  		if (child < 0) {
  			warn("fork");
 
 
 >  kre
 >  
 >  ps: this has most likely never been a problem, as script is almost
 >  always used interactively, and only exits when the user enters ^D
 >  to the terminal, which they typically don't do until all the output
 >  that is expected has been seen.   For the kind of usage in your test.
 >  the input is already known (it is in the test script) so isn't needed,
 >  to capture output simple shell redirection is enough.   I am not sure
 >  why anyone would ever normally run script as it is being run here.
 
 I actually use script(1) that way somewhat regularly if I want to log
 the output of a longer job.  The alternative would be to redirect stdout
 and stderr, open a second terminal and "tail -f" the log file (but
 very occasionally I also want timestamping via "script -t").  I find
 it simpler to run "script ./blah logfile".  And sure, I could do it in
 two steps, call script and then call whatever I want interactively.
 So yes, I really did stumble over this issue a while ago in a real
 situation.  And of course the test case is contrived and just
 illustrates the issue.
 
 
 Thanks for your input!
   Harold
 



Home | Main Index | Thread Index | Old Index