use Carp;
use Symbol qw(gensym qualify);
-$VERSION = 1.0106;
+$VERSION = 1.02;
@ISA = qw(Exporter);
@EXPORT = qw(open3);
=head1 SYNOPSIS
- $pid = open3(\*WTRFH, \*RDRFH, \*ERRFH,
+ $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,
'some cmd and args', 'optarg', ...);
my($wtr, $rdr, $err);
=head1 DESCRIPTION
Extremely similar to open2(), open3() spawns the given $cmd and
-connects RDRFH for reading, WTRFH for writing, and ERRFH for errors. If
-ERRFH is false, or the same file descriptor as RDRFH, then STDOUT and
-STDERR of the child are on the same filehandle. The WTRFH will have
-autoflush turned on.
-
-If WTRFH begins with C<< <& >>, then WTRFH will be closed in the parent, and
-the child will read from it directly. If RDRFH or ERRFH begins with
-C<< >& >>, then the child will send output directly to that filehandle.
-In both cases, there will be a dup(2) instead of a pipe(2) made.
+connects CHLD_OUT for reading from the child, CHLD_IN for writing to
+the child, and CHLD_ERR for errors. If CHLD_ERR is false, or the
+same file descriptor as CHLD_OUT, then STDOUT and STDERR of the child
+are on the same filehandle. The CHLD_IN will have autoflush turned
+on.
+
+If CHLD_IN begins with C<< <& >>, then CHLD_IN will be closed in the
+parent, and the child will read from it directly. If CHLD_OUT or
+CHLD_ERR begins with C<< >& >>, then the child will send output
+directly to that filehandle. In both cases, there will be a dup(2)
+instead of a pipe(2) made.
If either reader or writer is the null string, this will be replaced
by an autogenerated filehandle. If so, you must pass a valid lvalue
open3() returns the process ID of the child process. It doesn't return on
failure: it just raises an exception matching C</^open3:/>. However,
-C<exec> failures in the child are not detected. You'll have to
-trap SIGPIPE yourself.
+C<exec> failures in the child (such as no such file or permission denied),
+are just reported to CHLD_ERR, as it is not possible to trap them.
+
+If the child process dies for any reason, the next write to CHLD_IN is
+likely to generate a SIGPIPE in the parent, which is fatal by default.
+So you may wish to handle this signal.
Note if you specify C<-> as the command, in an analogous fashion to
C<open(FOO, "-|")> the child process will just be the forked Perl
what it does with pipe buffering. Thus you can't just open a pipe to
C<cat -v> and continually read and write a line from it.
+=head1 See Also
+
+=over 4
+
+=item L<IPC::Open2>
+
+Like Open3 but without STDERR catpure.
+
+=item L<IPC::Run>
+
+This is a CPAN module that has better error handling and more facilities
+than Open3.
+
+=back
+
=head1 WARNING
The order of arguments differs from that of open2().
my($package, $dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
my($dup_wtr, $dup_rdr, $dup_err, $kidpid);
+ if (@cmd > 1 and $cmd[0] eq '-') {
+ croak "Arguments don't make sense when the command is '-'"
+ }
+
# simulate autovivification of filehandles because
# it's too ugly to use @_ throughout to make perl do it for us
# tchrist 5-Mar-00
} else {
xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
}
- if ($cmd[0] eq '-') {
- croak "Arguments don't make sense when the command is '-'"
- if @cmd > 1;
- return 0;
- }
+ return 0 if ($cmd[0] eq '-');
local($")=(" ");
- exec @cmd # XXX: wrong process to croak from
- or croak "$Me: exec of @cmd failed";
+ exec @cmd or do {
+ carp "$Me: exec of @cmd failed";
+ eval { require POSIX; POSIX::_exit(255); };
+ exit 255;
+ };
} elsif ($do_spawn) {
# All the bookkeeping of coincidence between handles is
# handled in spawn_with_handles.