can't read from STDIN after system call

D

David Resnick

I've been poking at a script that loses the ability to ready from
<STDIN> after doing a system() call.

I located this
http://perldoc.perl.org/perlfaq8.ht...ter-I-gave-it-EOF-(^D-on-Unix,-^Z-on-MS-DOS)?
which seemed to be the obvious answer to my questions.

But after doing this:
STDIN->clearerr();

or this:

seek STDIN, 0, SEEK_SET

or this
(at program beginning)
my $stdinBegin = tell(STDIN);

Before trying to read STDIN
seek(STDIN, $stdinBegin, 0);

or this
seek(STDIN, 1, 0);
seek(STDIN, 0, 0);


I still find I eternally get undef from <STDIN> after calling this
system command. The system command runs sipp, which does nothing
special as far as I can see. Why would invoking any system command
mess up the parent processes STDIN file handle?

Any suggestions appreciated...
 
D

David Resnick

I've been poking at a script that loses the ability to ready from
<STDIN> after doing a system() call.

I located thishttp://perldoc.perl.org/perlfaq8.html#Why-can%27t-my-script-read-from...D-on-Unix,-^Z-on-MS-DOS%29?
which seemed to be the obvious answer to my questions.

But after doing this:
  STDIN->clearerr();

or this:

seek STDIN, 0, SEEK_SET

or this
(at program beginning)
my $stdinBegin = tell(STDIN);

Before trying to read STDIN
    seek(STDIN, $stdinBegin, 0);

or this
    seek(STDIN, 1, 0);
    seek(STDIN, 0, 0);

I still find I eternally get undef from <STDIN> after calling this
system command.  The system command runs sipp, which does nothing
special as far as I can see.  Why would invoking any system command
mess up the parent processes STDIN file handle?

Any suggestions appreciated...

Very interestingly, I figured out that if I close stdin on the system
command (with 0<&-) it works. Any comments on what I was doing wrong
above or why this works welcom though!
 
D

David Resnick

Please post your code, and also your OS and version of perl. Something
like

    perl -E'system "cat"; say scalar <STDIN>;'

works just fine for me here. (The first ^D sends EOF to cat, and any
subsequent lines are happily read by perl.)





Nothing involving seek will work on STDIN if STDIN is connected to a
terminal.


Is it *any* command? What happens if you replace the command with
something innocuous like 'sleep 1'?

Ben

As I mentioned in the follow up, closing stdin on the system command
fixed it.

It does not apply to any command, I discovered that early on. Once I
saw that the "system" command is what seemed to mess up my STDIN, I
tried the "date" run via system, didn't cause the issue.

The relevant part of the code is here. Note sipp is an open source
tool to handle SIP traffic. When run normally it does look for input
in STDIN.

getline("hit return when ready to execute test $testName\n");

my $sippCommand = "$vobBase/thparty3/sipp/sipp -sf " .
"$sippFile $remoteIpAddress -trace_msg -m 1 -l 1 -key
testname $testName -key testdir $outputDirRoot/$testName" .
" > /dev/null 2> /dev/null 0<&-";

my $sippReturnValue = mysystem("$sippCommand");

sub mysystem
{
my $cmd = $_[0];
my $result = 0;
debug("issuing command '$cmd'\n");

if (($result = system("$cmd")) != 0) {
warn "command '$cmd' failed";
}

return $result;
}

sub debug
{
if ($debug != 0) {
print STDERR "@_";
}

}

sub getline()
{
my $prompt = "@_[0]";
print $prompt;
my $line = <STDIN>;
chomp($line);
return $line;
}

********************

If I don't do the 0<&- in the system call, all future calls to <STDIN>
return eof. But that seems to fix my problem, so I'm now merely just
curious as to why this happens. I'm still mystified as to why, as I
thought that system would create an independent process that couldn't
alter its parents file descriptor state in any way.

My perl version is: perl, v5.8.8 built for i386-linux-thread-multi

Thanks,
-David
 
D

David Resnick

Quoth David Resnick <[email protected]>:









It's generally safer to redirect stdin from /dev/null rather than
closing it. Closing it means the first file sipp opens will appear on
its fd 0, which may have unfortunate consequences.


It does create a separate process, but the two filehandles are still
somewhat connected. I can't see, off the top of my head, what sipp could
be doing to cause your STDIN to return EOF, but if you're interested you
could run the whole thing under strace to find out what it actually does
to fd 0.

Ben

I was still a bit curious, so I examined the sipp source code for how
they mucked with stdin. Here is a minimal perl script and C program
that allows reproduction of the problem.

temp(1726)$ cat foo.pl
#!/usr/bin/perl -w

use strict;

my $line = <STDIN>;

print "got: $line";

if ( ! $line )
{
die("STDIN returns undef before system call");
}

system("foo");

$line = <STDIN>;

if ( ! $line )
{
die("STDIN returns undef before system call");
}

print "got: $line";


***********

temp(1727)$ cat foo.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
printf("about to fcntl\n");
fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
O_NONBLOCK);
return 0;
}


Hmmm. Apparently this fcntl crocks the parent perl scripts STDIN.
OK, I have a work around, guess I'm done with this issue. Thanks for
your help!

-David
 
U

Uri Guttman

DR> I was still a bit curious, so I examined the sipp source code for how
DR> they mucked with stdin. Here is a minimal perl script and C program
DR> that allows reproduction of the problem.

and it is now obvious what the cause of the problem is.

DR> system("foo");

stdin is no in nonblocking mode (what foo does). so since you haven't
typed anything quickly, <> will return immediately and be
undef. sipp/foo are doing async stdio, likely some form of terminal
screen stuff or whatever. clean programs will return stdin to the normal
blocking mode when they exit. you can do that in your perl easily with
IO::Handle's nonblocking method. something like this should do:

use IO::Handle ;

STDIN->nonblocking(0) ;

DR> ***********
DR> printf("about to fcntl\n");
DR> fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
DR> O_NONBLOCK);


DR> Hmmm. Apparently this fcntl crocks the parent perl scripts STDIN.
DR> OK, I have a work around, guess I'm done with this issue. Thanks for
DR> your help!

if your workaround is anything more complex than mine, switch it. all
you need to do is set clear the nonblocking flag after you run sipp.

uri
 
D

David Resnick

  DR> I was still a bit curious, so I examined the sipp source code forhow
  DR> they mucked with stdin.  Here is a minimal perl script and C program
  DR> that allows reproduction of the problem.

and it is now obvious what the cause of the problem is.

  DR> system("foo");

stdin is no in nonblocking mode (what foo does). so since you haven't
typed anything quickly, <>  will return immediately and be
undef. sipp/foo are doing async stdio, likely some form of terminal
screen stuff or whatever. clean programs will return stdin to the normal
blocking mode when they exit. you can do that in your perl easily with
IO::Handle's nonblocking method. something like this should do:

        use IO::Handle ;

        STDIN->nonblocking(0) ;

  DR> ***********
  DR>     printf("about to fcntl\n");
  DR>     fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
  DR> O_NONBLOCK);

  DR> Hmmm.  Apparently this fcntl crocks the parent perl scripts STDIN.
  DR> OK, I have a work around, guess I'm done with this issue.  Thanks for
  DR> your help!

if your workaround is anything more complex than mine, switch it. all
you need to do is set clear the nonblocking flag after you run sipp.
-----
Thanks for the comments.

My work around is simple, in the system() invocation I redirect stdin
to take input from /dev/null (closing stdin in the system call also
works). I think (and you suggest above) that it is a bug in sipp --
it should put stdin back to how it found it prior to exiting. I may
suggest that to the sipp devs.

The part that surprised me and made this a bit painful was that I had
no idea the process launched by the system command could muck with the
parents i/o. I guess I had an understanding that after system fork
and execs the new command the new process was basically independent.
Apparently not completely...

-David
 
U

Uri Guttman

DR> My work around is simple, in the system() invocation I redirect stdin
DR> to take input from /dev/null (closing stdin in the system call also
DR> works). I think (and you suggest above) that it is a bug in sipp --
DR> it should put stdin back to how it found it prior to exiting. I may
DR> suggest that to the sipp devs.

normally the shell will return the terminal to a sane mode (it didn't in
the old days) and the sipp dev team may not have noticed for that reason.

DR> The part that surprised me and made this a bit painful was that I
DR> had no idea the process launched by the system command could muck
DR> with the parents i/o. I guess I had an understanding that after
DR> system fork and execs the new command the new process was
DR> basically independent. Apparently not completely...

forked processes have their own memory and many private things but they
can share stdio and usually do. that is how sipp even gets to use stdio
from the terminal after you fork it. otherwise it wouldn't be able to
get any terminal i/o. this has always been the case for unix
forking. the shell opens (or rather init does) the terminal one time and
the 3 fds (0,1,2) are share with forked children so they can do stdio
and not need to know which terminal to open. the other side of this is
when you want a child not to deal with the terminal it will usually
close stdio. in your case redirectling stdin from /dev/null did it.

uri
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top