home *** CD-ROM | disk | FTP | other *** search
- #! /usr/local/bin/perl
-
- # Wrappers around execute, providing control on whether to die or not,
- # and to handle redirection.
-
- {
- package main;
- require 'mrm-export.pl';
-
- &export ('execute', $EXPORT_FUNCTION,
- 'execute_status',
- 'execute',
- 'execute_or_die',
- 'execute_pipe',
- 'execute_pipe_or_die',
- 'execute_redirect',
- 'execute_redirect_or_die',
- 'execute_output',
- 'execute_output_or_die',
- 'spawn',
- 'spawn_redirect',
- 'spawn_wait',
- 'execute_trace',
- 'execute_run',
- 'change_directory');
-
- &import ('execute', $IMPORT_FUNCTION, 'trace', 'trace_enable', 'fix_file', 'unfix_file');
- &import ('execute', $IMPORT_VARIABLE, 'trace_p');
-
- $EXPORT_FUNCTION || $IMPORT_FUNCTION || $IMPORT_VARIABLE; # silence perl -w
- }
-
- package execute;
-
- {
- $prog = substr ($0, rindex ($0, '/') + 1);
- $exec = !defined ($ENV{'EXECUTE_NOEXEC'});
- $no_stdin = undef;
- $no_stdout = undef;
- $no_stderr = undef;
- $no_func = undef;
- $no_parent_func = undef;
- $no_child_func = undef;
- $do_wait = 1;
- $no_wait = 0;
- @sig_names = ('SIG<none>',
- 'SIGHUP',
- 'SIGINT',
- 'SIGQUIT',
- 'SIGILL',
- 'SIGTRAP',
- 'SIGABRT',
- 'SIGEMT',
- 'SIGFPE',
- 'SIGKILL',
- 'SIGBUS',
- 'SIGSEGV',
- 'SIGSYS',
- 'SIGPIPE',
- 'SIGALRM',
- 'SIGTERM',
- 'SIGURG',
- 'SIGSTOP',
- 'SIGTSTP',
- 'SIGCONT',
- 'SIGCHLD',
- 'SIGTTIN',
- 'SIGTTOU',
- 'SIGIO',
- 'SIGXCPU',
- 'SIGXFSZ',
- 'SIGVTALRM',
- 'SIGPROF',
- 'SIGWINCH',
- 'SIGINFO',
- 'SIGUSR1',
- 'SIGUSR2');
- }
-
-
- # Function to decode the exit status into a normal readable string.
-
- sub execute_status {
- local ($status) = undef;
- local ($raw_status) = (scalar (@_) > 0) ? shift (@_) : $?;
-
- if ($raw_status == 0) {
- $status = 'no errors';
-
- } elsif ($raw_status >= 256) { # non-zero exit
- local ($ret_code) = $raw_status >> 8;
- $status = "exit status = $ret_code";
-
- } elsif ($raw_status > 0) { # killed by signal
- local ($sig) = $raw_status & 127;
- local ($name) = $sig_names[ $sig - $[ ];
- local ($core) = ($raw_status & 128) ? ', core dumped' : '';
- $status = "Killed by signal $sig ($name)$core";
- }
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Internal function to execute a program.
- # Arg 1 is the file to open as stdin, or undef
- # Arg 2 is the file to open as stdout, or undef
- # Arg 3 is the file to open as stderr, or undef
- # Arg 4 is the function to call with each line of input when spawning the program on a pipe
- # Arg 5 is the function to call in the parent context after starting child.
- # Arg 6 is the function to call in the child context before doing the exec.
- # Arg 7 is true if we want to wait for the process to finish.
- # Arg 8 is the program to execute.
- # Arg 9.. are the program arguments.
-
- # If we are waiting for the process to finish, the return value is the exit status
- # If we are not waiting, the return value is the child pid
-
- sub execute_internal {
- local ($in) = shift (@_);
- local ($out) = shift (@_);
- local ($err) = shift (@_);
- local ($pipe_func) = shift (@_);
- local ($parent_func) = shift (@_);
- local ($child_func) = shift (@_);
- local ($wait) = shift (@_);
- local ($child_program) = shift (@_);
- local ($pid) = undef;
- local ($status) = undef;
- local ($") = ' ';
- local (@trace_args) = @_;
-
- $? = 0;
- push (@trace_args, $in) if (defined ($in));
- push (@trace_args, $out) if (defined ($out));
- push (@trace_args, "2$err") if (defined ($err));
- &trace ('exec', $child_program, @trace_args) if ($trace_p);
-
- if (!$exec) {
- $status = 'no exec';
- &trace ('stop', "$child_program:", $status) if ($trace_p);
- return ($status, 0);
- }
-
- (! defined ($pipe_func)) || pipe (PIPE_READ, PIPE_WRITE) || return ("error in pipe: $!", -1);
-
- $pid = fork ();
- (defined ($pid) && $pid != -1) || return ("fork problems: $!", -1);
-
- if ($pid == 0) { # child context
-
- if (defined ($pipe_func)) {
- open (STDOUT, ">&PIPE_WRITE") || die "$prog: dup stdout: $!\n";
- open (STDERR, '>&STDOUT') || die "$prog: dup stderr: $!\n";
- close (PIPE_READ) || die "$prog: close pipe reader: $!\n";
- close (PIPE_WRITE) || die "$prog: close pipe writer: $!\n";
- }
-
- (!defined ($in)) || open (STDIN, $in) || die "$prog: open $in: $!\n";
- (!defined ($out)) || open (STDOUT, $out) || die "$prog: open $out: $!\n";
- (!defined ($err)) || open (STDERR, $err) || die "$prog: open $err: $!\n";
-
- &$child_func ($child_program, @_) if (defined ($child_func));
-
- exec ($child_program, @_);
- die "$prog: $child_program: $!\n";
-
- } else { # parent context
- if (!$wait) {
- &$parent_func ($pid, $child_program, @_) if (defined ($parent_func));
- return $pid;
- }
-
- local ($int, $quit) = ($SIG{'INT'}, $SIG{'QUIT'});
- $int = 'DEFAULT' if (!defined ($int));
- $quit = 'DEFAULT' if (!defined ($quit));
- $SIG{'INT'} = 'IGNORE' if ($int eq 'DEFAULT');
- $SIG{'QUIT'} = 'IGNORE' if ($quit eq 'DEFAULT');
-
- &$parent_func ($pid, $child_program, @_) if (defined ($parent_func));
-
- if (defined ($pipe_func)) {
- close (PIPE_WRITE) || return ("close pipe writer: $!", -1);
- while (<PIPE_READ>) {
- chop;
- &trace ('pipe', $_) if ($trace_p);
- &$pipe_func ($_);
- }
- close (PIPE_READ) || return ("close pipe reader: $!", -1);
- }
-
- waitpid ($pid, 0);
-
- $SIG{'INT'} = $int;
- $SIG{'QUIT'} = $quit;
- }
-
- $status = &execute_status ($?);
- &trace ('stop', "$child_program:", $status) if ($trace_p);
- ($status, $?);
- }
-
-
- # Function to execute a program, die on signals SIGINT, SIGHUP
-
- sub execute {
- local ($") = ' ';
- local ($status, $raw_status) = &execute_internal ($no_stdin,
- $no_stdout,
- $no_stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status == -1
- || ($raw_status & 127) == 2
- || ($raw_status & 127) == 3);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and die if there were errors
-
- sub execute_or_die {
- local ($") = ' ';
- local ($status, $raw_status) = &execute_internal ($no_stdin,
- $no_stdout,
- $no_stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status != 0);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and direct it's stdout/stderr to a pipe, and call a function
- # with each line of the pipe. The first argument is the name of the function
-
- sub execute_pipe {
- local ($func) = shift (@_);
- local ($") = ' ';
- local ($package, $src, $line) = caller;
-
- $func =~ s/^/$package'/ if ($func !~ /'/);
- local ($status, $raw_status) = &execute_internal ($no_stdin,
- $no_stdout,
- $no_stderr,
- $func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status == -1
- || ($raw_status & 127) == 2
- || ($raw_status & 127) == 3);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and direct it's stdout/stderr to a pipe, and call a function
- # with each line of the pipe. The first argument is the name of the function. Die if the
- # program returns a non-zero status.
-
- sub execute_pipe_or_die {
- local ($func) = shift (@_);
- local ($") = ' ';
- local ($package, $src, $line) = caller;
-
- $func =~ s/^/$package'/ if ($func !~ /'/);
- local ($status, $raw_status) = &execute_internal ($no_stdin,
- $no_stdout,
- $no_stderr,
- $func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status != 0);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and redirect its standard files. The first
- # three arguments are the file names for stdin, stdout, or stderr.
-
- sub execute_redirect {
- local ($package,$src,$line) = caller;
- local ($stdin) = &fix_file (shift (@_), '<', $package);
- local ($stdout) = &fix_file (shift (@_), '>', $package);
- local ($stderr) = &fix_file (shift (@_), '>', $package);
- local ($") = ' ';
-
- local ($status, $raw_status) = &execute_internal ($stdin,
- $stdout,
- $stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status == -1
- || ($raw_status & 127) == 2
- || ($raw_status & 127) == 3);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and redirect its standard files. The first
- # three arguments are the file names for stdin, stdout, or stderr. If the program
- # returns non-zero, die.
-
- sub execute_redirect_or_die {
- local ($package,$src,$line) = caller;
- local ($stdin) = &fix_file (shift (@_), '<', $package);
- local ($stdout) = &fix_file (shift (@_), '>', $package);
- local ($stderr) = &fix_file (shift (@_), '>', $package);
- local ($") = ' ';
-
- local ($status, $raw_status) = &execute_internal ($stdin,
- $stdout,
- $stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $do_wait,
- @_);
-
- die "$prog: @_: $status\n" if ($raw_status != 0);
-
- if (wantarray) {
- ($status, $raw_status);
- } else {
- $status;
- }
- }
-
-
- # Function to execute a program, and return the output (the same as `` with tracing).
- # The first argument is non-null if we want to chop off newlines.
-
- sub execute_output {
- local ($do_chop) = shift (@_);
- local ($child_program) = $_[$[];
- local ($status) = undef;
- local ($") = ' ';
- local ($return_string) = undef;
- local (@return_array) = ();
- local (@temp_array) = ();
- local ($i) = undef;
-
- $? = 0;
- &trace ('exec output',
- (($do_chop) ? '[chop]' : '[no chop]'),
- ((wantarray) ? '[wantarray]' : '[scalar]'), @_) if ($trace_p);
-
- if (!$exec) {
- $status = 'no exec';
- &trace ('stop', "$child_program:", $status) if ($trace_p);
- return "";
- }
-
- if (wantarray) {
- @return_array = `@_`;
- foreach $temp_string (@return_array) {
- chop ($temp_string) if (substr ($temp_string, -1) eq "\n");
- &trace ('output', $temp_string) if ($trace_p);
- }
-
- $status = &execute_status ($?);
- &trace ('stop', "$child_program:", $status) if ($trace_p);
-
- if ($do_chop) {
- for ($i = $[; $i <= $#return_array; $i++) {
- chop ($return_array[$i]) if (substr ($return_array[$i], -1) eq "\n");
- }
- }
-
- @return_array;
-
- } else {
- local ($temp_string) = undef;
-
- $return_string = `@_`;
- $temp_string = $return_string;
- chop ($temp_string) if (substr ($temp_string, -1) eq "\n");
-
- &trace ('output', $temp_string) if ($trace_p);
-
- $status = &execute_status ($?);
- &trace ('stop', "$child_program:", $status) if ($trace_p);
-
- chop ($return_string) if ($do_chop
- && substr ($return_string, -1) eq "\n");
-
- $return_string;
- }
- }
-
-
- # Function to execute a program, and return the output (the same as `` with tracing).
- # The first argument is non-null if we want to chop off newlines. If the program
- # dies, abort.
-
- sub execute_output_or_die {
- local ($pid) = undef;
- local ($return_string) = undef;
- local (@return_array) = ();
-
- if (wantarray) {
- @return_array = &execute_output; # pass ARGV straight through
-
- if ($? != 0) {
- shift (@_); # remove do_chop
- local ($status) = &execute_status ($?);
- local ($") = ' ';
- die "$prog: @_: $status\n";
- }
-
- @return_array;
-
- } else {
- $return_string = &execute_output; # pass ARGV straight through
-
- if ($? != 0) {
- shift (@_); # remove do_chop
- local ($status) = &execute_status ($?);
- local ($") = ' ';
- die "$prog: @_: $status\n";
- }
-
- $return_string;
- }
- }
-
-
- # Function to execute a program and not wait for it to finish
-
- sub spawn {
- local ($") = ' ';
- return &execute_internal ($no_stdin,
- $no_stdout,
- $no_stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $no_wait,
- @_);
- }
-
-
- # Function to execute a program, redirect its standard files, and not
- # wait for it to finish. The first three arguments are the file names
- # for stdin, stdout, or stderr.
-
- sub spawn_redirect {
- local ($package,$src,$line) = caller;
- local ($stdin) = &fix_file (shift (@_), '<', $package);
- local ($stdout) = &fix_file (shift (@_), '>', $package);
- local ($stderr) = &fix_file (shift (@_), '>', $package);
- local ($") = ' ';
-
- return &execute_internal ($stdin,
- $stdout,
- $stderr,
- $no_func,
- $no_parent_func,
- $no_child_func,
- $no_wait,
- @_);
- }
-
-
- # Wait for a spawn'ed process to die, and return it's status
-
- sub spawn_wait {
- local ($pid) = (scalar (@_) > 0) ? shift (@_) : -1;
-
- waitpid ($pid, 0);
- return &execute_status ($?);
- }
-
-
- # Function to enable or disable execute tracing
-
- sub execute_trace {
- &trace_enable; # pass args along to trace_enable
- }
-
-
- # Function to enable or disable executing the program
-
- sub execute_run {
- $exec = (scalar (@_) > 0) ? shift (@_) : 1;
- }
-
-
- # Function to change directory, and trace if needed.
-
- sub change_directory {
- local ($dir) = shift (@_);
-
- return if (defined ($cur_dir) && ($dir =~ m!^/!) && $dir eq $cur_dir);
-
- &trace ('cd', $dir) if ($trace_p);
- chdir ($dir) || die "$prog: chdir $dir: $!\n";
- $cur_dir = ($dir =~ m!^/!) ? $dir : undef;
- }
-
-
- # Make sure require doesn't abort.
- 1;
-