Subject: (CODE) Pdist - Front-end to rdist utility

From: [email-masked] (Gordon C. Galligher)
Date: Thu, 02 Jan 92 20:52:44 GMT

For those of you that use rdist, this may be for you.  If an rdist hangs while
updating one host in many, only that host's update will be effected, pdist
will kill that particular one and then go onto the next host in the list.  If
a ping of the host does not return 'host is alive', then the host will be
skipped.  As with all 'features' that I ever incorporate, you can turn them
off if you so choose.  Pdist needs to be a front-end so the only way to tell
it to change the timeout (0 to never timeout) or the ping (-noping if
desired) is through the program's environment ($PDIST to be exact).

This has been tested on Perl 4.0 on Sun4 and Sun3 machines.  It gives a SEGV
and dumps core on Perl's prior to 4.0 due to (presumably) a memory leak in
3.0.  Other than that, there is no reason why it should not work with Perl's
prior to 4.0 as well.  The only restrictions are that your 'rdist' must
support the '-n' option to not do anything, and the '-m' option to restrict
the updating to only be that particular host.  If your rdist has similar
options but with different characters, then it is trivial to change it in
the program.  Enjoy.

		-- Gordon.

P.S. If there are any questions/problems/suggestions, please do not hesitate
	to contact me.  The return-address is in the program/manual page.  If
	you have different experiences with ping or rdist interaction which
	requires code modifications, please be good enough to send them off
	to me so I can, at the very least, include the relevant information
	in the comments and manual page parts of the program.
================================snip=snip=snip===============================
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  pdist
# Wrapped by gorpong@ping on Thu Jan  2 14:38:25 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'pdist' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pdist'\"
else
echo shar: Extracting \"'pdist'\" \(29268 characters\)
sed "s/^X//" >'pdist' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X'di ';
X#'ig 00';
X#eval "exec perl -S $0 $*"
X#	if $running_under_some_shell;
X###############################################################################
X## IF YOU ARE USING GROFF, YOU MUST COMMENT THE 'ig 00' LINE BECAUSE GTROFF   #
X## IS TOO STUPID TO HANDLE IGNORES.  THIS MEANS THAT THE ENTIRE SCRIPT IS PUT #
X## INTO THE MACRO, AND THIS WILL TAKE TIME, BUT THAT IS THE BREAKS.	      #
X###############################################################################
X##
X##  $Id: pdist.perl.mail,v 1.1 2000/03/27 07:34:29 eichin Exp $
X##				PERL 4.019+
X##
X###############################################################################
X##
X##  PDIST - Perl front-end to the RDIST utility, $Revision: 1.1 $
X##  Copyright 1991 Gordon C. Galligher
X##
X##  PDIST is free software; you can redistribute it and/or modify it
X##  under the terms of the GNU General Public License as published by
X##  the Free Software Foundation; either version 2, or (at your option)
X##  any later version.
X##
X##  PDIST is distributed in the hope that it will be useful, but WITHOUT
X##  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
X##  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
X##  License for more details.
X##
X##  You should have received a copy of the GNU General Public License
X##  along with the Perl distribution; if not, write to the Free Software
X##  Foundation, Inc., 675 Mass Ave, Cambridge, MA  02139, USA.
X##
X###############################################################################
X##
X##  If changes are necessary and made, I request that you send those changes
X##  back to me at [email-masked] or [email-masked]
X##  the ping.chi.il.us may go away soon.
X##
X###############################################################################
X##
X##	This file contains a front-end to the rdist(8) utility.  It
X##	basically monitors the execution of the rdist(8) program and
X##	does not allow a particular rdist update to hang.  This is a
X##	front-end that does not get in the way of rdist, so it can
X##	be used wherever you would use rdist.  It is controlled by
X##	internally defined constants or with an environment variable.
X##	This means that it accepts no parameters and passes all
X##	parameters unmolested to the rdist program (with the exception
X##	of the -q parameter, which it honors by not showing you any
X##	output, but it strips off so it can see rdist's output to know
X##	if it is hung or not).
X##
X##	The environment variable is $PDIST (makes sense, eh?) and the
X##	format is:
X##		-t tmout	- # of seconds to wait for each host
X##		-r rdist_cmd	- Full path to the rdist(8) command
X##		-noping		- Do not do ping(8) before rdist(8)
X##	The default timeout is 60 seconds ($TMOUT below), and the default
X##	rdist(8) path is /usr/ucb/rdist ($RDIST below).  Please note that
X##	$TMOUT is NOT the number of seconds for the rdist to complete
X##	updating a particular host, but the number of seconds that pdist will
X##	wait for rdist to output anything.  For this reason, pdist
X##	strips off the -q to rdist so it can constantly monitor rdist's
X##	progress.  The reason that $PDIST requires the -t is for future
X##	growth, in case other customizable options present themselves.
X##
X###############################################################################
X##
X##  $RCSfile: pdist.perl.mail,v $
X##
X##  $Author: eichin $
X##
X##  $Date: 2000/03/27 07:34:29 $
X##
X##  $Revision: 1.1 $
X##
X##  $Log: pdist.perl.mail,v $
X##  Revision 1.1  2000/03/27 07:34:29  eichin
X##  initial perl stuff
X##
X##	Revision 1.3  91/12/15  17:09:54  gorpong
X##	+ Make distinction between rdist output and pdist output.
X##	  The -q command line option silences rdist output but
X##	  does nothing to pdist output.  To get pdist to shutup,
X##	  use -q in the PDIST environment variable.  The -q in
X##	  the environment variable does NOT also imply the -q
X##	  rdist output.  Therefore, for almost EXACT same output
X##	  that rdist gives, use the -q option in the environment
X##	  variable.  (I say ALMOST exact because there are a few
X##	  fatal error conditions that really should never happen
X##	  but I check for anyway, these will halt pdist in its
X##	  tracks with a diagnostic message.  Call me pedantic.)
X##	+ Fix bug that caused it to not print out the rdist lines
X##	  at all.
X##	Really need to get the '$pwd = open(....)' into a fork()/exec()
X##	thing.  This way the exec() can be trapped and such.  As it
X##	stands, the shell is always executed and if it returns a non-zero
X##	status, there is no way of knowing whether it is shell's status
X##	or rdist's status.  Perhaps in the next version.
X##	
X##	Revision 1.2  91/12/15  14:53:06  gorpong
X##	+ Only works with Perl 4.0+, so made changes to reflect that.
X##	  There is a memory leak in Perl 3.0 and this program tickles
X##	  that bug causing nasty problems.
X##	+ Some cosmetic changes in the output and how/where it reports
X##	  errors.
X##	+ Checking in now to prevent disaster.
X##	
X##	Revision 1.1  91/10/18  02:59:20  gorpong
X##	Initial revision
X##	
X##
X###############################################################################
X
X##
X## Global variables to be set here.
X##
X
X($argv0 = $0) =~ s#.*//##;		# Basename of command
X$rc    = 0;				# Return code for this program.
X$|     = 1;				# Unbuffered output
X
X@HOSTS = ();				# List of hosts to rdist to
X$TMOUT = 60;				# Wait 60 secs. for output
X$RDIST = "/usr/ucb/rdist";		# The location of the rdist(8) command
X$DOPING= 1;				# Use ping(8) to see if host is avail
X$SHUTUP= 0;				# Print certain diagnostic things
X$PING  = -f "/etc/ping"			# Or, select your own and put it
X	  ? "/etc/ping"			# here.
X	  : -f "/usr/etc/ping"
X	     ? "/usr/etc/ping"
X	     : -f "/usr/bin/ping"
X	        ? "/usr/bin/ping"
X		: -f "/bin/ping"
X		   ? "/bin/ping"
X		   : "/bin/true";
X
X##
X##  SIGALRM
X##
X##		ACCEPTS:
X##			void
X##
X##		PERFORMS:
X##			This subroutine is called as a signal handler and
X##			simply calls die "alarm trapped.\n".  The object
X##			behind it is that where the alarm(x) call is
X##			used, this should be protected by an eval(), so
X##			the die() from this subroutine will be packaged
X##			up into $@ and the line after the eval() can be
X##			checked to see if it succeeded or timed out.
X##
X##		RETURNS:
X##			die()s
X##
X##  Gordon C. Galligher (10/2/91)
X##
X
sub sigalrm
X{
X	die "Alarm trapped.\n";
X} # SIGALRM
X
X$OK		= 0;			# Docmd() has exited correctly
X$TIMED_OUT	= 1;			# The command timed out
X$TOO_MANY_LINES = 2;			# Too many lines were output
X$CANNOT_EXEC	= 3;			# Cannot execute the command
X$OTHER		= 4;			# Some other error not handled
X
X##
X##  DOCMD
X##
X##		ACCEPTS:
X##			$max	 --	Scalar maximum # of output lines
X##			$tmout	 --	Scalar max. seconds to wait for output
X##			$pline	 --	Scalar to print line at a time
X##			@cmd	 --	Array containing command to exec.
X##
X##		PERFORMS:
X##			This subroutine executes the specified command,
X##			capturing the output.  It only collects $max
X##			lines (if $max > 0) and after that many lines it
X##			will kill the process.  This is done to make sure
X##			we control runaway processes, and to be used for
X##			those processes that you really do not need all of
X##			the output.  If $max <= 0, then no maximum is
X##			ever reached, and the output is read until exhausted.
X##			When reading the output, a timeout is used for each
X##			line (if $tmout > 0).  If an input line
X##			(input == output from command) is not seen before
X##			the timeout, then the process is killed and a return
X##			code is sent back, along with the present output.
X##			If $tmout <= 0, then no timeout is imposed and
X##			the process will hang until either the input is
X##			drained or the process killed (if $max > 0).
X##			Regardless of these, (if $pline != 0) then each
X##			line received from the output of the process is
X##			printed on the current output as it is received.
X##
X##		RETURNS:
X##			@output	 --	Array containing output lines
X##
X##  Gordon C. Galligher (10/2/91)
X##
X
sub docmd
X{
X	local($max, $tmout, $pline, @cmd) = @_;
X	local(@output)    = ();			# Output from process
X	local($rc)        = 0;			# Return code from stuff
X	local($line)      = "";			# Line from pipeline
X	local($")	  = " ";		# Put it to a space
X	local($pid)       = 0;			# Child process
X	local($alrm)      = $SIG{"ALRM"};	# Save their signal handler
X	local($theirexit) = 0;			# Exit of child process
X	local($!, $src)   = (0, 0);		# Save stuff
X
X	$tmout = 0 unless $tmout > 0;
X	$pid   = open(PIPE, "@cmd 2>&1 |");	# Execute the command
X	if ( defined($pid) && $pid > 0 )	# If the command is executing
X	{
X		$rc = $OK;			# Be optimistic
X		for (;;)			# Loop for ever (last in loop)
X		{
X			$SIG{"ALRM"} = "sigalrm";	# Set our signal hndlr
X			alarm($tmout);			# Set the alarm
X			eval "\$line = <PIPE>";		# Read a line from PIPE
X			alarm(0);			# Cancel the alarm
X			$SIG{"ALRM"} = $alrm;		# Reset their handlr
X			$rc = $TIMED_OUT, last if length($@) > 0; # Eval died
X			last unless length($line);	# No chars, then EOF.
X			push(@output, $line);		# Put on output array
X			print $line if $pline;		# Print line, if nec.
X			$rc = $TOO_MANY_LINES, last
X				if ( (scalar(@output) >= $max) && ($max > 0) );
X		} # FOR (;;)
X		$rc && do { kill "TERM", $pid; sleep(5); kill "KILL", $pid; };
X		close(PIPE);
X		$theirexit = $? >> 8;			# The real exit val.
X	} # IF defined($pid) ...
X	else
X	{
X		$src = $!;
X		$rc  = $CANNOT_EXEC;
X		$theirexit = -1;
X	} # ELSE..IF defined($pid) ...
X
X	if ( scalar(@output) == 0 )
X	{
X		@output = ($rc, $theirexit);
X		push(@output, $src) if $src;	# If $src != 0, then put it on
X	} # IF scalar ...
X	else
X	{
X		unshift(@output, $theirexit);	# Put their exit on the beg.
X		unshift(@output, $rc);		# Put ours here.
X	} # ELSE..IF scalar ... 
X	@output;				# Return the output to caller
X} # DOCMD
X
X##
X##  RTOHOST
X##
X##		ACCEPTS:
X##			$host	 --	Scalar host to rdist to
X##			@args	 --	Array arguments to rdist command
X##
X##		PERFORMS:
X##			This function tries to execute the rdist(8) command
X##			on the specified host with the specified arguments.
X##			It first does a ping to see if the host is available.
X##			This is not always a best way to see if the host
X##			will work because rdist(8) uses the rshd(8) on
X##			the remote system, and the system has to become
X##			involved.  ICMP ECHO's, on the other hand, are
X##			handled by the ethernet board and the device driver.
X##			No context switching is necessary.  It calls
X##			&docmd() to do the actual command execution, and
X##			&docmd() shields us from hanging while updating.
X##			The entire output is printed, in case the user
X##			really wants the diagnostics.
X##
X##		RETURNS:
X##			0	 --	Command executed and completed
X##			1	 --	Rdist (or ping) failed for some reason
X##
X##  Gordon C. Galligher (10/3/91)
X##
X
sub rtohost
X{
X	local($host, @args) = @_;
X	local(@rargs)	    = grep(!/^-q/, @args);	# Get all but -q args
X	local(@cmdret);					# Return from &docmd()
X	local($qoption)     = scalar(@rargs) - scalar(@args);
X	local($rc, $rrc);				# Return codes
X	local($!);					# Local errno stuff
X	local($") = "";					# No tromp on others
X
X    #
X    # First try the ping.  We cannot trust the ping output because,
X    # unfortunately, not all pings are the same.  Sun's ping returns
X    # an exit value based on the availability of the remote host, none
X    # others that I have seen do.  Sun's also does a generic test, with
X    # constant pings available with an '-s' option.  Others loop
X    # continuously by default.  By calling the ping on these systems, we
X    # would never exit, so we need to have &docmd() kill the process after
X    # a maximum of 10 lines, or 5 seconds pause, whichever comes first.
X    #
X
X	if ( $DOPING )
X	{
X		@cmdret = &docmd(10, 0, 0, $PING, $host);
X		$rc     = shift(@cmdret);		# See &docmd()s return.
X		if ( $rc != $TOO_MANY_LINES )		# Not killed for that
X		{
X			if ( (scalar(grep(/no answer/, @cmdret)) > 0) ||
X			     ($rc == $TIMED_OUT) )	# No answer or constant
X			{				# ping timed out.
X				warn "No answer from $host, skipping update.\n"
X					unless $SHUTUP;
X				return 1;
X			} # IF grep ...
X			elsif ( scalar(grep(/unknown host/, @cmdret)) > 0 )
X			{
X				warn "Unknown host $host, no update tried.\n"
X					unless $SHUTUP;
X				return 1;
X			} # IF grep ...
X		} # IF $rc != $TOO_MANY_LINES	# If too many, then constant
X	} # IF $DOPING				# ping, always returned.
X
X    #
X    # Unforutnately, if we made it to here we are still not guaranteed to
X    # have a host that is valid and up.  This is not a problem since the
X    # rdist(8) command is protected from hanging by the timeout parameter.
X    #
X    # When building the @cmd array, I prepend the "-m $host" arguments to
X    # the rdist(8) command.  I have not yet decided if this is the place
X    # for it, or if the caller should do it, but it is here for now.
X    #
X
X	@cmdret = &docmd(0, $TMOUT, ! $qoption, $RDIST, "-m", $host, @rargs);
X	if ( ($rc = shift(@cmdret)) == $TIMED_OUT )
X	{
X		warn "Update of $host failed, time expired.\n"
X			unless $SHUTUP;
X		$rrc = 1;
X	} # IF ($rc = ...
X	elsif ( $rc == $CANNOT_EXEC )
X	{
X		$rc = shift(@cmdret);
X		$!  = shift(@cmdret);
X		warn "Update of $host failed, cannot execute, $!\n"
X			unless $SHUTUP;
X		$rrc = 1;
X	} # IF $rc == ...
X	elsif ( ($rc == $TOO_MANY_LINES) || ($rc == $OTHER) )
X	{
X		$rc = shift(@cmdret);
X		die("GAACK!!  I am so confused!  I should not be here!\n",
X			"Update of $host failed!\nOUTPUT:  @cmdret\n");
X	} # IF $rc == ...
X	elsif ( $rc == $OK )
X	{
X		if ( ($rc = shift(@cmdret)) != 0 )
X		{
X			warn "Rdist exited with non-zero value:  $rc\n"
X				unless $SHUTUP;
X			$rrc = 1;
X		} # IF ($rc = ...
X		$rrc = 0;
X	} # IF $rc == $OK
X	else
X	{
X		die("Uhm, the computer room is on fire, I should not be here ",
X		    "with code == $rc.\n");
X	} # ELSE..IF $rc ...
X	$rrc;				# Return status to the caller.
X} # RTOHOST
X
X##
X##  GETHOSTS
X##
X##		ACCEPTS:
X##			@rdistargs	 --	Array of arguments to rdist
X##
X##		PERFORMS:
X##			This subroutine makes a call to the $RDIST command
X##			with the arguments specified, but prepending them
X##			with the "-n" option.  The "-n" tells rdist(8) to
X##			only display what it would do, not actually do
X##			anything.  From rdist(8)'s output we can glean the
X##			hosts it would update by looking for the tell-tale
X##			"updating host ..." output.  This function copies
X##			the @rdistargs into @args, but DOES NOT copy the
X##			"-q" argument.  The "-q" argument tells rdist(8)
X##			not to display anything, and we obviously do not
X##			want this!  When calling &docmd(), do not use any
X##			timeout or maximum lines parameters, because rdist
X##			should really NOT do anything, so it should not
X##			take too long.  If this proves to be false for
X##			your system, then change it!  (If you do, then send
X##			me your changes, please.)  Please note that an
X##			eval is used at the last part of this subroutine.
X##			This is done so we only include in the list of
X##			hosts to return those hosts that are not already
X##			IN the list (do not want to do the same host
X##			multiple times).  In order to do that, I need to
X##			use 'grep()' to see if it is already in the @hosts
X##			array.  This is a VERY expensive operation, when the
X##			cmd is:
X##			    push(@hosts, $line) unless grep(/$line/, @hosts);
X##			Each time through, the RE has to be compiled, and
X##			this is nasty.  By putting the above line into a
X##			scalar variable (being sure to back-whack the @hosts
X##			and the first $line), then the eval causes the grep
X##			to be comparing a /string/ instead of a /$variable/.
X##			Learn to speak Perl and you will not be so confused.
X##					:-) :-) :-)
X##
X##		RETURNS:
X##			@hosts	 --	Array of hosts that will be checked
X##
X##  Gordon C. Galligher (10/2/91)
X##
X
sub gethosts
X{
X	local(@rdistargs) = @_;
X	local(@args)      = grep(!/-q/, @rdistargs);
X	local($")	  = " ";		# Be sure to have "@.." w/" "
X	local(@hosts);				# Array containing host names
X	local(@lines);				# Lines from &docmd.	
X	local($eval);				# Eval line.
X	local($rc);				# Return code from &docmd()
X
X	unshift(@args, "-n");
X	@lines = &docmd(0, 0, 0, $RDIST, @args);
X	if ( ($rc = shift(@lines)) != $OK )
X	{
X		die "Danger, Will Robinson!  Initial rdist == $rc\n" .
X		 	"Output:\n@lines";
X	} # IF $rc ...
X	elsif ( ($rc = shift(@lines)) != 0 )
X	{
X		die "Rdist error:  $rc\nOutput:\n@lines\n";
X	} # IF $rc ...
X
X	chop(@lines);				# Remove \n on each line.
X	foreach $line (grep(s/^updating host (.*)$/$1/, @lines))
X	{
X		$eval = "push(\@hosts, \$line) unless grep(/$line/, \@hosts)";
X		eval "$eval";
X	} # FOREACH $line ...
X	@hosts;					# Return list to the caller.
X} # GETHOSTS
X
X##
X##  MAIN
X##
X##		ACCEPTS:
X##			@ARGV	 --	Rdist(1) arguments
X##
X##		PERFORMS:
X##			This pseudo-function checks the environment variable
X##			$PDIST and sets things accordingly, and then goes
X##			into a loop executing rdist on each host.  At the
X##			end, it returns a value 0, if all hosts were
X##			updated as requested, or 1 if not.
X##
X##		RETURNS:
X##			0	 --	Everything updated correctly
X##			n	 --	There was a particular problem
X##
X##  Gordon C. Galligher (10/3/91)
X##
X
if ( defined($ENV{"PDIST"}) )
X{
X	local(@args) = split(' ', $ENV{"PDIST"});
X	while ( $_ = shift(@args) )
X	{
X		$TMOUT  = shift(@args)	if /-t/;
X		$RDIST  = shift(@args)	if /-r/;
X		$SHUTUP = 1		if /-q/;
X		$DOPING = 0		if /-noping/;
X	} # WHILE ...
X} # IF defined ...
X
X$rc = 0;
X@HOSTS = &gethosts(@ARGV);
X#$RDIST = "/this/will/cause/rtohost/to/fail";
foreach $host (@HOSTS)
X{
X	$rc |= &rtohost($host, @ARGV);
X} # FOREACH ...
X
exit($rc);
X
X.00;
X
X'di			\" Stop the diversion
X.nr nl 0-1		\" Fake up transition to first page again
X.nr % 0			\" Start at page 1
X'; __END__		\" From here on it is a standard manual page
X.\" ###########################################################################
X.\"
X.\"  This is the manual page for the pdist program.
X.\"
X.\"  $Id: pdist.perl.mail,v 1.1 2000/03/27 07:34:29 eichin Exp $
X.\"
X.\" ###########################################################################
X.\"
X.\"  $RCSfile: pdist.perl.mail,v $
X.\"
X.\"  $Author: eichin $
X.\"
X.\"  $Date: 2000/03/27 07:34:29 $
X.\"
X.\"  $Revision: 1.1 $
X.\"
X.\" ###########################################################################
X.\"
X.TH pdist 1 "$Date: 2000/03/27 07:34:29 $"
X.SH NAME
pdist \- Perl front-end for rdist program
X.SH SYNOPSIS
X.B pdist
X[rdist args]
X.PP
X.SH DESCRIPTION
X.B Pdist
X($Revision: 1.1 $)
is a front-end to the \fIrdist(1)\fR utility.
It merely keeps track of the execution of \fIrdist(1)\fR
and does not let it run away.
It has a timeout for output (default of 60 seconds),
so if the \fIrdist(1)\fR utility does not send output within
that amount of time,
it is assumed to be hung and is immediately killed.
If the \fB-q\fR option is not given, then the output from
X\fIrdist(1)\fR is displayed as it happens.  If a system
is killed in the middle the user is alerted regardless of
the presence of the \fB-q\fR flag.
If \fB-q\fR is specified, then no \fIrdist(1)\fR
output is sent to
the terminal.  The host killing function causing output
is a personal decision.  Like any feature I have, it can
be turned off.  See \fBOPTIONS\fR below for more information.
X.PP
Because this is a front-end to the \fIrdist(1)\fR program,
it accepts any and all of the \fIrdist(1)\fR commands that your particular
implementation of rdist supports.
There are only two options that are required in order for \fIpdist\fR
to operate properly:  \fB-m\fR, and \fB-n\fR.
The \fB-m\fR option is used to specify a single host,
out of the list of hosts in the \fIDistfile\fR to be updated.
The \fB-n\fR option is used to tell \fIrdist(1)\fR to not really
do anything, but just report what it \fBwould\fR do.
This utility works because it first executes \fIrdist(1)\fR with the
X\fB-n\fR option to see what hosts would be updated,
and then loops through each of those,
executing \fIrdist(1)\fR with the \fB-m\fR option so it only tries
to update one host at a time (and can kill it if it runs out of time).
X.PP
As another possible shortcut to figuring out if a host is capable of
updates is to use the \fIping(8)\fR command.  \fIPdist\fR first
sends an ICMP ECHO request (or two) to the host to see if it is
on the network and responding to \fIping\fR requests.
Since this is not 100% reliable (some routers may disable ICMP
packets to SLIP or PPP connections), there is an option (see below)
to tell it not to try \fIping(8)\fR first (or to just not trust its
output).
X.PP
X.SH RESTRICTIONS
X.PP
There is a memory leak in Perl prior to Version 4.0 which causes
X\fIpdist\fR to get a Segmentation Violation (and subsequent core dump)
when it has to kill a job.  For example, a host is down, or gets hung
while the \fIrdist(1)\fR is executing; \fIpdist\fR kills that process
and then when it attempts to go on to the next one, it gets a SEGV
signal and dumps core.  This program is verified to work with
Perl versions past 4.0.
X.PP
There is a minor difference (which could be major, depending upon how
you use it) between \fIpdist\fR and \fIrdist(1)\fR.  Rdist does not
really do a lot with the return code of the program, almost everything
returns a zero exit status.  Pdist, on the other hand, keeps track of
errors and warnings, and if it has to complain about a host, or skip
a host, then it remembers that and exits with a non-zero
exit status (namely, one).  When \fIrdist(1)\fR is fine and \fIpdist\fR
has to do nothing except monitor, then \fIpdist\fR will indeed exit
with a zero status.  This can actually be a benefit, but it can be a
hinderence for things such as a Makefile that depend upon \fIrdist(1)\fR
returning zero all the time.  This is not a feature, per se, because it
cannot be turned off, but it is merely a side-effect that I felt important
enough to point out.
X.PP
X.SH ENVIRONMENT
X.PP
This program is intended as a plug-and-play front-end to the \fIrdist(8)\fR
utility, and that means that wherever you use \fIrdist(1)\fR you should
be able to replace the call with \fIpdist\fR (assuming that \fIpdist\fR
and \fIperl\fR are in your path) and get the increased functionality.
Inorder to accomplish this, it is necessary to not use any command line
arguments to control \fIpdist\fR.  It is, however, necessary and
beneficial to customize the \fIpdist\fR utility for a particular
use without resorting to modifying the source code.
I have chosen the use of environment variables for this purpose.
The environment variable \fBPDIST\fR is checked at the onset of the
program, and this section details the options and their arguments
that belong only in the environment variable, and not on the command
line to \fIpdist\fR.
X.PP
X.SH OPTIONS
X.PP
Options found in the environment variable \fBPDIST\fR and what they
mean:
X.LP
X.IP -q
Just be quiet.  In normal operations \fIpdist\fR will report both
X\fIrdist(1)\fR errors and its own.  If the \fB-q\fR option is given on
the \fIpdist\fR command line, then all \fIrdist(1)\fR output will be
silenced, but \fIpdist\fR errors will still be generated.  To silence
the \fIpdist\fR errors just set \fBPDIST\fR to have \fB-q\fR in it.
To get \fIpdist\fR
to be totally quiet,
set \fBPDIST\fR to have \fB-q\fR option and include the \fB-q\fR
option on the \fIpdist\fR command line.
X.LP
X.IP "-t tmout"
Set the time that \fIpdist\fR will wait (in seconds) for output
>from the \fIrdist(1)\fR program (default of 60).
XEach time \fIrdist(1)\fR displays a line of output, this counter is
reset.  This implies that even if the \fB-q\fR option to \fIrdist(1)\fR
is used, it is stripped off for the purposes of the program.  \fIPdist\fR
does honor the \fB-q\fR option and, as such, ensures that no output
>from \fIrdist(1)\fR makes it to the
terminal.
X.LP
X.IP "-r rdist_cmd"
Set the path for the real \fIrdist(1)\fR command (default of
X\fB/usr/ucb/rdist\fR).
If the default for your site is incorrect, you can either
modify the source code, or create the \fBPDIST\fR environment
variable and put "-r /path/to/real/rdist" into it (see your favorite
shell's manual page for details on how to set and export an
environment variable).
This value \fBshould\fR be a full path to the real \fIrdist(1)\fR
executable (for security reasons), but this is not checked and if
it is not, then \fIperl\fR will do a path search for you (which
could, if running as root, lead to some security problems such as
Trojan Horse attacks).
X.LP
X.IP "-noping"
Do not try to \fIping(8)\fR the hosts to see if they are up
before trying the distribution to them.
While this is a convenience thing, if you have a router that
is disabling ICMP packets (for dial-up IP connections) then
any distribution to those hosts would fail because the ping
would fail.
This is not acceptable behavior, so just put \fB-noping\fR
into the \fBPDIST\fR environment variable and \fIping\fR will
not even be attempted.
X.\"
X.\" This next section is commented out because it is not currently
X.\" implemented.  I have not found a good way to do it yet, but
X.\" some thoughts have been "=help" or "=man" on the command line
X.\" (the = instead of - so it does not conflict with rdist args).
X.\"
X.\" .LP
X.\" .IP -help
X.\" Give help about \fIpdist\fR.  Namely, this exec's a copy of the
X.\" manual page formatter (\fInroff(1)\fR, with the -man macro package) and
X.\" pipes the output to the \fImore(1)\fR program (or whatever your
X.\" \fIPAGER\fR
X.\" environment variable is set to).  If \fInroff(1)\fR cannot be found (it
X.\" looks for \fInroff\fR and then \fIgroff\fR in the following places:  
X.\" \fI/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/gnu/bin\fR) then
X.\" \fIpdist\fR
X.\" will print out that it cannot give detailed help, and will show the usage.
X.\"
X.PP
X.SH "SEE ALSO"
X.PP
perl(1), ping(8), rdist(1)
X.PP
X.SH DIAGNOSTICS
X.LP
X.IP "No answer from \fIhost\fR, skipping update"
The \fIping(8)\fR command did not get a response from the host, so it
does not even try to execute \fIrdist(1)\fR on it.  See \fBOPTIONS\fR
above to see how to turn this \fIping(8)\fR checking off.
X.LP
X.IP "Unknown host \fIhost\fR, no update tried."
If \fIping(8)\fR gives an error "unknown host" for that particular host,
then \fIrdist(1)\fR is not even invoked, since it will have the same
error.
X.LP
X.IP "Update of \fIhost\fR failed, time expired."
While \fIrdist(1)\fR was updating the host,
it stopped producing output for a specified amount of time (see \fBOPTIONS\fR
for instructions on how to change this time).  Once this timer expired,
X\fIpdist\fR killed off the update and then went onto the next host in the
line.
X.LP
X.IP "Update of \fIhost\fR failed, cannot execute, \fIerrno\fR"
If the pipe to the \fIrdist(1)\fR command cannot be obtained (either
the rdist command cannot be found or some other problem) then this
line is printed.  The \fIerrno\fR is the output from the open command
which will give a system reason why it could not be executed.  If it is
the error \fINo such file or directory\fR error, then look at \fBOPTIONS\fR
above for information about how to specify an alternate path to the
X\fIrdist(1)\fR program.
X.LP
X.IP "Rdist exited with non-zero value:"
X\fIPdist\fR does some preliminary error code checking on the rdist program
to see that it exits with no error codes (zero exit status).  If it does
not exit with a zero, then \fIpdist\fR prints out this message with the
exit status following it.  Armed with this value, the administrator can
look at the manual page for the particular \fIrdist(1)\fR program to
see what the exit value really means.
X.LP
X.IP "Any that \fIrdist(1)\fR may give."
Since \fIpdist\fR is just a front-end to \fIrdist(1)\fR, any diagnostics
that \fIrdist(1)\fR may print will be printed by \fIpdist\fR (unless the
X\fB-q\fR option is given on the command line).
X.\" 
X.\" .LP
X.\" .IP "No formatter!"
X.\" Help was requested with the \fI=help\fR argument, but a suitable
X.\" formatter could not be found.
X.\"
X.PP
X.SH BUGS
X.PP
Since this is merely a front-end to the \fIrdist(8)\fR utility,
any bugs that exist in \fIrdist(8)\fR also exist in \fIpdist\fR.
X
There is a memory leak in Perl versions prior to 4.0.  This program
tickles that bug, therefore, Perl version 4.0 or better must be used
in order to use this program.
X.PP
X.SH AUTHOR
X.PP
X$Author: eichin $
X.PP
X.SH "REQUESTS/CHANGES"
X.PP
If \fIpdist\fR does not work on your system due to a bug in pdist that
is not mentioned above AND this is not a bug in rdist, then feel free
to send email requests to \[email-masked]\fR or
X\[email-masked]\fR if ping.chi.il.us bounces (it may change
soon).
X
If you find a bug and take the time to patch it for your site I would
appreciate it if you would send me an email message with this patch so
I can include it in the main distribution so others can benefit from your
work and we all can get a good package out of it.
X.PP
X.SH COPYRIGHT
X.PP
X.nf
PDIST $Revision: 1.1 $  Copyright 1991 Gordon C. Galligher
X
X  PDIST is free software; you can redistribute it and/or modify it
X  under the terms of the GNU General Public License as published by
X  the Free Software Foundation; either version 2, or (at your option)
X  any later version.
X
X  PDIST is distributed in the hope that it will be useful, but WITHOUT
X  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
X  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
X  License for more details.
X
X  You should have received a copy of the GNU General Public License
X  along with the Perl distribution; if not, write to the Free Software
X  Foundation, Inc., 675 Mass Ave, Cambridge, MA  02139, USA.
X
X.fi
END_OF_FILE
if test 29268 -ne `wc -c <'pdist'`; then
    echo shar: \"'pdist'\" unpacked with wrong size!
fi
chmod +x 'pdist'
# end of 'pdist'
fi
echo shar: End of shell archive.
exit 0
-- 
Gordon C. Galligher	9127 Potter Rd. #2E	Des Plaines, IL    60016-4881
[email-masked]   [email-masked]  ...!uu.psi.com!ping!gorpong
   	We had V6, V7, System III, System V, and now Plan 9.
	 Next AT&T will say:  "Gee, I could have had a V8."