Subject: Re: Help, I need a case-like construct!

From: Alan Stebbens <[email-masked]>
Date: Fri, 13 Mar 1992 02:46:05 GMT

|   I am trying to put together a script that will log onto 15 different
|   production systems and check for given background processes that
|   should be running, but are not.  I have figured out the connectivity to
|   get the script across the systems, but I am puzzled at how determine 
|   whether the processes that are supposed to be running are not, and
|   how to report it.
|  
|   I know PERL is the tool with it's incredible pattern-matching capabilities,
|   but unfortunately I am not that adept.  I was thinking of setting up the
|   process list in a case statement, is this possible?

Perl doesn't have a case, but it has a very optimized multi-"if"-"elsif"
control structure.  In any case, as with many languages, there are
several ways to do what you want: here's one.  It may not be optimal,
but you can probably learn some things from it.

procscan:
============================= cut here ===================================
#!/bin/perl
#
# The following builds a hashed-array of system-process list pairs.
# For each system, give a list of process, possibly followed by the max
# and min process count acceptable.  The defaults are: [*,1] or
# MAX,[MAX]; that is, if MAX is given, the MIN defaults to it, otherwise
# MIN defaults to 1, and there is no MAX.

%SysProcesses = ();
foreach (split(/\n/,<<EOF)) {
#Name   	Process[,max[,min]]
#----		-------	----
sys1		inetd,1  lpd nfsd,8 biod,4 sendmail gopherd nnmaster,1 
sys2		inetd,1  lpd nfsd,8 biod,4 sendmail kproc,4,1 srcmstr,1 fs,1
sys3		inetd,1  lpd nfsd,8 biod,4 sendmail swapper,1
# add more as you like
EOF
    next if /^#/ || /^$/;
    ($sys,@plist) = split(' ');
    $SysProcesses{$sys} = join(' ',@plist);
}

$thisHost = `hostname`;

# The following loops through the system name list, invoking a pipe to
# "ps axww" (either locally or remotely, as appropriate for the system),
# scanning and counting the subsequent output for process names
# occurrences, after which any process names with zero occurrences are
# reported.
#
foreach $sys (keys SysProcesses) {
    @plist = split(' ',$SysProcesses{$sys}); # get process list
    %procCount = ();
    %procMin = ();
    %procMax = ();
    foreach $proc (@plist) { 
	($name,$max,$min) = split(',',$proc);
	$min = 1 unless ($min = $max);	# default min is MAX
	$max = 999999999 unless $max;	# default max is BIG
	$procCount{$proc} = 0;
	$procMin{$proc} = $min;
	$procMax{$proc} = $max;
    }
    $rcmd = ($thisHost eq $sys ? "rsh $thisHost -n " : '').'ps axww';
    if (open(PS,"$rcmd|")) {	# scan PS output
	$header = <PS>;		# junk the header
	while (<PS>) {
	    ($pid,$stat,$tty,$time,$cmd) = split(' ');
	    ($cmdname,@cmdargs) = split(' ',$cmd);
	    $procCount{$cmdname}++;
	}
    }
    close PS;
    # Now figure out which commands aren't running or are under/over running
    foreach $proc (@plist) {
	$count = $procCount{$proc};
	$min = $procMin{$proc};
	$max = $procMax{$proc};
        $err = '';
	if ($count == 0) {
	    $err = 'not running';
	} elsif ( $count > $max ) {
	    $err = 'over-running';
	} elsif ( $count < $min ) {
	    $err = 'under-running';
	}
	if ($err) {
	    warn "Process $proc on system $sys is $err\n";
	    printf STDERR "\tCurrent = %d, min = %d, max = %d\n",
		          $count,$min,$max if $count > 0;
	}
    }
    undef %procCount;
    undef %procMax;
    undef %procMin;
}
============================= cut here ===================================
-- Alan Stebbens, UCSB, Santa Barbara <[email-masked]>
"If all you have is a hammer, then everything looks like a nail."