From nobody@FreeBSD.org  Thu Jun 23 16:01:49 2011
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 288311065679
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 23 Jun 2011 16:01:49 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [69.147.83.34])
	by mx1.freebsd.org (Postfix) with ESMTP id 18E468FC08
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 23 Jun 2011 16:01:49 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p5NG1m3i067550
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 23 Jun 2011 16:01:48 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id p5NG1mMX067549;
	Thu, 23 Jun 2011 16:01:48 GMT
	(envelope-from nobody)
Message-Id: <201106231601.p5NG1mMX067549@red.freebsd.org>
Date: Thu, 23 Jun 2011 16:01:48 GMT
From: Chris Ulrich <culrich@csnstores.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: /bin/sh doesn't properly return IO errors to conditionals in a script
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         158206
>Category:       bin
>Synopsis:       sh(1) doesn't properly return IO errors to conditionals in a script
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jilles
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jun 23 16:10:14 UTC 2011
>Closed-Date:    Thu Dec 13 22:28:00 UTC 2012
>Last-Modified:  Thu Dec 13 22:28:00 UTC 2012
>Originator:     Chris Ulrich
>Release:        amd64 freebsd 8.2-RELEASE
>Organization:
CSN Stores
>Environment:
FreeBSD svn.csnzoo.com 8.2-RELEASE FreeBSD 8.2-RELEASE #0: Thu Feb 17 02:41:51 UTC 2011     root@mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
a /bin/sh script writing to a closed file descriptor doesn't pass the IO error it receives from the write to the script itself.


>How-To-Repeat:
write these two scripts:

#!/bin/sh
while echo -n . ; do : ; done

and

#!/bin/sh
while printf . ; do : ; done


now run each script with std-out closed, ie (assuming your interactive shell is bourne shell or similar):

$ sh ./bomb-echo.sh >&-

or 

$ sh ./bomb-printf.sh >&-


both should exit instantly because echo *should* get an error from writing to a closed file descriptor.  Instead both spin madly until they get a kill signal or you truss them (the last bit of stuff you see when you truss them is:

72238: sigprocmask(SIG_SETMASK,0x0,0x0)          = 0 (0x0)
72238: write(1,".",1)                            ERR#9 'Bad file descriptor'
72238: process exit, rval = 0

which itself is another 
>Fix:
sorry.  don't know C.

>Release-Note:
>Audit-Trail:

From: Jilles Tjoelker <jilles@stack.nl>
To: bug-followup@FreeBSD.org, culrich@csnstores.com
Cc:  
Subject: Re: bin/158206: sh(1) doesn't properly return IO errors to
 conditionals in a script
Date: Sun, 26 Jun 2011 12:41:00 +0200

 Thank you for your bug report.
 
 The below patch should fix the problem. It applies to 9-current only. It
 could be changed to apply to 8-stable but I will not commit this change
 to 8-stable anyway. It is even a bit late for 9.x, one week into code
 slush.
 
 commit 22f46c6d493531fc8df124675598edbfb9eb8130
 Author: Jilles Tjoelker <jilles@stack.nl>
 Date:   Sun Jun 26 12:25:07 2011 +0200
 
     sh: Detect and flag write errors on stdout in builtins.
     
     PR:		bin/158206
 
 diff --git a/bin/sh/eval.c b/bin/sh/eval.c
 index d5da7d3..8330094 100644
 --- a/bin/sh/eval.c
 +++ b/bin/sh/eval.c
 @@ -1000,6 +1000,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
  		}
  		handler = &jmploc;
  		redirect(cmd->ncmd.redirect, mode);
 +		outclearerror(out1);
  		/*
  		 * If there is no command word, redirection errors should
  		 * not be fatal but assignment errors should.
 @@ -1015,6 +1016,11 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
  		builtin_flags = flags;
  		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
  		flushall();
 +		if (outiserror(out1)) {
 +			warning("write error on stdout");
 +			if (exitstatus == 0 || exitstatus == 1)
 +				exitstatus = 2;
 +		}
  cmddone:
  		if (argc > 0)
  			bltinunsetlocale();
 diff --git a/bin/sh/output.c b/bin/sh/output.c
 index b4dab51..d26adce 100644
 --- a/bin/sh/output.c
 +++ b/bin/sh/output.c
 @@ -239,6 +239,20 @@ freestdout(void)
  }
  
  
 +int
 +outiserror(struct output *file)
 +{
 +	return (file->flags & OUTPUT_ERR);
 +}
 +
 +
 +void
 +outclearerror(struct output *file)
 +{
 +	file->flags &= ~OUTPUT_ERR;
 +}
 +
 +
  void
  outfmt(struct output *file, const char *fmt, ...)
  {
 diff --git a/bin/sh/output.h b/bin/sh/output.h
 index 5e3b048..51974d8 100644
 --- a/bin/sh/output.h
 +++ b/bin/sh/output.h
 @@ -66,6 +66,8 @@ void emptyoutbuf(struct output *);
  void flushall(void);
  void flushout(struct output *);
  void freestdout(void);
 +int outiserror(struct output *);
 +void outclearerror(struct output *);
  void outfmt(struct output *, const char *, ...) __printflike(2, 3);
  void out1fmt(const char *, ...) __printflike(1, 2);
  void out2fmt_flush(const char *, ...) __printflike(1, 2);
 diff --git a/tools/regression/bin/sh/errors/write-error1.0 b/tools/regression/bin/sh/errors/write-error1.0
 new file mode 100644
 index 0000000..fcb52e7
 --- /dev/null
 +++ b/tools/regression/bin/sh/errors/write-error1.0
 @@ -0,0 +1,3 @@
 +# $FreeBSD$
 +
 +! echo >&- 2>/dev/null
 
 -- 
 Jilles Tjoelker
Responsible-Changed-From-To: freebsd-bugs->jilles 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Sun Jun 26 12:37:45 UTC 2011 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=158206 
State-Changed-From-To: open->closed 
State-Changed-By: jilles 
State-Changed-When: Thu Dec 13 22:26:18 UTC 2012 
State-Changed-Why:  
Fixed in current in r244162. No MFC is planned. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=158206 
>Unformatted:
