File Coverage

blib/lib/IPC/Run3.pm
Criterion Covered Total %
statement 171 175 97.7
branch 101 128 78.9
condition 47 72 65.2
subroutine 21 21 100.0
pod 1 1 100.0
total 341 397 85.8


line stmt bran cond sub pod time code
1             package IPC::Run3;
2 12     12   237946 BEGIN { require 5.006_000; } # i.e. 5.6.0
3 12     12   76 use strict;
  12         14  
  12         628  
4              
5             =head1 NAME
6              
7             IPC::Run3 - run a subprocess with input/ouput redirection
8              
9             =head1 VERSION
10              
11             version 0.048
12              
13             =cut
14              
15             our $VERSION = '0.048';
16              
17             =head1 SYNOPSIS
18              
19             use IPC::Run3; # Exports run3() by default
20              
21             run3 \@cmd, \$in, \$out, \$err;
22              
23             =head1 DESCRIPTION
24              
25             This module allows you to run a subprocess and redirect stdin, stdout,
26             and/or stderr to files and perl data structures. It aims to satisfy 99% of the
27             need for using C, C, and C
28             with a simple, extremely Perlish API.
29              
30             Speed, simplicity, and portability are paramount. (That's speed of Perl code;
31             which is often much slower than the kind of buffered I/O that this module uses
32             to spool input to and output from the child command.)
33              
34             =cut
35              
36 12     12   66 use Exporter;
  12         29  
  12         1358  
37             our @ISA = qw(Exporter);
38             our @EXPORT = qw( run3 );
39             our %EXPORT_TAGS = ( all => \@EXPORT );
40              
41 12   50 12   66 use constant debugging => $ENV{IPCRUN3DEBUG} || $ENV{IPCRUNDEBUG} || 0;
  12         23  
  12         1614  
42 12   100 12   73 use constant profiling => $ENV{IPCRUN3PROFILE} || $ENV{IPCRUNPROFILE} || 0;
  12         20  
  12         812  
43 12     12   58 use constant is_win32 => 0 <= index $^O, "Win32";
  12         14  
  12         1013  
44              
45             BEGIN {
46 12     12   238 if ( is_win32 ) {
47             eval "use Win32 qw( GetOSName ); use Win32::ShellQuote qw(quote_native); 1" or die $@;
48             }
49             }
50              
51             #use constant is_win2k => is_win32 && GetOSName() =~ /Win2000/i;
52             #use constant is_winXP => is_win32 && GetOSName() =~ /WinXP/i;
53              
54 12     12   68 use Carp qw( croak );
  12         24  
  12         878  
55 12     12   15450 use File::Temp qw( tempfile );
  12         353659  
  12         882  
56 12     12   10174 use POSIX qw( dup dup2 );
  12         100823  
  12         105  
57              
58             # We cache the handles of our temp files in order to
59             # keep from having to incur the (largish) overhead of File::Temp
60             my %fh_cache;
61             my $fh_cache_pid = $$;
62              
63             my $profiler;
64              
65 2     1   28 sub _profiler { $profiler } # test suite access
66              
67             BEGIN {
68 12     12   49348 if ( profiling ) {
69 1     1   2055 eval "use Time::HiRes qw( gettimeofday ); 1" or die $@;
  1         1677  
  1         4  
70             if ( $ENV{IPCRUN3PROFILE} =~ /\A\d+\z/ ) {
71             require IPC::Run3::ProfPP;
72             IPC::Run3::ProfPP->import;
73             $profiler = IPC::Run3::ProfPP->new(Level => $ENV{IPCRUN3PROFILE});
74             } else {
75             my ( $dest, undef, $class ) =
76             reverse split /(=)/, $ENV{IPCRUN3PROFILE}, 2;
77             $class = "IPC::Run3::ProfLogger"
78             unless defined $class && length $class;
79             if ( not eval "require $class" ) {
80             my $e = $@;
81             $class = "IPC::Run3::$class";
82             eval "require IPC::Run3::$class" or die $e;
83             }
84             $profiler = $class->new( Destination => $dest );
85             }
86             $profiler->app_call( [ $0, @ARGV ], scalar gettimeofday() );
87             }
88             }
89              
90              
91             END {
92 13     12   10278 $profiler->app_exit( scalar gettimeofday() ) if profiling;
93             }
94              
95             sub _binmode {
96 266     266   1914 my ( $fh, $mode, $what ) = @_;
97             # if $mode is not given, then default to ":raw", except on Windows,
98             # where we default to ":crlf";
99             # otherwise if a proper layer string was given, use that,
100             # else use ":raw"
101 266 100       948 my $layer = !$mode
    100          
102             ? (is_win32 ? ":crlf" : ":raw")
103             : ($mode =~ /^:/ ? $mode : ":raw");
104 266         310 warn "binmode $what, $layer\n" if debugging >= 2;
105              
106 267 100       1023 binmode $fh, ":raw" unless $layer eq ":raw"; # remove all layers first
107 267 50       2650 binmode $fh, $layer or croak "binmode $layer failed: $!";
108             }
109              
110             sub _spool_data_to_child {
111 95     94   375 my ( $type, $source, $binmode_it ) = @_;
112              
113             # If undef (not \undef) passed, they want the child to inherit
114             # the parent's STDIN.
115 94 50       313 return undef unless defined $source;
116              
117 94         317 my $fh;
118 94 100       459 if ( ! $type ) {
    100          
119 3 50       319 open $fh, "<", $source or croak "$!: $source";
120 3         43 _binmode($fh, $binmode_it, "STDIN");
121 2         5 warn "run3(): feeding file '$source' to child STDIN\n"
122             if debugging >= 2;
123             } elsif ( $type eq "FH" ) {
124 1         11 $fh = $source;
125 1         7 warn "run3(): feeding filehandle '$source' to child STDIN\n"
126             if debugging >= 2;
127             } else {
128 91   100     783 $fh = $fh_cache{in} ||= tempfile;
129 91         21754 truncate $fh, 0;
130 91         843 seek $fh, 0, 0;
131 91         754 _binmode($fh, $binmode_it, "STDIN");
132 91         117 my $seekit;
133 91 100       498 if ( $type eq "SCALAR" ) {
    100          
    50          
134              
135             # When the run3()'s caller asks to feed an empty file
136             # to the child's stdin, we want to pass a live file
137             # descriptor to an empty file (like /dev/null) so that
138             # they don't get surprised by invalid fd errors and get
139             # normal EOF behaviors.
140 88 100       374 return $fh unless defined $$source; # \undef passed
141              
142 8         23 warn "run3(): feeding SCALAR to child STDIN",
143             debugging >= 3
144             ? ( ": '", $$source, "' (", length $$source, " chars)" )
145             : (),
146             "\n"
147             if debugging >= 2;
148              
149 8         27 $seekit = length $$source;
150 8 50       84 print $fh $$source or die "$! writing to temp file";
151              
152             } elsif ( $type eq "ARRAY" ) {
153 2         9 warn "run3(): feeding ARRAY to child STDIN",
154             debugging >= 3 ? ( ": '", @$source, "'" ) : (),
155             "\n"
156             if debugging >= 2;
157              
158 2 50       16 print $fh @$source or die "$! writing to temp file";
159 2         16 $seekit = grep length, @$source;
160             } elsif ( $type eq "CODE" ) {
161 1         8 warn "run3(): feeding output of CODE ref '$source' to child STDIN\n"
162             if debugging >= 2;
163 1         10 my $parms = []; # TODO: get these from $options
164 1         12 while (1) {
165 3         10 my $data = $source->( @$parms );
166 3 100       24 last unless defined $data;
167 2 50       14 print $fh $data or die "$! writing to temp file";
168 2         8 $seekit = length $data;
169             }
170             }
171              
172 11 50 33     662 seek $fh, 0, 0 or croak "$! seeking on temp file for child's stdin"
173             if $seekit;
174             }
175              
176 14 50       63 croak "run3() can't redirect $type to child stdin"
177             unless defined $fh;
178              
179 14         49 return $fh;
180             }
181              
182             sub _fh_for_child_output {
183 173     173   904 my ( $what, $type, $dest, $options ) = @_;
184              
185 173         231 my $fh;
186 173 100 100     2003 if ( $type eq "SCALAR" && $dest == \undef ) {
    100          
    100          
187 68         78 warn "run3(): redirecting child $what to oblivion\n"
188             if debugging >= 2;
189              
190 68   66     278 $fh = $fh_cache{nul} ||= do {
191 15         1039 open $fh, ">", File::Spec->devnull;
192 15         70 $fh;
193             };
194             } elsif ( $type eq "FH" ) {
195 1         6 $fh = $dest;
196 1         10 warn "run3(): redirecting $what to filehandle '$dest'\n"
197             if debugging >= 3;
198             } elsif ( !$type ) {
199 2         12 warn "run3(): feeding child $what to file '$dest'\n"
200             if debugging >= 2;
201              
202 2 100       183 open $fh, $options->{"append_$what"} ? ">>" : ">", $dest
    50          
203             or croak "$!: $dest";
204             } else {
205 102         126 warn "run3(): capturing child $what\n"
206             if debugging >= 2;
207              
208 102   66     554 $fh = $fh_cache{$what} ||= tempfile;
209 102         9299 seek $fh, 0, 0;
210 102         5605 truncate $fh, 0;
211             }
212              
213 173         526 my $binmode_it = $options->{"binmode_$what"};
214 173         678 _binmode($fh, $binmode_it, uc $what);
215              
216 173         430 return $fh;
217             }
218              
219             sub _read_child_output_fh {
220 170     170   1551 my ( $what, $type, $dest, $fh, $options ) = @_;
221              
222 170 100 100     2319 return if $type eq "SCALAR" && $dest == \undef;
223              
224 102 50       1060 seek $fh, 0, 0 or croak "$! seeking on temp file for child $what";
225              
226 102 100       487 if ( $type eq "SCALAR" ) {
    100          
    50          
227 99         149 warn "run3(): reading child $what to SCALAR\n"
228             if debugging >= 3;
229              
230             # two read()s are used instead of 1 so that the first will be
231             # logged even it reads 0 bytes; the second won't.
232 99 100       3005 my $count = read $fh, $$dest, 10_000,
233             $options->{"append_$what"} ? length $$dest : 0;
234 99         255 while (1) {
235 179 50       448 croak "$! reading child $what from temp file"
236             unless defined $count;
237              
238 179 100       699 last unless $count;
239              
240 80         112 warn "run3(): read $count bytes from child $what",
241             debugging >= 3 ? ( ": '", substr( $$dest, -$count ), "'" ) : (),
242             "\n"
243             if debugging >= 2;
244              
245 80         690 $count = read $fh, $$dest, 10_000, length $$dest;
246             }
247             } elsif ( $type eq "ARRAY" ) {
248 2 100       59 if ($options->{"append_$what"}) {
249 1         40 push @$dest, <$fh>;
250             } else {
251 1         44 @$dest = <$fh>;
252             }
253 2         14 if ( debugging >= 2 ) {
254             my $count = 0;
255             $count += length for @$dest;
256             warn
257             "run3(): read ",
258             scalar @$dest,
259             " records, $count bytes from child $what",
260             debugging >= 3 ? ( ": '", @$dest, "'" ) : (),
261             "\n";
262             }
263             } elsif ( $type eq "CODE" ) {
264 1         45 warn "run3(): capturing child $what to CODE ref\n"
265             if debugging >= 3;
266              
267 1         21 local $_;
268 1         40 while ( <$fh> ) {
269 2         33 warn
270             "run3(): read ",
271             length,
272             " bytes from child $what",
273             debugging >= 3 ? ( ": '", $_, "'" ) : (),
274             "\n"
275             if debugging >= 2;
276              
277 2         30 $dest->( $_ );
278             }
279             } else {
280 0         0 croak "run3() can't redirect child $what to a $type";
281             }
282              
283             }
284              
285             sub _type {
286 300     300   520 my ( $redir ) = @_;
287              
288 300 50       600 return "FH" if eval {
289 300         2399 local $SIG{'__DIE__'};
290 300         3501 $redir->isa("IO::Handle")
291             };
292              
293 300         947 my $type = ref $redir;
294 300 100       1382 return $type eq "GLOB" ? "FH" : $type;
295             }
296              
297             sub _max_fd {
298 20     20   13581 my $fd = dup(0);
299 20         117 POSIX::close $fd;
300 20         77 return $fd;
301             }
302              
303             my $run_call_time;
304             my $sys_call_time;
305             my $sys_exit_time;
306              
307             sub run3 {
308 101     101 1 2898488 $run_call_time = gettimeofday() if profiling;
309              
310 101 100 100     1808 my $options = @_ && ref $_[-1] eq "HASH" ? pop : {};
311              
312 101         562 my ( $cmd, $stdin, $stdout, $stderr ) = @_;
313              
314 101         157 print STDERR "run3(): running ",
315             join( " ", map "'$_'", ref $cmd ? @$cmd : $cmd ),
316             "\n"
317             if debugging;
318              
319 101 100       515 if ( ref $cmd ) {
320 100 50       648 croak "run3(): empty command" unless @$cmd;
321 100 50       406 croak "run3(): undefined command" unless defined $cmd->[0];
322 100 50       386 croak "run3(): command name ('')" unless length $cmd->[0];
323             } else {
324 1 50       167 croak "run3(): missing command" unless @_;
325 0 0       0 croak "run3(): undefined command" unless defined $cmd;
326 0 0       0 croak "run3(): command ('')" unless length $cmd;
327             }
328              
329 100         278 foreach (qw/binmode_stdin binmode_stdout binmode_stderr/) {
330 300 100       1277 if (my $mode = $options->{$_}) {
331 5 50       61 croak qq[option $_ must be a number or a proper layer string: "$mode"]
332             unless $mode =~ /^(:|\d+$)/;
333             }
334             }
335              
336 100         473 my $in_type = _type $stdin;
337 100         300 my $out_type = _type $stdout;
338 100         253 my $err_type = _type $stderr;
339              
340 100 100       787 if ($fh_cache_pid != $$) {
341             # fork detected, close all cached filehandles and clear the cache
342 6         800 close $_ foreach values %fh_cache;
343 6         671 %fh_cache = ();
344 6         56 $fh_cache_pid = $$;
345             }
346              
347             # This routine proceeds in stages so that a failure in an early
348             # stage prevents later stages from running, and thus from needing
349             # cleanup.
350              
351 100 100       1632 my $in_fh = _spool_data_to_child $in_type, $stdin,
352             $options->{binmode_stdin} if defined $stdin;
353              
354 100 100       771 my $out_fh = _fh_for_child_output "stdout", $out_type, $stdout,
355             $options if defined $stdout;
356              
357 100   100     1337 my $tie_err_to_out =
358             defined $stderr && defined $stdout && $stderr eq $stdout;
359              
360 100 100       588 my $err_fh = $tie_err_to_out
    100          
361             ? $out_fh
362             : _fh_for_child_output "stderr", $err_type, $stderr,
363             $options if defined $stderr;
364              
365             # this should make perl close these on exceptions
366             # local *STDIN_SAVE;
367 100         324 local *STDOUT_SAVE;
368 100         245 local *STDERR_SAVE;
369              
370 100 100       921 my $saved_fd0 = dup( 0 ) if defined $in_fh;
371              
372             # open STDIN_SAVE, "<&STDIN"# or croak "run3(): $! saving STDIN"
373             # if defined $in_fh;
374 100 100 33     2464 open STDOUT_SAVE, ">&STDOUT" or croak "run3(): $! saving STDOUT"
375             if defined $out_fh;
376 100 100 33     1380 open STDERR_SAVE, ">&STDERR" or croak "run3(): $! saving STDERR"
377             if defined $err_fh;
378              
379 100         147 my $errno;
380 100         186 my $ok = eval {
381             # The open() call here seems to not force fd 0 in some cases;
382             # I ran in to trouble when using this in VCP, not sure why.
383             # the dup2() seems to work.
384 100 100 33     917 dup2( fileno $in_fh, 0 )
385             # open STDIN, "<&=" . fileno $in_fh
386             or croak "run3(): $! redirecting STDIN"
387             if defined $in_fh;
388              
389             # close $in_fh or croak "$! closing STDIN temp file"
390             # if ref $stdin;
391              
392 100 100 33     3302 open STDOUT, ">&" . fileno $out_fh
393             or croak "run3(): $! redirecting STDOUT"
394             if defined $out_fh;
395              
396 100 100 33     2262 open STDERR, ">&" . fileno $err_fh
397             or croak "run3(): $! redirecting STDERR"
398             if defined $err_fh;
399              
400 100         124 $sys_call_time = gettimeofday() if profiling;
401              
402 100         975922 my $r = ref $cmd
403 100 50       512 ? system { $cmd->[0] } is_win32 ? quote_native( @$cmd ) : @$cmd
404             : system $cmd;
405              
406 100         5799 $errno = $!; # save $!, because later failures will overwrite it
407 100         365 $sys_exit_time = gettimeofday() if profiling;
408 100         179 if ( debugging ) {
409             my $err_fh = defined $err_fh ? \*STDERR_SAVE : \*STDERR;
410             if ( defined $r && $r != -1 ) {
411             print $err_fh "run3(): \$? is $?\n";
412             } else {
413             print $err_fh "run3(): \$? is $?, \$! is $errno\n";
414             }
415             }
416              
417 100 50 100     3871 if (
      33        
      66        
418             defined $r
419             && ( $r == -1 || ( is_win32 && $r == 0xFF00 ) )
420             && !$options->{return_if_system_error}
421             ) {
422 0         0 croak( $errno );
423             }
424              
425 100         2176 1;
426             };
427 100         682 my $x = $@;
428              
429 100         345 my @errs;
430              
431 100 100       1112 if ( defined $saved_fd0 ) {
432 94         1280 dup2( $saved_fd0, 0 );
433 94         717 POSIX::close( $saved_fd0 );
434             }
435              
436             # open STDIN, "<&STDIN_SAVE"# or push @errs, "run3(): $! restoring STDIN"
437             # if defined $in_fh;
438 100 100 33     5163 open STDOUT, ">&STDOUT_SAVE" or push @errs, "run3(): $! restoring STDOUT"
439             if defined $out_fh;
440 100 100 33     2210 open STDERR, ">&STDERR_SAVE" or push @errs, "run3(): $! restoring STDERR"
441             if defined $err_fh;
442              
443 100 50       376 croak join ", ", @errs if @errs;
444              
445 100 50       292 die $x unless $ok;
446              
447 100 100 100     3587 _read_child_output_fh "stdout", $out_type, $stdout, $out_fh, $options
      100        
448             if defined $out_fh && $out_type && $out_type ne "FH";
449 100 100 66     1411 _read_child_output_fh "stderr", $err_type, $stderr, $err_fh, $options
      66        
      66        
450             if defined $err_fh && $err_type && $err_type ne "FH" && !$tie_err_to_out;
451 100         181 $profiler->run_exit(
452             $cmd,
453             $run_call_time,
454             $sys_call_time,
455             $sys_exit_time,
456             scalar gettimeofday()
457             ) if profiling;
458              
459 100         335 $! = $errno; # restore $! from system()
460              
461 100         5684 return 1;
462             }
463              
464             1;
465              
466             __END__