Re: [PATCH 5.6.0 IPC/Open3.pm] Allow the use of numeric fd's
[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
92d29cee 52open3() does not wait for and reap the child process after it exits.
227e8dd4 53Except for short programs where it's acceptable to let the operating system
54take care of this, you need to do this yourself. This is normally as
55simple as calling C<waitpid $pid, 0> when you're done with the process.
56Failing to do this can result in an accumulation of defunct or "zombie"
57processes. See L<perlfunc/waitpid> for more information.
58
2675ae2b 59If you try to read from the child's stdout writer and their stderr
60writer, you'll have problems with blocking, which means you'll want
61to use select() or the IO::Select, which means you'd best use
62sysread() instead of readline() for normal stuff.
63
64This is very dangerous, as you may block forever. It assumes it's
65going to talk to something like B<bc>, both writing to it and reading
66from it. This is presumably safe because you "know" that commands
67like B<bc> will read a line at a time and output a line at a time.
68Programs like B<sort> that read their entire input stream first,
7e1af8bc 69however, are quite apt to cause deadlock.
70
71The big problem with this approach is that if you don't have control
7a2e2cd6 72over source code being run in the child process, you can't control
7e1af8bc 73what it does with pipe buffering. Thus you can't just open a pipe to
74C<cat -v> and continually read and write a line from it.
75
2675ae2b 76=head1 WARNING
77
78The order of arguments differs from that of open2().
79
7e1af8bc 80=cut
a0d0e21e 81
82# &open3: Marc Horowitz <marc@mit.edu>
83# derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
4633a7c4 84# fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
f55ee38a 85# ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
2675ae2b 86# fixed for autovivving FHs, tchrist again
cab27d23 87# allow fd numbers to be used, by Frank Tobin
a0d0e21e 88#
89# $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
90#
91# usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
92#
93# spawn the given $cmd and connect rdr for
94# reading, wtr for writing, and err for errors.
95# if err is '', or the same as rdr, then stdout and
96# stderr of the child are on the same fh. returns pid
7e1af8bc 97# of child (or dies on failure).
a0d0e21e 98
99
4633a7c4 100# if wtr begins with '<&', then wtr will be closed in the parent, and
a0d0e21e 101# the child will read from it directly. if rdr or err begins with
102# '>&', then the child will send output directly to that fd. In both
103# cases, there will be a dup() instead of a pipe() made.
104
105
106# WARNING: this is dangerous, as you may block forever
107# unless you are very careful.
108#
109# $wtr is left unbuffered.
110#
111# abort program if
112# rdr or wtr are null
7e1af8bc 113# a system call fails
a0d0e21e 114
2675ae2b 115our $Me = 'open3 (bug)'; # you should never see this, it's always localized
a0d0e21e 116
7e1af8bc 117# Fatal.pm needs to be fixed WRT prototypes.
118
119sub xfork {
120 my $pid = fork;
121 defined $pid or croak "$Me: fork failed: $!";
122 return $pid;
123}
124
125sub xpipe {
126 pipe $_[0], $_[1] or croak "$Me: pipe($_[0], $_[1]) failed: $!";
127}
128
129# I tried using a * prototype character for the filehandle but it still
130# disallows a bearword while compiling under strict subs.
a0d0e21e 131
7e1af8bc 132sub xopen {
133 open $_[0], $_[1] or croak "$Me: open($_[0], $_[1]) failed: $!";
134}
135
136sub xclose {
137 close $_[0] or croak "$Me: close($_[0]) failed: $!";
138}
139
cab27d23 140sub xfileno {
141 my ($fh) = @_;
142 return $1 if $fh =~ /^=?(\d+)$/; # deal with $fh just being an fd
143 return fileno $fh;
144}
145
146sub fh_is_fd {
147 return $_[0] =~ /^=?\d+$/;
148}
149
f55ee38a 150my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';
a24d8dfd 151
7e1af8bc 152sub _open3 {
153 local $Me = shift;
154 my($package, $dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
155 my($dup_wtr, $dup_rdr, $dup_err, $kidpid);
156
2675ae2b 157 # simulate autovivification of filehandles because
158 # it's too ugly to use @_ throughout to make perl do it for us
159 # tchrist 5-Mar-00
160
161 unless (eval {
162 $dad_wtr = $_[1] = gensym unless defined $dad_wtr && length $dad_wtr;
163 $dad_rdr = $_[2] = gensym unless defined $dad_rdr && length $dad_rdr;
164 1; })
165 {
166 # must strip crud for croak to add back, or looks ugly
167 $@ =~ s/(?<=value attempted) at .*//s;
168 croak "$Me: $@";
169 }
170
171 $dad_err ||= $dad_rdr;
a0d0e21e 172
4633a7c4 173 $dup_wtr = ($dad_wtr =~ s/^[<>]&//);
174 $dup_rdr = ($dad_rdr =~ s/^[<>]&//);
175 $dup_err = ($dad_err =~ s/^[<>]&//);
a0d0e21e 176
2675ae2b 177 # force unqualified filehandles into caller's package
cab27d23 178 $dad_wtr = qualify $dad_wtr, $package unless fh_is_fd($dad_wtr);
179 $dad_rdr = qualify $dad_rdr, $package unless fh_is_fd($dad_rdr);
180 $dad_err = qualify $dad_err, $package unless fh_is_fd($dad_err);
7e1af8bc 181
8b3e92c6 182 my $kid_rdr = gensym;
183 my $kid_wtr = gensym;
184 my $kid_err = gensym;
7e1af8bc 185
186 xpipe $kid_rdr, $dad_wtr if !$dup_wtr;
187 xpipe $dad_rdr, $kid_wtr if !$dup_rdr;
188 xpipe $dad_err, $kid_err if !$dup_err && $dad_err ne $dad_rdr;
189
a24d8dfd 190 $kidpid = $do_spawn ? -1 : xfork;
191 if ($kidpid == 0) { # Kid
7e1af8bc 192 # If she wants to dup the kid's stderr onto her stdout I need to
193 # save a copy of her stdout before I put something else there.
194 if ($dad_rdr ne $dad_err && $dup_err
cab27d23 195 && xfileno($dad_err) == fileno(STDOUT)) {
8b3e92c6 196 my $tmp = gensym;
7e1af8bc 197 xopen($tmp, ">&$dad_err");
198 $dad_err = $tmp;
199 }
a0d0e21e 200
a0d0e21e 201 if ($dup_wtr) {
cab27d23 202 xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != xfileno($dad_wtr);
a0d0e21e 203 } else {
8ebc5c01 204 xclose $dad_wtr;
8b3e92c6 205 xopen \*STDIN, "<&=" . fileno $kid_rdr;
a0d0e21e 206 }
207 if ($dup_rdr) {
cab27d23 208 xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != xfileno($dad_rdr);
a0d0e21e 209 } else {
8ebc5c01 210 xclose $dad_rdr;
8b3e92c6 211 xopen \*STDOUT, ">&=" . fileno $kid_wtr;
a0d0e21e 212 }
213 if ($dad_rdr ne $dad_err) {
214 if ($dup_err) {
8b3e92c6 215 # I have to use a fileno here because in this one case
216 # I'm doing a dup but the filehandle might be a reference
217 # (from the special case above).
cab27d23 218 xopen \*STDERR, ">&" . xfileno($dad_err)
219 if fileno(STDERR) != xfileno($dad_err);
a0d0e21e 220 } else {
8ebc5c01 221 xclose $dad_err;
8b3e92c6 222 xopen \*STDERR, ">&=" . fileno $kid_err;
a0d0e21e 223 }
224 } else {
8ebc5c01 225 xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
a0d0e21e 226 }
227 local($")=(" ");
2675ae2b 228 exec @cmd # XXX: wrong process to croak from
ad973f30 229 or croak "$Me: exec of @cmd failed";
a24d8dfd 230 } elsif ($do_spawn) {
231 # All the bookkeeping of coincidence between handles is
232 # handled in spawn_with_handles.
233
234 my @close;
235 if ($dup_wtr) {
8b3e92c6 236 $kid_rdr = \*{$dad_wtr};
237 push @close, $kid_rdr;
a24d8dfd 238 } else {
8b3e92c6 239 push @close, \*{$dad_wtr}, $kid_rdr;
a24d8dfd 240 }
241 if ($dup_rdr) {
8b3e92c6 242 $kid_wtr = \*{$dad_rdr};
243 push @close, $kid_wtr;
a24d8dfd 244 } else {
8b3e92c6 245 push @close, \*{$dad_rdr}, $kid_wtr;
a24d8dfd 246 }
247 if ($dad_rdr ne $dad_err) {
248 if ($dup_err) {
8b3e92c6 249 $kid_err = \*{$dad_err};
250 push @close, $kid_err;
a24d8dfd 251 } else {
8b3e92c6 252 push @close, \*{$dad_err}, $kid_err;
a24d8dfd 253 }
254 } else {
255 $kid_err = $kid_wtr;
256 }
257 require IO::Pipe;
258 $kidpid = eval {
259 spawn_with_handles( [ { mode => 'r',
8b3e92c6 260 open_as => $kid_rdr,
a24d8dfd 261 handle => \*STDIN },
262 { mode => 'w',
8b3e92c6 263 open_as => $kid_wtr,
a24d8dfd 264 handle => \*STDOUT },
265 { mode => 'w',
8b3e92c6 266 open_as => $kid_err,
a24d8dfd 267 handle => \*STDERR },
268 ], \@close, @cmd);
269 };
ad973f30 270 die "$Me: $@" if $@;
a0d0e21e 271 }
272
7e1af8bc 273 xclose $kid_rdr if !$dup_wtr;
274 xclose $kid_wtr if !$dup_rdr;
275 xclose $kid_err if !$dup_err && $dad_rdr ne $dad_err;
276 # If the write handle is a dup give it away entirely, close my copy
277 # of it.
278 xclose $dad_wtr if $dup_wtr;
a0d0e21e 279
280 select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
281 $kidpid;
282}
7e1af8bc 283
284sub open3 {
a24d8dfd 285 if (@_ < 4) {
286 local $" = ', ';
287 croak "open3(@_): not enough arguments";
288 }
7e1af8bc 289 return _open3 'open3', scalar caller, @_
290}
a0d0e21e 291
a24d8dfd 292sub spawn_with_handles {
293 my $fds = shift; # Fields: handle, mode, open_as
294 my $close_in_child = shift;
295 my ($fd, $pid, @saved_fh, $saved, %saved, @errs);
296 require Fcntl;
297
298 foreach $fd (@$fds) {
299 $fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
300 $saved{fileno $fd->{handle}} = $fd->{tmp_copy};
301 }
302 foreach $fd (@$fds) {
303 bless $fd->{handle}, 'IO::Handle'
304 unless eval { $fd->{handle}->isa('IO::Handle') } ;
305 # If some of handles to redirect-to coincide with handles to
306 # redirect, we need to use saved variants:
307 $fd->{handle}->fdopen($saved{fileno $fd->{open_as}} || $fd->{open_as},
308 $fd->{mode});
309 }
f55ee38a 310 unless ($^O eq 'MSWin32') {
311 # Stderr may be redirected below, so we save the err text:
312 foreach $fd (@$close_in_child) {
313 fcntl($fd, Fcntl::F_SETFD(), 1) or push @errs, "fcntl $fd: $!"
314 unless $saved{fileno $fd}; # Do not close what we redirect!
315 }
a24d8dfd 316 }
317
318 unless (@errs) {
319 $pid = eval { system 1, @_ }; # 1 == P_NOWAIT
320 push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!" if !$pid || $pid < 0;
321 }
322
323 foreach $fd (@$fds) {
324 $fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
325 $fd->{tmp_copy}->close or croak "Can't close: $!";
326 }
327 croak join "\n", @errs if @errs;
328 return $pid;
329}
330
3311; # so require is happy