integrate cfgperl contents into mainline
[p5sagit/p5-mst-13.2.git] / lib / IPC / Open3.pm
CommitLineData
a0d0e21e 1package IPC::Open3;
7e1af8bc 2
3use strict;
4no strict 'refs'; # because users pass me bareword filehandles
2675ae2b 5our ($VERSION, @ISA, @EXPORT);
7e1af8bc 6
a0d0e21e 7require Exporter;
7e1af8bc 8
a0d0e21e 9use Carp;
8b3e92c6 10use Symbol qw(gensym qualify);
7e1af8bc 11
8b3e92c6 12$VERSION = 1.0103;
7e1af8bc 13@ISA = qw(Exporter);
14@EXPORT = qw(open3);
a0d0e21e 15
f06db76b 16=head1 NAME
17
18IPC::Open3, open3 - open a process for reading, writing, and error handling
19
20=head1 SYNOPSIS
21
84902520 22 $pid = open3(\*WTRFH, \*RDRFH, \*ERRFH,
f06db76b 23 'some cmd and args', 'optarg', ...);
24
2675ae2b 25 my($wtr, $rdr, $err);
26 $pid = open3($wtr, $rdr, $err,
27 'some cmd and args', 'optarg', ...);
28
f06db76b 29=head1 DESCRIPTION
30
31Extremely similar to open2(), open3() spawns the given $cmd and
32connects RDRFH for reading, WTRFH for writing, and ERRFH for errors. If
2675ae2b 33ERRFH is false, or the same file descriptor as RDRFH, then STDOUT and
34STDERR of the child are on the same filehandle. The WTRFH will have
35autoflush turned on.
f06db76b 36
2675ae2b 37If WTRFH begins with C<< <& >>, then WTRFH will be closed in the parent, and
4633a7c4 38the child will read from it directly. If RDRFH or ERRFH begins with
2675ae2b 39C<< >& >>, then the child will send output directly to that filehandle.
a24d8dfd 40In both cases, there will be a dup(2) instead of a pipe(2) made.
f06db76b 41
2675ae2b 42If either reader or writer is the null string, this will be replaced
43by an autogenerated filehandle. If so, you must pass a valid lvalue
44in the parameter slot so it can be overwritten in the caller, or
45an exception will be raised.
cb1a09d0 46
7e1af8bc 47open3() returns the process ID of the child process. It doesn't return on
2675ae2b 48failure: it just raises an exception matching C</^open3:/>. However,
49C<exec> failures in the child are not detected. You'll have to
50trap SIGPIPE yourself.
f06db76b 51
2675ae2b 52If you try to read from the child's stdout writer and their stderr
53writer, you'll have problems with blocking, which means you'll want
54to use select() or the IO::Select, which means you'd best use
55sysread() instead of readline() for normal stuff.
56
57This is very dangerous, as you may block forever. It assumes it's
58going to talk to something like B<bc>, both writing to it and reading
59from it. This is presumably safe because you "know" that commands
60like B<bc> will read a line at a time and output a line at a time.
61Programs like B<sort> that read their entire input stream first,
7e1af8bc 62however, are quite apt to cause deadlock.
63
64The big problem with this approach is that if you don't have control
7a2e2cd6 65over source code being run in the child process, you can't control
7e1af8bc 66what it does with pipe buffering. Thus you can't just open a pipe to
67C<cat -v> and continually read and write a line from it.
68
2675ae2b 69=head1 WARNING
70
71The order of arguments differs from that of open2().
72
7e1af8bc 73=cut
a0d0e21e 74
75# &open3: Marc Horowitz <marc@mit.edu>
76# derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
4633a7c4 77# fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
f55ee38a 78# ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
2675ae2b 79# fixed for autovivving FHs, tchrist again
a0d0e21e 80#
81# $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
82#
83# usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
84#
85# spawn the given $cmd and connect rdr for
86# reading, wtr for writing, and err for errors.
87# if err is '', or the same as rdr, then stdout and
88# stderr of the child are on the same fh. returns pid
7e1af8bc 89# of child (or dies on failure).
a0d0e21e 90
91
4633a7c4 92# if wtr begins with '<&', then wtr will be closed in the parent, and
a0d0e21e 93# the child will read from it directly. if rdr or err begins with
94# '>&', then the child will send output directly to that fd. In both
95# cases, there will be a dup() instead of a pipe() made.
96
97
98# WARNING: this is dangerous, as you may block forever
99# unless you are very careful.
100#
101# $wtr is left unbuffered.
102#
103# abort program if
104# rdr or wtr are null
7e1af8bc 105# a system call fails
a0d0e21e 106
2675ae2b 107our $Me = 'open3 (bug)'; # you should never see this, it's always localized
a0d0e21e 108
7e1af8bc 109# Fatal.pm needs to be fixed WRT prototypes.
110
111sub xfork {
112 my $pid = fork;
113 defined $pid or croak "$Me: fork failed: $!";
114 return $pid;
115}
116
117sub xpipe {
118 pipe $_[0], $_[1] or croak "$Me: pipe($_[0], $_[1]) failed: $!";
119}
120
121# I tried using a * prototype character for the filehandle but it still
122# disallows a bearword while compiling under strict subs.
a0d0e21e 123
7e1af8bc 124sub xopen {
125 open $_[0], $_[1] or croak "$Me: open($_[0], $_[1]) failed: $!";
126}
127
128sub xclose {
129 close $_[0] or croak "$Me: close($_[0]) failed: $!";
130}
131
f55ee38a 132my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';
a24d8dfd 133
7e1af8bc 134sub _open3 {
135 local $Me = shift;
136 my($package, $dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
137 my($dup_wtr, $dup_rdr, $dup_err, $kidpid);
138
2675ae2b 139 # simulate autovivification of filehandles because
140 # it's too ugly to use @_ throughout to make perl do it for us
141 # tchrist 5-Mar-00
142
143 unless (eval {
144 $dad_wtr = $_[1] = gensym unless defined $dad_wtr && length $dad_wtr;
145 $dad_rdr = $_[2] = gensym unless defined $dad_rdr && length $dad_rdr;
146 1; })
147 {
148 # must strip crud for croak to add back, or looks ugly
149 $@ =~ s/(?<=value attempted) at .*//s;
150 croak "$Me: $@";
151 }
152
153 $dad_err ||= $dad_rdr;
a0d0e21e 154
4633a7c4 155 $dup_wtr = ($dad_wtr =~ s/^[<>]&//);
156 $dup_rdr = ($dad_rdr =~ s/^[<>]&//);
157 $dup_err = ($dad_err =~ s/^[<>]&//);
a0d0e21e 158
2675ae2b 159 # force unqualified filehandles into caller's package
7e1af8bc 160 $dad_wtr = qualify $dad_wtr, $package;
161 $dad_rdr = qualify $dad_rdr, $package;
162 $dad_err = qualify $dad_err, $package;
163
8b3e92c6 164 my $kid_rdr = gensym;
165 my $kid_wtr = gensym;
166 my $kid_err = gensym;
7e1af8bc 167
168 xpipe $kid_rdr, $dad_wtr if !$dup_wtr;
169 xpipe $dad_rdr, $kid_wtr if !$dup_rdr;
170 xpipe $dad_err, $kid_err if !$dup_err && $dad_err ne $dad_rdr;
171
a24d8dfd 172 $kidpid = $do_spawn ? -1 : xfork;
173 if ($kidpid == 0) { # Kid
7e1af8bc 174 # If she wants to dup the kid's stderr onto her stdout I need to
175 # save a copy of her stdout before I put something else there.
176 if ($dad_rdr ne $dad_err && $dup_err
177 && fileno($dad_err) == fileno(STDOUT)) {
8b3e92c6 178 my $tmp = gensym;
7e1af8bc 179 xopen($tmp, ">&$dad_err");
180 $dad_err = $tmp;
181 }
a0d0e21e 182
a0d0e21e 183 if ($dup_wtr) {
8ebc5c01 184 xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != fileno($dad_wtr);
a0d0e21e 185 } else {
8ebc5c01 186 xclose $dad_wtr;
8b3e92c6 187 xopen \*STDIN, "<&=" . fileno $kid_rdr;
a0d0e21e 188 }
189 if ($dup_rdr) {
8ebc5c01 190 xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != fileno($dad_rdr);
a0d0e21e 191 } else {
8ebc5c01 192 xclose $dad_rdr;
8b3e92c6 193 xopen \*STDOUT, ">&=" . fileno $kid_wtr;
a0d0e21e 194 }
195 if ($dad_rdr ne $dad_err) {
196 if ($dup_err) {
8b3e92c6 197 # I have to use a fileno here because in this one case
198 # I'm doing a dup but the filehandle might be a reference
199 # (from the special case above).
200 xopen \*STDERR, ">&" . fileno $dad_err
8ebc5c01 201 if fileno(STDERR) != fileno($dad_err);
a0d0e21e 202 } else {
8ebc5c01 203 xclose $dad_err;
8b3e92c6 204 xopen \*STDERR, ">&=" . fileno $kid_err;
a0d0e21e 205 }
206 } else {
8ebc5c01 207 xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
a0d0e21e 208 }
209 local($")=(" ");
2675ae2b 210 exec @cmd # XXX: wrong process to croak from
ad973f30 211 or croak "$Me: exec of @cmd failed";
a24d8dfd 212 } elsif ($do_spawn) {
213 # All the bookkeeping of coincidence between handles is
214 # handled in spawn_with_handles.
215
216 my @close;
217 if ($dup_wtr) {
8b3e92c6 218 $kid_rdr = \*{$dad_wtr};
219 push @close, $kid_rdr;
a24d8dfd 220 } else {
8b3e92c6 221 push @close, \*{$dad_wtr}, $kid_rdr;
a24d8dfd 222 }
223 if ($dup_rdr) {
8b3e92c6 224 $kid_wtr = \*{$dad_rdr};
225 push @close, $kid_wtr;
a24d8dfd 226 } else {
8b3e92c6 227 push @close, \*{$dad_rdr}, $kid_wtr;
a24d8dfd 228 }
229 if ($dad_rdr ne $dad_err) {
230 if ($dup_err) {
8b3e92c6 231 $kid_err = \*{$dad_err};
232 push @close, $kid_err;
a24d8dfd 233 } else {
8b3e92c6 234 push @close, \*{$dad_err}, $kid_err;
a24d8dfd 235 }
236 } else {
237 $kid_err = $kid_wtr;
238 }
239 require IO::Pipe;
240 $kidpid = eval {
241 spawn_with_handles( [ { mode => 'r',
8b3e92c6 242 open_as => $kid_rdr,
a24d8dfd 243 handle => \*STDIN },
244 { mode => 'w',
8b3e92c6 245 open_as => $kid_wtr,
a24d8dfd 246 handle => \*STDOUT },
247 { mode => 'w',
8b3e92c6 248 open_as => $kid_err,
a24d8dfd 249 handle => \*STDERR },
250 ], \@close, @cmd);
251 };
ad973f30 252 die "$Me: $@" if $@;
a0d0e21e 253 }
254
7e1af8bc 255 xclose $kid_rdr if !$dup_wtr;
256 xclose $kid_wtr if !$dup_rdr;
257 xclose $kid_err if !$dup_err && $dad_rdr ne $dad_err;
258 # If the write handle is a dup give it away entirely, close my copy
259 # of it.
260 xclose $dad_wtr if $dup_wtr;
a0d0e21e 261
262 select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
263 $kidpid;
264}
7e1af8bc 265
266sub open3 {
a24d8dfd 267 if (@_ < 4) {
268 local $" = ', ';
269 croak "open3(@_): not enough arguments";
270 }
7e1af8bc 271 return _open3 'open3', scalar caller, @_
272}
a0d0e21e 273
a24d8dfd 274sub spawn_with_handles {
275 my $fds = shift; # Fields: handle, mode, open_as
276 my $close_in_child = shift;
277 my ($fd, $pid, @saved_fh, $saved, %saved, @errs);
278 require Fcntl;
279
280 foreach $fd (@$fds) {
281 $fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
282 $saved{fileno $fd->{handle}} = $fd->{tmp_copy};
283 }
284 foreach $fd (@$fds) {
285 bless $fd->{handle}, 'IO::Handle'
286 unless eval { $fd->{handle}->isa('IO::Handle') } ;
287 # If some of handles to redirect-to coincide with handles to
288 # redirect, we need to use saved variants:
289 $fd->{handle}->fdopen($saved{fileno $fd->{open_as}} || $fd->{open_as},
290 $fd->{mode});
291 }
f55ee38a 292 unless ($^O eq 'MSWin32') {
293 # Stderr may be redirected below, so we save the err text:
294 foreach $fd (@$close_in_child) {
295 fcntl($fd, Fcntl::F_SETFD(), 1) or push @errs, "fcntl $fd: $!"
296 unless $saved{fileno $fd}; # Do not close what we redirect!
297 }
a24d8dfd 298 }
299
300 unless (@errs) {
301 $pid = eval { system 1, @_ }; # 1 == P_NOWAIT
302 push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!" if !$pid || $pid < 0;
303 }
304
305 foreach $fd (@$fds) {
306 $fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
307 $fd->{tmp_copy}->close or croak "Can't close: $!";
308 }
309 croak join "\n", @errs if @errs;
310 return $pid;
311}
312
3131; # so require is happy