#! @PERLV_PATH@ ## ## $Id: par.in,v 1.14 2006/11/28 21:21:28 heas Exp $ ## ## @PACKAGE@ @VERSION@ ## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed ## without fee for non-commerical purposes provided that this license ## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. ## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## ## Except where noted otherwise, rancid was written by and is maintained by ## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # PAR - parallel processing of command # # par -q -n # -l logfile -c command -x -d # -q = quiet mode (don't log anything to the logfiles) # -n # = number of processes to run at once (default = 3) # -l logfile = logfile to store par logging into (.0-.n) # -c command = command to run (can also be in the list # of routers begining with a : # -x = view par logs as they run through xterms # -i = run commands through interactive xterms # -d = print debugging to stderr # -p # = pause # seconds between forks, default 0. # -f = no file or STDIN, just run a quantity of $command. # This precludes passing different args to each process. # -e = exec args split by spaces rather than use sh -c # # par takes a list of items to run a command on. If the list entry begins # with a ":" the remainder of the line is the command to run ("{}" will be # replaced with each subsequent item in the list. If the list entry begins # with a "#", the entry is ignored. If a command is defined (either with # the -c or with a : line) any entry thereafter will be applied to the # command by replacing the {} brackets. In no cammand is defined, then each # line is assumed to be a command to be run. # use Getopt::Std; getopts('p:n:l:c:fixedqV'); if ($opt_V) { print "@PACKAGE@ @VERSION@\n"; exit(0); } $procs=$opt_n; $procs=3 if(!$procs); $command=$opt_c; #$command="{}" if(!$command); $parlog=$opt_l; $parlog="par.log.".time() if(!$parlog); $debug=$opt_d; $no_file=$opt_f ? 1 : 0; $pause_time = $opt_p ? $opt_p : 0; if ($opt_q && ($opt_x || $opt_l)) { print STDERR "-q nullifies -x and -l\n"; exit(1); } $signalled=0; sub handler { $signalled++; print STDERR "Received signal - ending run ($signalled).\n"; if($signalled>1) { printf(STDERR "Ok - killing $id!\n"); kill 9, 0; exit(1); } } $SIG{'INT'} = 'handler'; $SIG{'TERM'} = 'handler'; $SIG{'QUIT'} = 'handler'; sub start { local($cmd,$logfile)=@_; unless ($id=fork) { if (!$opt_q) { local($date)=scalar localtime; open(LOG,">>$logfile"); print(LOG "!!!!!!!\n!$date: $cmd\n!!!!!!!\n"); close(LOG); exec "($cmd) >>$logfile"; } else { if($opt_e) { # Don't use sh -c. exec split(/\s+/, $cmd); } exec "($cmd)"; } exit 0; } print STDERR "Starting $cmd: process id=$id logfile=$logfile\n" if ($debug); $id; } sub finish { if(($id=wait)>0){ $logfile=$log{$id}; print STDERR "$id finished (logfile $logfile)\n" if($logfile && $debug); $logfile; } } sub watchf { local($log)=@_; unless(fork) { exec "xterm -e tail -f $log" ; exit 1; } } # this does not work, $_ doesnt end up with <> #for($i=0; ($no_file && $i<$procs) || (! $no_file && <> ) ;$i++) { for($i=0; ($no_file || ($_=<>)) ;$i++) { chop; if (/^\#/){$i--;next;} if ($opt_c == "" && /^:(.*)$/) { $command=$1;$i--;next; } if ($i<$procs) { $logfile="running.$i"; $logfile="$parlog.$i" if (!$opt_q); } else { $logfile=finish; } last if $signalled; if ($logfile) { $cmd = $command; $cmd =~ s/\{\}/$_/g; $cmd = "xterm -e $cmd" if ($opt_i); $id=start($cmd,$logfile); watchf($logfile) if($opt_x); $log{$id} = $logfile; } print STDERR "$i/$procs: $_: id=$id, log=$log{$id}\n" if ($debug); sleep($pause_time) if ($pause_time); } if($signalled && !eof) { $i--; print STDERR "Signalled - not running these:\n$_\n"; while(<>){print STDERR;} } else { print STDERR "All work assigned. Waiting for remaining processes.\n" if ($debug); } $procs=$i if ($i<$procs); while($procs) { $procs-- if(finish); } print STDERR "Complete\n" if ($debug);