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