#726735 redirect stdin from stdin to override asynchronous list redirection fails

Package:
dash
Source:
dash
Description:
POSIX-compliant shell
Submitter:
Serge van den Boom
Date:
2013-12-08 23:03:04 UTC
Severity:
normal
#726735#5
Date:
2013-10-18 14:08:52 UTC
From:
To:
(Note: I have tested this with dash built from the up-to-date sources
from the Git repository on git://git.kernel.org/pub/scm/utils/dash/dash.git
on 2013-10-18.)

Dash redirects stdin from /dev/null when a command is started
asynchronously, as specified by POSIX.
However, POSIX also specifies that this can be overridden by explicitely
redirecting.
This fails when redirecting stdin from stdin.

The relevant text from POSIX ( http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03_02 ):
] The standard input for an asynchronous list, before any explicit
] redirections are performed, shall be considered to be assigned to a file
] that has the same properties as /dev/null. If it is an interactive
] shell, this need not happen. In all cases, explicit redirection of
] standard input shall override this activity.

To test: create the following script:
    #!/bin/dash
    sleep 100 <&0 &

Run this, and then look at the open file descriptors of the sleep
process:
    ls -l /proc/`pgrep sleep`/fd
The output is as follows:
    lr-x------ 1 svdb svdb 64 Oct 18 15:58 0 -> /dev/null
    lrwx------ 1 svdb svdb 64 Oct 18 15:58 1 -> /dev/pts/2
    lrwx------ 1 svdb svdb 64 Oct 18 15:58 2 -> /dev/pts/2
fd 0 is assigned to /dev/null instead of /dev/pts/2

#726735#10
Date:
2013-12-08 22:53:19 UTC
From:
To:
Hi Serge, ltns,

In Debian bug #726735, you wrote:
Therefore, the shell cannot, in the general case, know about this
redirection when it forks the child process. For some reason, bash still
overrides the implicit </dev/null if the outer command has a redirection
of stdin, and therefore your example works with bash.

The following version works in various shells:
  { sleep 100 & } </dev/stdin
(A <&0 is treated as a no-op by Almquist derivatives such as FreeBSD and
NetBSD /bin/sh, even for the purpose of suppressing the </dev/null
implicit in background commands; I consider this a bug and have fixed it
in FreeBSD 11-current.)

The code to suppress the implicit </dev/null in ash is very old. It is
in the first version of bin/sh/redir.c in the FreeBSD repository, and
the NetBSD commit that added it is from May 2, 1993 by 'sef', message
'Jim "wilson@moria.cygnus.com" Wilson's patches to make C News (and
other things) work.'. It looks like this code was deliberately removed
from dash years ago. No version in the dash git repository has it.

In particular, the modified example works in both ksh93 and the original
Bourne shell (Heirloom). Together with the fact that this override is
explicitly mentioned in POSIX (that the redirection in
  sleep 100 </dev/tty &
overrides the implicit /dev/null is obvious and would not warrant
explicit notice), I think the removal from dash was wrong.

Note that mksh does not implement this feature either, so relying on it
in scripts seems unwise at this time. Instead, duplicate stdin in the
parent and put it back in the child:
  { foo <&3 3<&- & } 3<&0