File Coverage

blib/lib/Proc/Reliable.pm
Criterion Covered Total %
statement 15 276 5.4
branch 0 156 0.0
condition 0 69 0.0
subroutine 5 18 27.7
pod 3 5 60.0
total 23 524 4.3


line stmt bran cond sub pod time code
1             package Proc::Reliable;
2              
3             =head1 NAME
4              
5             Proc::Reliable -- Run external processes reliably with many options.
6              
7             =head1 SYNOPSIS
8              
9             use Proc::Reliable;
10              
11             Create a new process object
12            
13             $myproc = Proc::Reliable->new();
14              
15             Run a subprocess and collect its output
16              
17             $output = $myproc->run("/bin/ls -l");
18              
19             Check for problems
20              
21             if($myproc->status()) {
22             print("problem!\n");
23             }
24              
25             Run another subprocess, keeping stdout and stderr separated.
26             Also, send the subprocess some data on stdin.
27              
28             $msg = "Hello World\n");
29             $p->want_single_list(0);
30             $stdout = $p->run("/usr/bin/fastmail - foo@bar.com", $msg);
31             if($p->status()) {
32             print("problem: ", $p->stderr(), "\n");
33             }
34              
35             Another way to get output
36              
37             ($stdout, $stderr, $status, $msg) = $p->run("/bin/ls -l");
38              
39             =head1 OPTIONS
40              
41             Run Modes
42              
43             $p->run("shell-command-line"); # Launch a shell process
44             $p->run("cmdline", "data"); # Launch a shell process with stdin data
45             $p->run(["cmd", "arg1", ...]); # Bypass shell processing of arguments
46             $p->run(sub { ... }); # Launch a perl subroutine
47             $p->run(\&subroutine); # Launch a perl subroutine
48              
49             Option settings below represent defaults
50              
51             $p->num_tries(1); # execute the program only once
52             $p->time_per_try(60); # time per try 60 sec
53             $p->maxtime(60); # set overall timeout
54             $p->time_btw_tries(5); # time between tries 5 sec
55             $p->want_single_list(); # return STDOUT and STDERR together
56             $p->accept_no_error(); # Re-try if any STDERR output
57             $p->pattern_stdout($pat); # require STDOUT to match regex $pat
58             $p->pattern_stderr($pat); # require STDERR to match regex $pat
59             $p->allow_shell(1); # allowed to use shell for operation
60             $p->child_exit_time(1.0); # timeout for child to exit after it closes stdout
61             $p->sigterm_exit_time(0.5); # timeout for child to exit after sigterm
62             $p->sigkill_exit_time(0.5); # timeout for child to exit after sigkill
63             $p->input_chunking(0); # feed stdin data line-by-line to subprocess
64             $p->stdin_error_ok(0); # ok if child exits without reading all stdin
65             $p->stdout_cb(undef); # callback function for line-by-line stdout
66             $p->stderr_cb(undef); # callback function for line-by-line stderr
67              
68             Getting output
69              
70             $out = $p->stdout(); # stdout produced by last run()
71             $err = $p->stderr(); # stderr produced by last run()
72             $stat = $p->status(); # exit code produced by last run()
73             $msg = $p->msg(); # module messages produced by last run()
74              
75             Debug
76              
77             Proc::Reliable::debug($level); # Turn debug on
78              
79             =head1 OVERVIEW
80              
81             Proc::Reliable is a class for simple, reliable and
82             configurable subprocess execution in perl. In particular, it is
83             especially useful for managing the execution of 'problem' programs
84             which are likely to fail, hang, or otherwise behave in an unruly manner.
85              
86             Proc::Reliable includes all the
87             functionality of the backticks operator and system() functions, plus
88             many common uses of fork() and exec(), open2() and open3().
89             Proc::Reliable incorporates a number of options, including
90             sending data to the subprocess on STDIN, collecting STDOUT and STDERR
91             separately or together, killing hung processes, timouts and automatic retries.
92              
93             =cut
94              
95             =head1 DESCRIPTION
96              
97             A new process object is created by
98              
99             $myproc = Proc::Reliable->new();
100              
101             The default will run a subprocess only once with a 60-second timeout.
102             Either shell-like command lines or references
103             to perl subroutines can be specified for launching a process in
104             background. A simple list process, for example, can be started
105             via the shell as
106              
107             $out = $myproc->run("ls");
108              
109             To separate stdout, stderr, and exit status:
110              
111             ($out, $err, $status, $msg) = $myproc->run("ls");
112              
113             The output data is also stored within the $myproc object for later
114             retrieval. You can also run a perl subroutine in a subprocess, with
115              
116             $myproc->run(sub { return <*>; });
117              
118             The I Method will try to run the named process. If the
119             process times out (after I seconds) or has an
120             error defined as unacceptable and you would like to re-run it,
121             you can use the I option. Use the I
122             option to set the number of seconds between runs. This can repeat
123             until I seconds have elapsed.
124              
125             When using I, the user can specify what constitutes an
126             unacceptable error of STDOUT or STDERR output -- i.e. demanding a retry.
127             One common shorthand is to have the I method retry if there
128             is any return from STDERR.
129              
130             $myproc->accept_no_error(); # Re-try if any STDERR
131             $myproc->pattern_stdout($pat); # require STDOUT to match regex $pat
132             $myproc->pattern_stderr($pat); # require STDERR to match regex $pat
133              
134             Subprocess completion is detected when the process closes all filehandles.
135             The process must then exit before child_exit_time expires, or it will be
136             killed. If the subprocess does not exit, it is sent a TERM signal unless
137             sigterm_exit_time is 0. then if it does not exit before sigterm_exit_time
138             expires, it is sent a KILL signal unless sigkill_exit_time is 0. then if
139             it does not exit before sigkill_exit_time expires an error is generated.
140             waiting is done in 0.01 second increments.
141              
142             Proc::Reliable is not MT-Safe due to signals usage.
143              
144             =cut
145              
146             require 5.003;
147 1     1   8968 use strict;
  1         3  
  1         38  
148 1     1   5 use Carp;
  1         2  
  1         70  
149 1     1   1125 use FileHandle;
  1         26276  
  1         7  
150 1     1   1663 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %SIG $AUTOLOAD);
  1         2  
  1         111  
151 1     1   1586 use POSIX "sys_wait_h";
  1         27278  
  1         16  
152              
153             require Exporter;
154              
155             @ISA = qw(Exporter AutoLoader);
156             @EXPORT = qw( );
157             $VERSION = '1.16';
158              
159             ######################################################################
160             # Globals: Debug and the mysterious waitpid nohang constant.
161             ######################################################################
162             my $Debug = 0;
163             my $alarm_msg = "Proc::Reliable: child timed out";
164             # my $WNOHANG = _get_system_nohang();
165              
166             # all valid options must exist in this hash
167             my %intdefaults = ("maxtime" => 60,
168             "num_tries" => 1,
169             "time_per_try" => 60,
170             "time_btw_tries" => 5,
171             "allow_shell" => 1,
172             "want_single_list" => undef,
173             "accept_no_error" => 0,
174             "pattern_stdout" => undef,
175             "pattern_stderr" => undef,
176             "child_exit_time" => 1.0,
177             "sigterm_exit_time" => 0.5,
178             "sigkill_exit_time" => 0.5,
179             "input_chunking" => 0,
180             "stdin_error_ok" => 0,
181             "in_after_out_closed" => 1,
182             "stdout_cb" => undef,
183             "stderr_cb" => undef,
184             );
185              
186             ######################################################################
187              
188             =head1 METHODS
189              
190             The following methods are available:
191              
192             =over 4
193              
194             =item new (Constructor)
195              
196             Create a new instance of this class by writing either
197              
198             $proc = new Proc::Reliable; or $proc = Proc::Reliable->new();
199              
200             The I method accepts any valid configuration options:
201              
202             $proc = Proc::Reliable->new('maxtime' => 200, 'num_tries' => 3);
203              
204             =cut
205              
206             ######################################################################
207             # $proc_obj=Proc::Reliable->new(); - Constructor
208             ######################################################################
209             sub new {
210 0     0 1   my($proto, %args) = @_;
211 0   0       my $class = ref($proto) || $proto;
212 0           my $self= { %intdefaults };
213 0           bless($self, $class);
214              
215 0           my($arg);
216 0           foreach $arg (keys(%args)) {
217 0           $self->$arg($args{$arg}); # set options via AUTOLOAD
218             }
219              
220             # Output fields
221 0           $self->{stdout}= undef;
222 0           $self->{stderr}= undef;
223 0           $self->{status}= undef;
224 0           $self->{msg} = undef;
225              
226 0           return $self;
227             }
228              
229             ######################################################################
230              
231             =item run
232              
233             Run a new process and collect the standard output and standard
234             error via separate pipes.
235              
236             $out = $proc->run("program-name");
237             ($out, $err, $status, $msg) = $proc->run("program-name");
238              
239             by default with a single return value, stdout and stderr are combined
240             to a single stream and returned. with 4 return values, stdout and
241             stderr are separated, and the program exit status is also returned.
242             $msg contains messages from Proc::Reliable when errors occur.
243             Set want_single_list(1) to force stdout and stderr to be combined,
244             and want_single_list(0) to force them separated. The results from
245             run() are stored as member data also:
246              
247             $proc->want_single_list(0);
248             $proc->run("program");
249             if($proc->status) {
250             print($proc->stderr);
251             exit;
252             }
253             else {
254             print($proc->stdout);
255             }
256              
257             Program exit status is returned in the same format as exec():
258             bits 0-7 set if program exited from a signal, bits 8-15 are the exit status
259             on a normal program exit.
260              
261             You can also set up callbacks to run a function of your choice as
262             each line of stdout and stderr is produced by the child process
263             using the stdout_cb and stderr_cb options.
264              
265             There are a number of other options.
266             You can also feed the forked program data on stdin via a second argument to run():
267              
268             $myinput = "hello\ntest\n";
269             $output = $proc->run("program-name", $myinput);
270              
271             The first option to run() supports three forms:
272             1) string containing command string to execute. this incurs shell parsing.
273             2) arrayref containing split command string to execute. this bypasses shell parsing.
274             3) coderef to perl function.
275             The first two options are executed via exec(), so the specifics of incurring shell
276             parsing are the same.
277              
278             The second option to run() supports two forms:
279             1) string containing data to feed on stdin
280             2) stringref pointing to data to feed on stdin
281              
282             You can start execution of an
283             independent Perl function (like "eval" except with timeout,
284             retries, etc.). Simply provide the function reference like
285              
286             $output = $proc->run(\&perl_function);
287              
288             or supply an unnamed subroutine:
289              
290             $output = $proc->run( sub { sleep(1) } );
291              
292             The I Method returns after the the function finishes,
293             one way or another.
294              
295             =cut
296              
297             ######################################################################
298             # ($out, $err, $status, $msg) = $proc_obj->run("prg"); - Run process
299             ######################################################################
300              
301             my($_WAIT_INCR_SEC) = 0.01; # global config
302              
303             # signal handler for SIGCHLD, stores child return status in $self->{status}
304             sub _collect_child {
305 0     0     my($self) = @_;
306 0           my($x) = waitpid(-1, 0);
307 0           $self->{status} = $?;
308 0 0         $Debug && print("got '$x' '$?'\n");
309             }
310              
311             # do it!
312             sub run {
313 0     0 1   my($self, $cmd, $input) = @_;
314            
315 0           my($cmdstr);
316 0 0         if(ref($cmd) eq "ARRAY") {
    0          
317             # user can input command as either a string, listref of command pieces, or coderef
318 0           $cmdstr = join(" ", @$cmd);
319             }
320             elsif(ref($cmd) eq "CODE") {
321 0           $cmdstr = ""
322             }
323             else {
324 0           $cmdstr = $cmd;
325             }
326              
327 0           my($inputref, @inputlines);
328 0 0         if(defined($input)) {
329 0 0         if(ref($input)) {
330             # user can input either a scalar or a scalar ref for input data
331 0           $inputref = $input;
332             }
333             else {
334 0           $inputref = \$input;
335             }
336 0 0         if($self->input_chunking()) {
337 0           @inputlines = split(/\n/, $$inputref);
338             }
339             }
340              
341             # if user has set want_single_list then do what they specify,
342             # otherwise autodetect the most useful thing.
343 0           my($do_single_list);
344 0 0         if(defined($self->want_single_list())) {
345 0           $do_single_list = $self->want_single_list();
346             }
347             else {
348 0           $do_single_list = !wantarray();
349             }
350              
351 0           my($pid, $t, $i);
352              
353 0           my $ntry= 0;
354 0           my $starttime= time();
355 0           my $endtime= time() + $self->maxtime();
356 0           my $time_per_try= $self->time_per_try();
357            
358 0           my $patout= $self->pattern_stdout();
359 0           my $paterr= $self->pattern_stderr();
360            
361 0           my $redo = 0;
362            
363             #foreach $t (keys(%$self)) {
364             # print("$t $self->{$t}\n");
365             #}
366            
367 0           $t = 0;
368              
369             # initialize object output variables
370 0           $self->{msg} = undef;
371            
372 0           my($fileno_getstdout,
373             $fileno_getstderr,
374             $fileno_getstdin,
375             $fileno_putstdout,
376             $fileno_putstderr,
377             $fileno_putstdin);
378 0           while(1) {
379 0 0         $Debug && $self->_dprt("ATTEMPT $ntry: '$cmdstr' ");
380              
381             # initialize object output variables
382 0           $self->{stdout} = undef;
383 0           $self->{stderr} = undef;
384 0           $self->{status} = undef;
385            
386             # set up pipes to collect STDOUT and STDERR from child process
387 0 0         pipe(GETSTDOUT,PUTSTDOUT) || die("couldn't create pipe 1");
388 0 0         pipe(GETSTDERR,PUTSTDERR) || die("couldn't create pipe 2");
389 0   0       $fileno_getstdout = fileno(GETSTDOUT) || die("couldn't get fileno 1");
390 0   0       $fileno_getstderr = fileno(GETSTDERR) || die("couldn't get fileno 2");
391 0   0       $fileno_putstdout = fileno(PUTSTDOUT) || die("couldn't get fileno 3");
392 0   0       $fileno_putstderr = fileno(PUTSTDERR) || die("couldn't get fileno 4");
393 0           PUTSTDOUT->autoflush(1);
394 0           PUTSTDERR->autoflush(1);
395 0 0         if(defined($inputref)) {
396 0 0         pipe(GETSTDIN,PUTSTDIN) || die("couldn't create pipe 3");
397 0   0       $fileno_getstdin = fileno(GETSTDIN) || die("couldn't get fileno 5");
398 0   0       $fileno_putstdin = fileno(PUTSTDIN) || die("couldn't get fileno 6");
399 0           PUTSTDIN->autoflush(1);
400             }
401            
402             # fork starts a child process, returns pid for parent, 0 for child
403 0           STDOUT->flush(); # don't dup a non-empty buffer
404 0           $redo = 0;
405              
406             #jvr added
407 0           my($oldsigchld) = $SIG{CHLD};
408 0     0     $SIG{CHLD} = sub { $self->_collect_child(); };
  0            
409              
410             ##### PARENT PROCESS #####
411 0 0         if($pid = fork()) {
    0          
    0          
412             # close the ends of the pipes the child will be using
413 0           close(PUTSTDOUT);
414 0           close(PUTSTDERR);
415 0 0         if(defined($inputref)) {
416 0           close(GETSTDIN);
417             }
418              
419             #print("sigs 1: ",$SIG{ALRM}," , ",$SIG{PIPE}," , ",$SIG{CHLD},"\n");
420             # set up handler to collect child return status no matter when it dies
421              
422 0           eval {
423             # exit the eval if child takes too long or dies abnormally
424 0     0     local $SIG{ALRM} = sub { die("SIGALRM") };
  0            
425 0     0     local $SIG{PIPE} = sub { die("SIGPIPE") };
  0            
426             #print("sigs 2: ",$SIG{ALRM}," , ",$SIG{PIPE}," , ",$SIG{CHLD},"\n");
427 0           $t = min($endtime - time(), $time_per_try);
428 0 0         if($t < 1) {
429 0           return 1;
430             }
431 0           alarm($t);
432              
433             # set up and do a select() to read/write the child to avoid deadlocks
434 0           my($stdinlen);
435 0           my($stdoutdone, $stderrdone, $stdindone) = (0, 0, 0);
436 0           my($nfound, $fdopen, $bytestodo, $blocksize, $s);
437 0           my($rin, $win, $ein) = ('', '', '');
438 0           my($rout, $wout, $eout) = ('', '', '');
439 0           my($gotread) = 0;
440             # bug: occational death with: 'Modification of a read-only value attempted at /home/public/dgold/acsim//Proc/Reliable.pm line 416.'
441 0           vec($rin, $fileno_getstdout, 1) = 1;
442 0           vec($rin, $fileno_getstderr, 1) = 1;
443 0           $blocksize = (stat(GETSTDOUT))[11];
444 0           $fdopen = 2; # stdout and stderr
445 0 0         if(defined($inputref)) {
446             # bug: same bug here
447 0           vec($win, $fileno_putstdin, 1) = 1;
448 0           $stdinlen = length($$inputref);
449 0 0         if($self->in_after_out_closed()) {
450 0           $fdopen++;
451             }
452             }
453 0           my $cbStdout = $self->{stdout_cb};
454 0           my $cbStderr = $self->{stderr_cb};
455 0           my ($outs,$oute);
456 0           while($fdopen) {
457 0           $nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
458              
459 0 0 0       if(defined($win) && vec($wout, $fileno_putstdin, 1)) { # ready to write
460             #print("write ready\n");
461 0           my($indone) = 0;
462 0 0         if($self->input_chunking()) {
463 0 0         if($gotread) {
464 0           $gotread = 0;
465 0           my($inputline) = shift(@inputlines) . "\n";
466 0           $stdinlen = length($inputline);
467             #print("writing $stdinlen '$inputline'\n");
468 0           $s = syswrite(PUTSTDIN, $inputline, $stdinlen, 0);
469 0 0         unless(defined($s)) { # stdin closed by child
470 0 0         if($self->stdin_error_ok()) {
471 0           $indone = 1;
472             }
473             else {
474 0           croak("failure writing to subprocess: $!");
475             }
476             }
477 0 0         if(scalar(@inputlines) == 0) { # finished writing all data
478 0           $indone = 1;
479             }
480             }
481             }
482             else {
483 0           $bytestodo = min($blocksize, $stdinlen - $stdindone);
484 0           $s = syswrite(PUTSTDIN, $$inputref, $bytestodo, $stdindone);
485 0 0         defined($s) || croak("failure writing to subprocess: $!");
486 0           $stdindone += $s; # number of bytes actually written
487 0 0         if($stdindone >= $stdinlen) { # finished writing all data
488 0           $indone = 1;
489             }
490             }
491 0 0         if($indone) {
492 0           $win = undef; # don't select this descriptor anymore
493 0           close(PUTSTDIN);
494 0 0         if($self->in_after_out_closed()) {
495 0           $fdopen--;
496             }
497             }
498             }
499 0 0         if(vec($rout, $fileno_getstdout, 1)) { # ready to read
500 0           $gotread = 1;
501 0           $s = sysread(GETSTDOUT, $self->{stdout}, $blocksize, $stdoutdone);
502 0 0 0       if ($cbStdout && $s) {
503 0           $outs .= substr($self->stdout, $stdoutdone);
504 0           my $lastcr = rindex($outs, "\n");
505 0 0         if ($lastcr >= 0) {
506 0           &$cbStdout("STDOUT", substr($outs, 0, $lastcr + 1));
507 0           $outs = substr($outs, $lastcr + 1);
508             }
509             }
510 0 0         defined($s) || croak("failure reading from subprocess: $!");
511 0           $stdoutdone += $s; # number of bytes actually read
512 0 0         unless($s) {
513 0           vec($rin, $fileno_getstdout, 1) = 0; # don't select this descriptor anymore
514 0           close(GETSTDOUT);
515 0           $fdopen--;
516             }
517             }
518 0 0         if(vec($rout, $fileno_getstderr, 1)) { # ready to read
519 0           $gotread = 1;
520 0           $s = sysread(GETSTDERR, $self->{stderr}, $blocksize, $stderrdone);
521 0 0 0       if ($cbStderr && $s) {
522 0           $oute .= substr($self->stderr, $stderrdone);
523 0           my $lastcr = rindex($oute, "\n");
524 0 0         if ($lastcr >= 0) {
525 0           &$cbStderr("STDERR", substr($oute, 0, $lastcr + 1));
526 0           $oute = substr($oute, $lastcr + 1);
527             }
528             }
529 0 0         defined($s) || croak("failure reading from subprocess: $!");
530 0           $stderrdone += $s; # number of bytes actually read
531 0 0         unless($s) {
532 0           vec($rin, $fileno_getstderr, 1) = 0; # don't select this descriptor anymore
533 0           close(GETSTDERR);
534 0           $fdopen--;
535             }
536             }
537             }
538              
539             # Clean up code to send any left over data to methods
540             # Send any left over data to methods
541 0 0 0       if ($cbStdout && $outs) {
542 0           &$cbStdout("STDOUT", $outs);
543 0           $outs = '';
544             }
545 0 0 0       if ($cbStderr && $oute) {
546 0           &$cbStderr("STDERR", $oute);
547 0           $oute = '';
548             }
549              
550             #print("bytes processed: $stdindone $stdoutdone $stderrdone\n");
551             #if($self->input_chunking() && scalar(@inputlines)) {
552             # print(scalar(@inputlines) . " lines of stdin not fed\n");
553             #}
554 0           alarm(0);
555 0           return 1;
556             }; # end of eval
557              
558             # check return status of eval()
559 0 0         if($@) { # exited from eval() via die()
560 0 0         if($@ =~ /SIG(ALRM|PIPE)/) {
561 0           my($sig) = $1;
562 0 0         if($sig eq "ALRM") {
563 0           $self->{msg} .= "Timed out after $t seconds\n";
564             }
565             else {
566 0           $self->{msg} .= "Pipe error talking to subprocess\n";
567             }
568 0           $redo++;
569             }
570             else { # only a code bug should get here
571 0           croak("unexpected error talking to subprocess: '$@'");
572             }
573             }
574              
575             # wait until child exits, kill it if it doesn't.
576             # normally child will exit shortly unless eval failed via SIGALRM.
577             # if eval() succeeded, wait up to child_exit_time for child to exit
578 0           my($s) = 0;
579 0   0       while(!$redo && !defined($self->{status}) && kill(0, $pid) && ($s < $self->child_exit_time)) {
      0        
      0        
580             #print("waiting for exit\n");
581 0           select(undef, undef, undef, $_WAIT_INCR_SEC);
582 0           $s += $_WAIT_INCR_SEC;
583             }
584            
585             # if child has not exited yet, send sigterm.
586 0 0 0       if(!defined($self->{status}) && kill(0, $pid) && $self->sigterm_exit_time) { # child still alive
      0        
587             #print("sending term\n");
588 0           kill('TERM', $pid);
589             }
590              
591             # wait until process exits or wait-time is exceeded.
592 0           $s = 0;
593 0   0       while(!defined($self->{status}) && kill(0, $pid) && ($s < $self->sigterm_exit_time)) {
      0        
594 0           select(undef, undef, undef, $_WAIT_INCR_SEC);
595 0           $s += $_WAIT_INCR_SEC;
596             }
597              
598 0 0 0       if(!defined($self->{status}) && kill(0, $pid) && $self->sigkill_exit_time) { # child still alive
      0        
599             #print("sending kill\n");
600 0           kill('KILL', $pid);
601             }
602              
603             # wait until process exits or wait-time is exceeded.
604 0           $s = 0;
605 0   0       while(!defined($self->{status}) && kill(0, $pid) && ($s < $self->sigkill_exit_time)) {
      0        
606 0           select(undef, undef, undef, $_WAIT_INCR_SEC);
607 0           $s += $_WAIT_INCR_SEC;
608             }
609              
610 0           $SIG{CHLD} = $oldsigchld; # why is this giving '-w' warning?
611              
612             #print("sigs 3: ",$SIG{ALRM}," , ",$SIG{PIPE}," , ",$SIG{CHLD},"\n");
613            
614 0 0         if(!defined($self->{status})) {
615 0 0         if(kill(0, $pid)) {
616             # get here if unable to kill or if coredump takes longer than sigkill_exit_time
617 0           $self->{msg} .= "unable to kill subprocess $pid";
618             }
619 0           $self->{status} = -1;
620 0           $self->{msg} .= "no return status from subprocess\n";
621             }
622             else {
623 0 0         if(kill(0, $pid)) {
624             # most likely coredumping?
625 0           $self->{msg} .= "got return status but subprocess still alive\n";
626             }
627             }
628             }
629              
630             ##### CHILD PROCESS #####
631             elsif(defined($pid)) { # if child process: $pid == 0
632             #jvr added
633 0           $SIG{CHLD} = 'DEFAULT';
634              
635 0           close(GETSTDOUT); close(GETSTDERR);
  0            
636 0 0         if(defined($inputref)) {
637 0           close(PUTSTDIN);
638             }
639            
640 0 0         open(STDOUT, ">&=PUTSTDOUT") || croak("Couldn't redirect STDOUT: $!");
641 0 0         if($do_single_list) {
642 0 0         open(STDERR, ">&=PUTSTDOUT") || croak("Couldn't redirect STDERR: $!");
643             }
644             else {
645 0 0         open(STDERR, ">&=PUTSTDERR") || croak("Couldn't redirect STDERR: $!");
646             }
647            
648 0 0         if(defined($inputref)) {
649 0 0         open(STDIN, "<&=GETSTDIN") || croak("Couldn't redirect STDIN: $!");
650             }
651              
652 0           my($status) = -1;
653 0 0         if(ref($cmd) eq "CODE") {
    0          
654 0           $status = &$cmd; # Start perl subroutine
655             }
656             elsif(ref($cmd) eq "ARRAY") { # direct exec(), no shell parsing
657 0           exec(@$cmd);
658             #croak("exec() failure: '$!'"); # causes warnings with '-w'
659             }
660             else { # start shell process
661 0           exec($cmd);
662             #croak("exec() failure: '$!'"); # causes warnings with '-w'
663             }
664              
665             # we get here for the perl subroutine normally.
666 0           exit $status;
667             }
668            
669             ##### FORK FAILURES #####
670             elsif($! =~ /No more process/) { # temporary fork error
671 0           $self->{msg} .= "PERL fork error: $!\n";
672 0           $redo++;
673             }
674              
675             else { # weird fork error
676 0           croak("couldn't fork() subprocess: $!");
677             }
678            
679             ##### CONTINUE AFTER CHILD IS DONE #####
680              
681             # figure out if we will loop again or exit
682 0           $ntry++; # retry counter
683 0 0 0       if(defined($patout) or defined($paterr)) {
684 0 0         $redo++ unless ($self->{stdout} =~ /$patout/);
685 0 0         $redo++ unless ($self->{stderr} =~ /$paterr/);
686             }
687 0 0 0       if($self->accept_no_error() && $self->{stderr}) {
688 0           $redo++; # accept_no_error only works if stdout and stderr are separated
689             }
690              
691 0 0         $Debug && $self->_dprt("STDOUT\n$self->{stdout}");
692 0 0         $Debug && $self->_dprt("STDERR\n$self->{stderr}");
693 0 0         $Debug && $self->_dprt("RETURNVALUE $self->{status}");
694 0 0         $Debug && $self->_dprt("MESSAGE\n$self->{msg}");
695              
696 0 0         if($redo) {
697 0 0         if($ntry >= $self->{num_tries}) {
698 0           $self->{msg} .= "Exceeded retry limit\n";
699 0           last;
700             }
701 0 0         if((time() + $self->time_btw_tries) >= $endtime) {
702 0           $self->{msg} .= "Exceeded time limit\n";
703 0           last;
704             }
705 0           sleep($self->time_btw_tries);
706             }
707             else {
708 0           last; # successful termination
709             }
710             } # end of retry loop
711              
712 0 0         if(wantarray()) {
713 0           return ($self->{stdout}, $self->{stderr}, $self->{status}, $self->{msg});
714             }
715             else {
716 0           return $self->{stdout};
717             }
718             }
719              
720             ######################################################################
721              
722             =item debug
723              
724             Switches debug messages on and off -- Proc::Reliable::debug(1) switches
725             them on, Proc::Reliable::debug(0) keeps Proc::Reliable quiet.
726              
727             =cut
728              
729 0     0 1   sub debug { $Debug = shift; } # debug($level) - Turn debug on/off
730              
731             ######################################################################
732              
733             =item maxtime
734              
735             Return or set the maximum time in seconds per I method call.
736             Default is 300 seconds (i.e. 5 minutes).
737              
738             =cut
739              
740             =item num_tries
741              
742             Return or set the maximum number of tries the I method will
743             attempt an operation if there are unallowed errors. Default is 5.
744              
745             =cut
746              
747             =item time_per_try
748              
749             Return or set the maximum time in seconds for each attempt which
750             I makes of an operation. Multiple tries in case of error
751             can go longer than this. Default is 30 seconds.
752              
753             =cut
754              
755             =item time_btw_tries
756              
757             Return or set the time in seconds between attempted operations
758             in case of unacceptable error. Default is 5 seconds.
759              
760             =cut
761              
762             =item child_exit_time
763              
764             When the subprocess closes stdout, it is assumed to have completed
765             normal operation. It is expected to exit within the amount of time
766             specified. If it does not exit, it will be killed (with SIGTERM).
767             This option can be disabled by setting to '0'.
768             Values are in seconds, with a resolution of 0.01.
769              
770             =cut
771              
772             =item sigterm_exit_time
773              
774             If the I or I has been exceeded, or if
775             I action has not succeeded, the subprocess will be
776             killed with SIGTERM. This option specifies the amount of time to allow
777             the process to exit after closing stdout.
778             This option can be disabled by setting to '0'.
779             Values are in seconds, with a resolution of 0.01.
780              
781             =cut
782              
783             =item sigkill_exit_time
784              
785             Similar to I, but a SIGKILL is sent instead of a
786             SIGTERM. When both options are enabled, the SIGTERM is sent first
787             and SIGKILL is then sent after the specified time only if the
788             subprocess is still alive.
789             This option can be disabled by setting to '0'.
790             Values are in seconds, with a resolution of 0.01.
791              
792             =cut
793              
794             =item input_chunking
795              
796             If data is being written to the subprocess on stdin, this option will
797             cause the module to split() the input data at linefeeds, and only feed
798             the subprocess a line at a time. This option typically would be used
799             when the subprocess is an application with a command prompt and does
800             not work properly when all the data is fed on stdin at once.
801             The module will feed the subprocess one line of data on stdin, and
802             will then wait until some data is produced by the subprocess on stdout
803             or stderr. It will then feed the next line of data on stdin.
804              
805             =cut
806              
807             =item stdout_cb
808              
809             Set up a callback function to get stdout data from the child line-by-line.
810             The function you supply will be called whenever the child prints a line
811             onto stdout. This is the only way to get output from the child while it
812             is still running, the normal method will give you all the output at once
813             after the child exits.
814              
815             =cut
816              
817             =item stderr_cb
818              
819             Similar to stdout_cb for stderr data.
820              
821             =cut
822              
823             sub AUTOLOAD {
824 0     0     my $self= shift;
825 0 0         my $type= ref($self) or croak("$self is not an object");
826 0           my $name= $AUTOLOAD;
827 0           $name =~ s/.*://; # strip qualified call, i.e. Geometry::that
828 0 0         unless (exists $self->{$name}) {
829 0           croak("Can't access `$name' field in object of class $type");
830             }
831 0 0         if (@_) {
832 0           my $val = shift;
833 0 0         unless(exists($intdefaults{$name})) {
834 0           croak "Invalid $name initializer $val";
835             }
836             #print("got: $name -> $val\n");
837 0           $self->{$name}= $val;
838             }
839 0           return $self->{$name};
840             }
841              
842             sub DESTROY {
843 0     0     my $self = shift;
844             }
845              
846             # INPUT: two numbers
847             # OUTPUT: the larger one
848             sub max($$) {
849 0     0 0   my($a, $b) = @_;
850 0 0         return ($a > $b) ? $a : $b;
851             }
852              
853             # INPUT: two numbers
854             # OUTPUT: the smaller one
855             sub min($$) {
856 0     0 0   my($a, $b) = @_;
857 0 0         return ($a < $b) ? $a : $b;
858             }
859              
860             ######################################################################
861             # Internal debug print function
862             ######################################################################
863             sub _dprt {
864 0 0   0     return unless $Debug;
865 0 0         if (ref($_[0])) {
866 0           warn ref(shift()), "> @_\n";
867             } else {
868 0           warn "> @_\n";
869             }
870             }
871              
872             ######################################################################
873             # This is for getting the WNOHANG constant of the system: a magic
874             # flag for the "waitpid" command which guards against certain errors
875             # which could hang the system.
876             #
877             # Since the waitpid(-1, &WNOHANG) command isn't supported on all Unix
878             # systems, and we still want Proc::Reliable to run on every system, we
879             # have to quietly perform some tests to figure out if -- or if not.
880             # The function returns the constant, or undef if it's not available.
881             ######################################################################
882             sub _get_system_nohang {
883 0     0     return &WNOHANG;
884             }
885             #sub _get_system_nohang {
886             # my $nohang;
887             # open(SAVEERR, ">&STDERR");
888             # # If the system doesn't even know /dev/null, forget about it.
889             # open(STDERR, ">/dev/null") || return undef;
890             # # Close stderr, since some weirdo POSIX modules write nasty
891             # # error messages
892             # close(STDERR);
893             # # Check for the constant
894             # eval 'use POSIX ":sys_wait_h"; $nohang = &WNOHANG;';
895             # # Re-open STDERR
896             # open(STDERR, ">&SAVEERR");
897             # close(SAVEERR);
898             # # If there was an error, return undef
899             # return undef if $@;
900             # return $nohang;
901             #}
902              
903             1;
904              
905             __END__