Path: utzoo!attcan!uunet!zaphod.mps.ohio-state.edu!usc!elroy.jpl.nasa.gov!jpl-devvax!lwall From: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Newsgroups: comp.lang.perl Subject: Re: Help a perl apprentice Message-ID: <10107@jpl-devvax.JPL.NASA.GOV> Date: 25 Oct 90 17:53:03 GMT References: <18840001@hp-lsd.COS.HP.COM> <10080@jpl-devvax.JPL.NASA.GOV> <107608@convex.convex.com> Reply-To: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 72 In article <107608@convex.convex.com> tchrist@convex.COM (Tom Christiansen) writes: : You can also find out at the time of the open, although this is trickier. : A solution for a command without metacharacters would be like this: : : ($pid = open (BDF_PIPE, "bdf @ARGV |")) && kill(0, $pid) : || die "can't start pipe: $!"; : : or for people preferring C syntax to shell: : : if (!($pid = open (BDF_PIPE, "bdf @ARGV |")) || !kill(0, $pid)) : { die "can't start pipe: $!"; } : : : If, however, there are shell meta-characters, the shell may not yet : have failed by the time the kill happens... It's worse than that. You're assuming vfork semantics. If they don't have vfork, the parent can continue executing even before the child has a chance to exec. : ...so for that case you would : want to introduce a delay with sleep, (although I dislike it) as in: : : ($pid = open (BDF_PIPE, "cmd >foo |")) && (sleep(1), kill(0, $pid)) : || die "can't start pipe: $!"; : : or : : ($pid = open(BDF_PIPE, "$cmd >$foo |")) || die "fork failed: $!"; : sleep 1; : kill(0, $pid) || die "cmd \"$cmd > $foo\" failed: $?"; sleep(1) isn't necessarily good enough either, since it can sleep anywhere from 0 to 1 seconds. In general this is unnecessary, since you simply get an immediate eof on the pipe read, and then you can pick up the exit status with close, as Tom rightly pointed out. : Note that if you're opening for output to a non-existent command, you : will eventually get hit with a SIGPIPE. I often install a plumber : function for this: : : sub plumber { die "$0: plumber: broken pipe"; } : SIG{'PIPE'} = 'plumber'; You can arrange for a faulty exec on an input pipe to give you a SIGPIPE too: $pid = open(IN,"-|"); die "Can't fork: $!\n" unless defined $pid; unless ($pid) { exec "program", "that", "may", "not", "exist"; kill('PIPE', getppid); exit 1; } : I thought that now that we have caller(), I should be able to catch : where this actually happened to me, but that doesn't seem to work. It : complains that "There is no caller" when I try to use caller from the : &plumber routine, which is too bad. Yeah, that'd be nice, but signals happen asynchronously, and you don't necessarily have a consistent context, so it currently pretends you don't have a caller. A sort subroutine doesn't have a context either, currently, though that has no problems with context consistency, and could be done fairly efficiently (we'd only have to establish the context once per sort, not once for each sub call). I could probably make signal handlers have a context, but I'll have to look at the consequences a little more. Larry