Tuesday 12 March 2013

Helpful Administrative Scripts


Courtesy: the-welters .com

These scripts are distributed under standard GNU Public License terms. You are free to use and distribute them, provided you preserve the attribution comments in them. They are not that sophisticated, but if you find them useful or have suggestions for improvement, please email. unix @ the-welters .com and let me know what you think. Most of these are written in Bourne shell. While I think Perl is a much better language for larger or more complex scripts, most of these are so simple that Bourne shell suites them just fine.
  • cdpinfo - display Cisco CDP packet info via tcpdump or snoop
  • createVgCloneScript - duplicate a volume group, volume, and filesystem structure
  • lvinfo - a script to help document Logical Volume Manager information on an AIX system.
  • wackVG - Delete the contents of a volume group, including all all files and volumes.
  • pstree - this script analyzes "ps" command output and displays the parent / child relationships of the running processes.
  • dumpall - a set of scripts to backup Solaris and Digital Unix systems.
  • vgbackup - a very basic script for doing backups on AIX systems.
  • mtfcount - count the file marks on a tape.
  • vmlog - a script that records time stamped vmstat output to a file.
  • hogs - A script to show the top CPU or Memory users on a system.
  • rex - An rexec client for executing commands on remote systems.
  • syslog maintenance scripts.
  • webcat and webload - These two scripts can be used to fetch web pages from the command line or generate system load on web servers.
  • logroll - A script to manage old log files.
  • format_clone - A script to copy Solaris disk format layouts from one disk to another.
  • inetd_cleanup - A script to tighten up the security of Solaris inetd configurations.
  • ping_scan - A script to ping IP addresses in sequence.
  • hostbyname - Get IP address for a host name via gethostbyname
  • hostbyaddr - Reverse lookup of hostnames by IP address, using gethostbyaddr
  • hostxcheck - Forward and reverse lookup cross check
  • rc4 - A perl implementation of the "crypt" rc4 encryption command.
  • repack - Recreate a Solaris package file from an installed package
  • makePackage - create a simple package through through simple prompts.
  • sh_ex - This Bourne shell script doesn't do anything, it just has a series of syntax examples to jog your memory when coding.
  • perl_ex - This Perl script doesn't do anything, it is just a series of syntax examples like sh_ex.





 

lvinfo

This script is handy for documenting the logical volume manager configuration for an AIX system. Having this information all in one place can be useful when trying to analyze disk utilization. It can also be valuable as part of the disaster recovery documentation for a system.
Click here to see the script.
Platforms supported: IBM AIX 4.x
#======================lvinfo=================================#

#!/bin/ksh
#
# Simple script to document LVM configurations.
#
# Andy Welter
# www.the-welters.com
#
exec 2>&1
printf "AIX DISK AND LVM INFORMATION\n"
printf "*********************************************************\n"
 
printf "\nDF\n"
printf "==========================\n"
df -k
 
printf "\nVOLUME GROUPS:\n"
printf "==========================\n"
lsvg
 
printf "\n\nPHYSICAL VOLUMES:\n"
printf "==========================\n"
lspv
 
printf "\n\nPVs BY VOLUME GROUP\n"
printf "==========================\n"
lsvg | while read VG; do
        VGLIST="$VGLIST $VG"
        printf "\n$VG\n"
        printf "--------------------------\n"
        lspv | grep $VG
done
 
printf "\n\nPV INFORMATION:\n"
printf "==========================\n"
lspv | while read PV; do
        printf "\n$PV\n"
        printf "--------------------------\n"
        lspv $PV
done
 
printf "\n\nVG INFORMATION\n"
printf "==========================\n"
for VG in $VGLIST; do
        printf "\n$VG\n"
        printf "--------------------------\n"
        lsvg $VG
        lsvg -l $VG
done
 
printf "\n\nLV INFORMATION\n"
printf "==========================\n"
for VG in $VGLIST; do
        printf "\nVolume Group: $VG\n"
        printf "--------------------------\n"
        lsvg -l $VG | egrep -v "^$VG:" | egrep -v "^LV NAME" | while read LV JUNK; 
do
               printf "\nLogical Volume: $LV\n"
               printf "--------------------------\n"
               lslv $LV
        done
done
 
#=======================lvinfo================================#

cdpinfo

Display Cisco Discovery Protocol packet information via tcpdump or snoop. This information includes the name of the network switch the network interface is connected to, plus the port number, vlan, and duplex of the port.
Click here for the script.
Platforms supported: IBM AIX, Sun Solaris
#=======================cdpinfo===============================#

#!/usr/bin/perl
#
# Listen for Cisco Discovery Protocol (CDP) packets
# and print out key values such as switch, port, vlan, and duplex.
#
# This script depends on either "snoop" (Solaris) or 
# "tcpdump" (AIX, and others).  Both of those programs generally 
# must be run as root.
#
# It has been tested on Solaris 10 and AIX 5.3.
#
# Andy Welter
# Version 1.1
# July 2007
#       Support timeout values while waiting on the cdp packet.
# Version 1.0
# December 2006
#       Initial Version.  
#
# 
 
$usage="cdpinfo -i <ethernet interface> [-t timeoutvalue] [-v]\n-i use the enX device name for the interface to watch\n-t timeout value in seconds.  Don't wait for a cdp packet longer than this. default is 60 seconds.  zero means no limit.\n-v verbose output\n";
use Getopt::Std;
if ( getopts ('i:t:v') == 0) {
        print "$usage";
        exit 1;
};
 
$idev=$opt_i; 
if ($opt_i) {
        $iface="-i $opt_i";
};
$verbose=$opt_v;
$timeout=$opt_t;
 
#
# convert string data to hex characters.
#
sub hexprint {
        my ($string)=@_;
        my $hex="";
        my $ii,$len;
        $len=length ($string);
        $ii=0;
        @bytes=unpack "C*",$string;
        foreach $byte (@bytes) {
            $hex=$hex . sprintf "%02x ",$byte;
            $ii++;
        };
return $hex;
};
 
 
#
# Parse TCP dump output to acquire a CDP packet
sub tcpdump {
my ($cmd)=@_;
# tcpdump omits the first 14 bytes of a packet in the hex dump
# so put some filler in the packet string
my $packet="01234567890123";
 
open (GETPACKET, "$cmd") || die "cannot open $cmd\n";
while ( $_ = <GETPACKET> ) {
        chomp;
        #
        # look a line that starts with white space, followed by at least
        # 2 hex characters
        if (m/^\s+([\da-fA-F]+ )/) {
               s/^\s+//;
               @data=split /\s+/,$_,8;
               foreach $bytes (@data)         {
                       $verbose && print "$bytes ";
                       $packet=$packet . pack "H4", $bytes;
               };
               $verbose && print "\n";
        } ;
};
close GETPACKET;
return $packet;
};
 
 
#
# Parse "snoop" output for the packet
sub snoop  {
my ($cmd)=@_;
my $packet="";
open (GETPACKET, "$cmd") || die "cannot open $cmd\n";
while ( $_ = <GETPACKET> ) {
        chomp;
        print "-- $_\n";       
        if (/^\s+\d+:/) {
               s/^\s+//;
               @data=split /\s+/,$_,10;
               shift @data;
               pop @data;
               foreach $bytes (@data)         {
                       $packet=$packet . pack "H4", $bytes;
               };
        };
};
close GETPACKET;
return $packet;
};
 
#
# Parse the acquired CDP packet for key values.
#
sub decodePacket {
my ($packet)=@_;
my $plen,$string,$ii,$flength,$switchName,$switchPort,$ftype,$vlan,$duplex;
# decode the packet
# ethernet layout:
# 0-7   8 byte preamble
# 8-13  6 byte dest mac addr
# 14-19 6 byte source mac addr
# 20-21 2 byte type field
# 22-23 2 byte check sum
# 24-25 2 byte ???
# 26-27 2 byte first CDP data field
# 28-29 2 byte field length (including field type and length)
# 30--  Variable data.
#       4 byte CRC field.
#
# Field type indicators
# Device-ID  => 0x01
# Version-String  => 0x05
# Platform  => 0x06
# Address  => 0x02
# Port-ID  => 0x03
# Capability  => 0x04
# VTP-Domain  => 0x09
# VLAN-ID  => 0x0a
# Duplex  => 0x0b
# AVVID-Trust  => 0x12
# AVVID-CoS  => 0x13);
 
 
$verbose && printf "packet len=%d\n",length($packet);
#
# The CDP packet data starts at offset 26
$ii=26;
$plen=length ($packet);
while ( $ii < $plen-4) {
        $ftype=unpack "S", substr ($packet, $ii, 2);
        $flength=unpack "S", substr ($packet, $ii+2, 2);
        if ( $ftype == 1 ) {
               $switchName=substr ($packet,$ii+4,$flength-4);
        } elsif ( $ftype == 3 ) {
               $switchPort=substr ($packet,$ii+4,$flength-4);
        } elsif ( $ftype == 10 ) {
               $vlan=unpack "s",substr ($packet,$ii+4,$flength-4);
        } elsif ( $ftype == 11 ) {
               $duplex=unpack "c",substr ($packet,$ii+4,$flength-4);
        };
        $string=substr ($packet,$ii+4,$flength-4);
        $fvalue=hexprint ($string);
        $string=~s/\W/./g;
        $verbose && printf "\noffset=%d, type 0x%04x, length 0x%04x\nHex Value:\n%s\nASCII value:\n%s\n\n",
               $ii,$ftype, $flength-4,$fvalue,$string;
        if ($flength == 0 ) {
               $ii=$plen;
        };
        $ii=$ii+$flength;
};
return sprintf "\"%s\",\"%s\",\"%d\",\"0x%02x\"",
        $switchName,$switchPort,$vlan,$duplex;
};
 
#
# MAIN ROUTINE
#
# determine whether we are a snoop or tcpdump kinda system
$cmd=`which tcpdump`;
chomp $cmd;
if ( $cmd ne "" ) {
        $cmd= "$cmd $iface -s 1500 -x -c 1 'ether [20:2] = 0x2000' 2>/dev/null |";
} else {
        $cmd=`which snoop`;
        chomp $cmd;
        if ( $cmd ne "" ) {
               $cmd="$cmd $iface -s 1500 -x0 -c 1 'ether[20:2] = 0x2000' 2>/dev/null |";
        } else {
               print "ERROR: neither snoop nor tcpdump in my path\n";
               exit 1;
        };
};
 
sub timeout {
        die "TIMEOUT";
};
$SIG{ALRM}=\&timeout;
 
eval {
alarm ($timeout);
#
# use tcpdump or snoop to get a CDP packet
if ( $cmd=~m/snoop/ ) {
        $packet=snoop ($cmd);
} elsif ( $cmd=~m/tcpdump/ ) {
        $packet=tcpdump($cmd);
} else {
        print "ERROR: snoop or tcpdump not found\n";
        exit 1;
};
alarm(0);
};
if ($@ =~ "TIMEOUT") {
        $packet="";
};
 
#
# Decode the acquired packet and print the results.
print  '"' . $idev . '",' . decodePacket ($packet) . "\n";

#=======================cdpinfo===============================#

CreateVgCloneScript:

This script can used in disaster recovery to rebuild the non-rootvg volume groups and volumes on a system. The output of this script is a script that will run the required mklv and crfs commands needed to duplicate a systems file system structure. This script needs to be run prior to a disaster in order to produce the volume creation script. The volume creation script requires some manual editing in order to adapt to the specific hardware being used for recovery. In the event of a real recovery the disk names and sizes will differ from the original system configuration, which requires that the mklv commands be manually edited.
Click hereto see the script.
Platforms supported: IBM AIX 5.x

#====================Createvg Clone============================#
#!/usr/bin/perl
#
# This script is used in disaster recovery to rebuild the 
# non-rootvg volume groups and volumes on a system. The output
# of this script is a script that will run the required mklv and
# crfs commands needed to duplicate a systems file system structure.
#
# This script needs to be run prior to a disaster in order to 
# produce the volume creation script. The volume creation script
# requires some manual editing in order to adapt to the specific 
# hardware being used for recovery.  In the event of a real recovery
# the disk names and sizes will differ from the original system 
# configuration, which requires that the mklv commands be manually 
# edited.
#
# Andy Welter - ajw8
# MeadWestvaco
# February 2005
# Version 1.4
# v1.4 NOTE: use "lsfs" to get nbpi, frag size, bf, and other file system parms.
# v1.3 NOTE: added jfslog and jfs2log volume support.  Fixed $lps vs $pps bug.
# v1.2 NOTE: fixed file system type error with mklv.  Changed output comments.
#
sub getfsparms {
#
# Use lsfs to determine the parameters used in creating the file system.
my ($fsname)=@_;
my $commandOptions="";
my $parms=`lsfs -cq $fsname | tail -1`;
 
chomp $parms;
$parms=~s/[\(\)]//g;
@parmList=split /:/,$parms;
foreach $option (@parmList) {
        @parsed=split /\s+/,$option;
        if ($parsed [0] eq "frag" ) {
               $commandOptions=$commandOptions . " -a frag=$parsed[2]";
        } elsif ( $parsed [0] eq "nbpi" ) {
               $commandOptions=$commandOptions . " -a nbpi=$parsed[1]";
        } elsif ( $parsed [0] eq "compress" ) {
               $commandOptions=$commandOptions . " -a compress=$parsed[1]";
        } elsif ( $parsed [0] eq "ag" ) {
               $commandOptions=$commandOptions . " -a ag=$parsed[1]";
        } elsif ( $parsed [0] eq "logname" ) {
               $commandOptions=$commandOptions . " -a logname=$parsed[1]";
        };
};             
return $commandOptions;
};
 
$scriptOutput=$ARGV[0];
 
if ( $scriptOutput ne "" ) {
    if ( -f $scriptOutput ) {
        rename ($scriptOutput,"$scriptOutput.old");
    };
    open (SCRIPT, ">$scriptOutput") ||
        die "cannot write output file $scriptOutput\n";
    select SCRIPT;
};
 
open (LSVG, "lsvg |") || die "cannot get vglist\n";
 
while ( $_ = <LSVG>) {
    chomp;
    if ( $_ ne "rootvg" ) {
        push (@vglist, $_);
    };
};
close LSVG;
 
print "#!/usr/bin/ksh\n";
print "## 
## This script auto generated by /root/createVgCloneScript
## Edit this script as needed, and run it to recreate
## non-rootvg volume groups and file systems.
##\n";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime (time);
printf ("## Created: %02d/%02d/%04d %02d:%02d:%02d \n",
        $mon+1, $mday, $year+1900, $hour, $min, $sec);
 
print "echo 'script to clone volume groups:'\n";
print "echo \"@vglist\"\n\n";
 
print "echo 'Create Volume groups:'\n";
print "echo 'edit script to add physical volumes to each mkvg command'\n";
print "echo 'ex: mkvg -f -y myvgname hdisk1 hdisk2'\n";
print "\n";
print "echo 'NOTE: once this script has been edited with the proper hdisks,'\n";
print "echo '      remove the exit statement from the script so it will run'\n";
print "#################################################\n";
print "## REMOVE THIS EXIT AFTER EDITING MKLV COMMANDS:\n";
print "#################################################\n";
print "exit 1\n\n\n";
foreach $vg (@vglist) {
    print "# volume group: $vg\n";
    open (VGINFO, "lsvg $vg |") ||die "cannot get vginfo for $vg\n";
    while ($_ = <VGINFO> ) {
        chomp;
 
        @info=split (/\s+/);
        if ( m/^VG STATE/ ) {
               $ppSize{$vg}=$info[5];
        } elsif ( m/^ACTIVE PVs/) {
               $vgActive{$vg} = $info[5];
        } elsif ( m/TOTAL PPs/) {
               $vgSize{$vg}="$info[5] $info[6] $info[7]";
        } elsif ( m/USED PPs/) {
               $vgUsed{$vg}="$info[4] $info[5] $info[6]";
        };
    };
    if ( $vgActive {$vg} ne "yes" ) {
        $noStart="-n";
    } else {
        $noStart="";
    };
    print ("#####################\n");
    print ("# CREATE $vg\n");
    print ("#    ORIGINAL SIZE: $vgSize{$vg}\n");
    print ("#    ORIGINAL USED: $vgUsed{$vg}\n");
    print ("# mkvg -f -s $ppSize{$vg} $noStart -y $vg <INSERT HDISK LIST>\n");
    close VGINFO;
};
 
foreach $vg (@vglist) {
   #
   # Create jfs and jfs2 log volumes.  Need to do this before we 
   # create the file systems.
   #
   open (LVLIST, "lsvg -l $vg | tail +3 |") || die "cannot get lvlist for $vg\n";
   while ( $_ = <LVLIST> ) {
        ($volname, $type, $lps, $pps, $pvs, $state, $mount) = 
               split /\s+/;
        if ($type eq "jfslog" || $type eq "jfs2log") {
               $logType=$type;
               $logType=~s/log//;
               print "#\n# $logType log file.\n";
               print "mklv -t $type -y $volname $vg $lps\n";
               print "logform -V $logType /dev/$volname\n";
        };
   };
   close LVLIST;
 
 
   open (LVLIST, "lsvg -l $vg | tail +3 |") || die "cannot get lvlist for $vg\n";
   while ( $_ = <LVLIST> ) {
        ($volname, $type, $lps, $pps, $pvs, $state, $mount) = 
               split /\s+/;
        if ($type eq "jfs" || $type eq "jfs2" || $type eq "paging") {
               push (@fsList, $mount);
               $lvInfo {$vg} = "$type $lps $mount";
               if ( $type eq paging ) {
                       print "mkps -s $lps -t lv $vg\n";
               } else {
                       $fsParms=getfsparms($mount);
                       # convert number of PPs to number of 
                       # 512 byte blocks
                       $fsSize=$lps * $ppSize{$vg} * 2048;
                       print "#\n# $mount file system size = $fsSize bytes\n";
                       print "lsfs $mount 2> /dev/null >&2\n";
                       print "if [ \$? -eq 0 ]; then\n\trmfs $mount\nfi\n";
                       print "mklv -t $type -y $volname $vg $lps\n";
                       print "crfs -v $type -A yes -d $volname $fsParms -m $mount\n"
               };
        };
   };
   close LVLIST;
};
#
# Sort the file systems by mount point name.  Mount points
# need to be created, and hierarchical file systems need to 
# be mounted in the proper order in order to create the 
# sub directory mount points.
 
print "\n##\n## Create mount points and mount file systems\n##\n";
@fsList=sort @fsList;
foreach $fs (@fsList) {
    print "if [ ! -d $fs ]; then\n";
    print "    mkdir -p $fs\n";
    print "fi\n";
    print "mount $fs\n";
};
#====================Createvg Clone============================#

wackVG:

This script performs a basic cleanup of a volume group in order to provide a somewhat secure remove of data. This is obviously not DOD or financial system grade data erasure, but may be sufficient for many enviroments when turning systems over to a recycling company or at the end of an offsite disaster recovery test. The script does the following actions: For each volume in the indicated volume group: - kill any processes using file systems in the volume group - recursively remove all files in the volume - remove the file system with rmfs - once all the volumes are removed, remove the volume group via reducevg. For best results, follow up the deletion of the volume group with a creation of a new volume group re-using the PVs.
Click here to see the script.
Platforms supported: IBM AIX 5.x
#==================== wackVG================================#
#!/bin/ksh
#
# This script performs a basic cleanup of a volume group in 
# order to provide a somewhat secure remove of data.  This is 
# obviously not DOD or financial system grade data erasure, 
# but may be sufficient for many enviroments when turning 
# systems over to a recycling company or at the end of an 
# offsite disaster recovery test.  
#
# The script does the following actions:
#    For each volume in the indicated volume group:
#       - kill any processes using file systems in the volume group
#       - recursively remove all files in the volume
#       - remove the file system with rmfs
#    - once all the volumes are removed, remove the volume group
#      via reducevg.
#
# For best results,
# follow up the deletion of the volume group with a creation
# of a new volume group re-using the PVs.
#
# Andy Welter
# January 2005
#
 
VG=$1
TESTRUN=$2
if [ "$VG" = "" ]; then
        print "ERROR: must specify a volume group"
        exit 1
fi
 
print "!!!!!!!! WARNING !!!!!!!"
print "!!! This script will !!!"
print "!!! delete all data  !!!"
print "!!! on the following !!!"
print "!!! volume group:    !!!"
print
lsvg -l $VG
print "Whack $VG ?\n\n"
read ANS
case $ANS in
        y|Y) print "Ok, here we go"
                sleep 2
                ;;
        *) print "Quitting."
                exit 1
                ;;
esac
lsvg -l $VG | sort -b +6r| egrep "jfs |jfs2 " | grep -v "^LV NAME" | \
        while read LVNAME TYPE LP PP PV STATE MOUNT; do
        print "removing $MOUNT..." >&2
        if [ "$TESTRUN" = "" ]; then
                fuser -ck $MOUNT
                find $MOUNT -xdev -depth -exec rm {} \;
                ls -alR $MOUNT
                umount $MOUNT
                rmfs $MOUNT
        else
                print "test: $MOUNT"
        fi
done
lspv  | while read PVNAME VOLID CURVG STATUS; do
        case $CURVG in
        $VG) print "remove $PVNAME from $VG"
                if [ "$TESTRUN" = "" ]; then
                        reducevg -df $VG $PVNAME
                fi
                ;;
        *) print "ignore $PVNAME... belongs to $CURVG"
                ;;
        esac
done
 
#==================== wackVG================================#

Pstree:

This script can be handy to visualize the parent child relationships of processes running on your system. When analyzing performance or other system problems, you often want to find out who belongs to who. This script uses a really handy feature in newer "ps" commands. The "-o" option. this command line option is used to control specifically what output fields you are interested in from "ps" and specifically what order you want them to appear in. This makes it much much easier to pick apart the output of "ps" in a script.
When issued without any parameters, it displays the ancestry of all processes running on the system relative to the "schd" process. (pid 0). You can also supply a specific pid, and only the ancestry of that process will be shown.
This script is kinda interesting in that it is a Bourne shell script that uses recursion. But because of this, it is really inefficient (recursive calls require a new process be spawned off). It would be much better off written in Perl, but I originally wrote it before I knew Perl very well.
click here to see the script.
Platforms supported: Unixs who's "ps" command supports the "-o" option. (ie, Solaris, Digital Unix, AIX, but not Linux)
#======================Pstree=================================#
#!/bin/sh
#
# Author: Andy Welter
# www.the-welters.com
# January 15, 2000
#
# Display a parent child relationship for a process or all processes
# on a system.
#
# This script uses recursive calls to itself in a bourne shell script
# which is kinda cool, but is really inefficient.
# 
# It takes advantage of the "-o" option on the PS command to put
# the PS output into a more easily parsed format and this also
# makes it more portable between Unix flavors.  Linux does not
# support this option, so unfortunately it doesn't work on Linux.
#
 
lookup_ancestors () {
        #
        # Find parent of current process, then recursively call this
        # script to display it's line of anscestors.
        #
        # Note that Orphan processes show pid 1 as their parent.
        #
        PID=$1
        PROC=`cat $FILE | grep "^$PID "`
        PPID=`echo "$PROC" | (read pid ppid user args;echo $ppid)`
        if [ -n "$PPID" ]; then
                if [ $PID -ne 0 ]; then
                        $0 -p $PPID
                fi
        fi
}
 
lookup_descendents () {
        #
        # Find list of children of the current process, and recursively
        # call this script for each of the children found to display
        # their children.
        cat $FILE | grep " $1 " |  \
        while read PID PPID USER ARGS; do
               if [ "$PID" != "$PPID" ]; then
                       $0 -c $PID "$indent"
               fi
        done
        }
 
display_process () {
        #
        # display the ps info of the indicated process. 
        # (can be used for parents or children)
        # $1 is the pid to display
        # $indent is the amount of indentation to display before the process
        #
        cat $FILE | grep "^$1 " | while read PID PPID USER ARGS; do
        echo "$indent$USER     $PID    $PPID   $ARGS"
        done
}
 
 
step="  "
 
PS="ps -ea -o pid -o ppid -o user -o args"
 
if [ "$1" = "-p" ]; then
        #
        # look up parent pid then display the current process.  
        # anscestors will be in oldest to newest order.
        #
        # don't bother indenting for parents.
        #indent="$3"
        lookup_ancestors $2
        #indent="$indent$step"
        display_process $2 
elif [ "$1" = "-c" ]; then
        #
        # lookup child pid
        #
        indent=$3
        display_process $2
        indent="$indent$step"
        lookup_descendents $2
else
        if [ "$1" = "" ]; then
               START=0
        else
               START=$1
        fi
        #
        # This is the initial call to the script.  
        # Display ancestors and descendents #
        #
        echo
        echo "================="
        echo "= Looking up information for process $START"
        echo "================="
        # Get the output to ps and normalize it's output
        FILE=/tmp/pstree.$$
        export FILE
        indent=""
        $PS | tail +2 | sed 's/^ *//g' > $FILE
        display_process $START
        #
        echo
        echo "================="
        echo "= Ancestors of process $START"
        echo "================="
        lookup_ancestors $START
        #
        echo
        echo "================="
        echo "= Descendents of process $START"
        echo "================="
        lookup_descendents $START
 
        /bin/rm $FILE
fi

#======================Pstree=================================#

Vmlog:

This script provides a simple way to log performance data to a file. Running accounting or installing a full shrink wrap package like HP Perfview can obviously provide you with more information. But if you want something cheap and easy, this can be a good start. The first step on solving performance complaints is to know what the system has done in the past. And the first steps in justifying hardware upgrades is to show that the system is busy and that usage has increased. The way I install this script is to run it via cron at midnight. By default, it reports 24 hours worth of observations, 60 seconds apart. Command line options can be used to alter the interval between observations or alter the number of observations.
Platforms supported: Most Unix flavors
#======================Vmlog================================#

#!/bin/sh
#
# This script records "vmstat" information for a defined period of time, 
# (default of 1 day) and records it to a file with a time stamp for each 
# line.  when the script is done running each day, it compresses the log file.
#
# This script would typically be called from cron at just after midnight 
# each day.
#
# Usage:
USEAGE="vmlog [-i interval] [-c count] [-l logfile]"
#
# Logfile      - If not specified, this defaults to /var/tmp/vmlog with a 
#              date and time stamp appended to the end.
# Interval     - If not specified, this defaults to 60 seconds.
# Count        - If not specified, this defaults to 24 hours worth of 
#              observations, the number of which depends on the interval 
#              chosen.
#
# Andy Welter
# www.the-welters.com
# 9/28/98
#
if [ $# -eq 1 ]; then
        echo $USAGE
        exit 1
fi
 
while [ $# -ge 2 ]; do
case $1 in 
        -c)     COUNT=$2
               shift 2
               ;;
        -i)     INTERVAL=$2
               shift 2
               ;;
        -l)     LOG=$2
               shift 2
               ;;
        *)      echo $USAGE
               exit 1
               ;;
esac
done
 
if [ -z "$INTERVAL" ]; then
        INTERVAL=60
fi
if [ -z "$COUNT" ]; then
        # Number of seconds in a day = 24x60x60=86400
        COUNT=`expr 86400 / $INTERVAL`
fi
if [ -z "$LOG" ]; then 
        LOG=`date +"/var/tmp/stats/vmlog.%y%m%d"`
else 
        LOG=`date +"$LOG.%y%m%d"`
fi
 
vmstat $INTERVAL $COUNT | while read LINE; do
        date +"%H:%M:%S $LINE" >> $LOG
done
 
compress $LOG


#======================Vmlog================================#











#======================Vmlog Clearnup=========================#

#!/bin/sh
#
# This program deletes vmlog output files.
#
# Andy Welter 10/01/98
# www.the-welters.com
#
#
# TIMELIMIT is used to control how long a file is kept by the system.
# every time this script runs, it will delete files that are greater 
# than the specified number of days.
#
# TIMELIMIT must start with a "+" in order to function properly.
#
TIMELIMIT="+30"
LOGDIR=/var/tmp/stats
DATE=`date +"%y%m%d"`
if [ -d $LOGDIR ]; then
        find $LOGDIR -type f -name 'vmlog.*' -mtime $TIMELIMIT -exec rm {} \;
fi

#======================Vmlog Clearnup=========================#

vgbackup

This script needs to be reworked, it isn't the greatest right now. It does a few things for you, so it is a starting point, but it doesn't send results via email, or warn you if you are not backing up a volume group or anything like that. All it does is do a mksysb, followed by a dump of the volumes in each additional volume group you specify. It maintains a log file, and can automatically print it out, but it doesn't send the results in email.
Click here to see the script.
Platforms supported: AIX 3.x and 4.x.
#======================vgbackup==============================#

#!/bin/ksh  
#
# Simple backup script for a list of volume groups.  All filesystems
# in each of the volume groups specified will be backed up using the
# "backup" command.
#
# Andy Welter
# www.the-welters.com
# February 17, 1999
#
# parms:
# -log  If this parm is used, script output will be logged to 
#       /var/adm/logs/backup.YYMMDD.log.  Otherwise script output
#       will be written to the screen.
# <vglist>  A list of additional volume groups to backup.  If not present, the 
#       The script defaults to backing up "rootvg" only.
# 
DEV=/dev/rmt0.1
PRINT=""
 
while [ "$1" != "" ]; do
case $1 in 
        "-log")
               # Redirect output to the log file
               LOG=`date +"/var/adm/logs/backup.%y%m%d.log"`
               exec 2> $LOG >&2
               ;;
        "-print")
               PRINT="yes"
               ;;
        *)
               VGLIST="$VGLIST $1"
        esac
shift
done
 
if [ "$VGLIST" = "" ]; then
        VGLIST=""
fi
# Get list of mount points
for VG in $VGLIST; do
        lsvg -l $VG | grep " jfs " | \
        while read LV junk2 junk3 junk4 junk5 junk6 FS; do
               FSLIST="$FSLIST $FS"
        done
done
if [ "$FSLIST" = "" ]; then
        echo "NOTE:  No extra file systems specified."
        echo "NOTE:  Only rootvg will be backed up."
fi
RC=0
date +"begin backup at %y/%m/%d %H:%M"
echo "Performing a mksysb and backing up the following file systems: $FSLIST"
echo "Run mksysb..."
mkszfile && mksysb -m -i -X $DEV
RC2=$?
RC=`expr $RC + $RC2`
date +"mksysb complete at %y%m%d %H:%M"
 
for FS in $FSLIST; do
        date +"backup $FS %y/%m/%d %H:%M"
        /etc/backup -0 -f $DEV $FS
        RC2=$?
        RC=`expr $RC + $RC2`
        if [ $RC -eq 0 ]; then 
               echo "SUCCESS: done with $FS"
        else
               echo "ERROR: Backup of $FS failed"
        fi
        echo
done
# eject the tape
 
if [ $RC -eq 0 ]; then
        echo "ejecting the tape..."
        mt -f $DEV offline
else
        echo "ERROR: at least one backup had errors."
fi
 
date +"done with backup at %y/%m/%d %H:%M"
 
if [ "$PRINT" = "yes" ]; then
        lp $LOG
fi
 

#======================vgbackup==============================#

mtfcount

This script counts the number of file marks on a tape. It can optionally position the tape just past the last file mark when it is done. This can be handy when trying to figure out what is on an unmarked tape, when verifying that a backup worked correctly, or when you want to append additional backups on the end of a tape that has been rewound already.
click here to see the script.
Platforms supported: Most Unix flavors

#======================mtfcount==============================#

#!/bin/sh
#
# Count file marks on a tape.  It can optionally position the tape
# after the last mark so you can append to the end of it.
#
# Andy Welter
# www.the-welters.com
#
USAGE="mtfcount [-f <devname>] [-append|-a]"
if [ "$TAPE" = "" ]; then
        DEV=/dev/rmt/0n
else
        DEV=$TAPE
fi
while [ $# -ge 1 ]; do
        case $1 in 
        -f)
               DEV=$2
               shift 2
               ;;
        -append|-a)
               APPEND=yes
               shift
               ;;
        *)
               echo "$USAGE"
               exit 1
               ;;
        esac
done
mt -f $DEV rewind
COUNT=0
RC=0
while [ $RC -eq 0 ]; do
        echo "Skipping file $COUNT..."
        mt -f $DEV fsf 1
        RC=$?
        if [ $RC -eq 0 ]; then
               COUNT=`expr $COUNT + 1`
        fi
done
 
echo "$COUNT files found on tape"
echo "rewinding tape..."
mt -f $DEV rewind
if [ "$APPEND" = "yes" ]; then
        if [ $COUNT -ge 1 ]; then
               echo "positioning tape to the end..."
               mt -f $DEV fsf $COUNT
        fi
fi
 

#======================mtfcount==============================#

hogs

This simplistic script uses the "-o" parameter to the ps command to put the ps output format into a more easily parsed format. This is a handy technique for any script that has to parse "ps" output. Unfortunately, not all ps commands support this option. Linux is one of the systems that does not support it. The "top" program available elsewhere on the net is a more powerful way of monitoring CPU utilization, but I still like this simple tweak to a ps command.
click here to see the script
Platforms supported: Versions of Unix that support the "-o" option for "ps" (ie not Linux)

#=========================hogs==============================#
#!/bin/ksh
#
# Display the top memory users or CPU users via ps.  
#
# Andy Welter
# www.the-welters.com
# 
# BUGS:
#       This script doesn't sort CPU time properly for processes using 
#       more than 24 hours of CPU time.  Re-writting this in perl is the 
#       most practical way to fix this bug since that will give me a lot
#       better string manipulation and pattern matching control.
#
USAGE="hogs [-mem|-cpu]"
 
if [ $# -ge 1 ]; then
        OPT=$1
else
        OPT="-mem"
fi
 
case $OPT in 
-c*) 
        # The long string of sed commands is used to normalize the elapsed CPU time field so 
        # that the processes are sorted by time properly.  
        echo "Top CPU users"
        echo "cputime     vsize  started      pid user       command"
        ps -ea -o time -o vsz -o stime -o pid -o user -o comm | \
               tail +2 | \
               sed 's/  *..:.. / ZZ:&/' | sed 's/  *ZZ:  */ 00:/' | sed 's/^  */ /' | sed s'/00:0:/00:00:/' | 
               sort -rn | head -20
        ;;
-m*)
        echo "Top Memory users"
        echo "vsize    cputime  started       pid     user    command"
        ps -ea -o vsz -o time -o stime -o pid -o user -o comm | \
               tail +2 | sort -rn | head -20
        ;;
*)
        echo "$USAGE"
        exit 1
esac

#=========================hogs==============================#

Rex”’

This Perl script acts as a "rexecd" client.
The rexec protocol is a is a method for executing commands on a remote system using a username and password for authentication. This differentiates rexec from rsh. Rsh commands use .rhosts and hosts.equiv files to set up trust relationships between systems, and allow command execution without a separate password challenge. There are security drawbacks to each approach.
Trust relationships can be used to compromise other systems once one system is breached. And rexec has no logging for failed login attempts. This allows it to be used as a conduit for dictionary password guessing attacks on a system. Systems directly exposed to the Internet should not run the execd. Systems on controlled networks should use software such as TCP Wrappers or "logdaemon" in order to put logging in place on this service. Future enhancements will include sending standard error and standard to different file descriptors and changing the command's ARGV list so that the command line options (ie password) are not visible via "ps" while the script is running.
inetd listens for rexec requests via TCP connections on port 512. rexec format as documented in the man page for rexec: The input stream consists of null separated values.
"port for standard error\0username\0password\0command and args\0"
Click here to see the script.
#=========================Reg==============================#

#!/usr/local/bin/perl
#
# Andy Welter
# www.the-welters.com
# January 10, 2000
# 
# This script acts as a "rexec" client.  The rexec protocol is a 
# is a method for executing commands on a remote system using a 
# username and password for authentication.  This diffentiates
# rexec from rsh.  Rsh commands use .rhosts and hosts.equiv files
# to set up trust relationships between systems, and allow command
# execution without a seperate password challenge.
#
# There are security drawbacks to each approach.  Trust relationships
# can be used to compromise other systems once one system is breached.
# And rexec has no logging for failed login attempts.  This allows it
# to be used as a conduit for dictionary password guessing attacks on 
# a system.  
# 
# Systems exposed to the internet should not run the execd.  Systems on
# controlled networks should use software such as TCP Wrappers in order
# to put logging in place on this service.  inetd listens for rexec requests
# via TCP connections on port 512.
# 
# rexec format as documented in the man page for rexec:  The input stream
# consists of null separated values. 
# port for standard error\0username\0password\0command and args\0
#
use Socket;
 
sub sendcmd {
$sockaddr = 'S n a4 x8';
($name, $aliases, $proto) = getprotobyname('tcp');
($name, $aliases, $type, $len, $thisaddr) = gethostbyname($host);
$thisport = pack($sockaddr, &AF_INET, 0, $thisaddr);
$thatport = pack($sockaddr, &AF_INET, $port, $thisaddr);
 
socket(S, &PF_INET, &SOCK_STREAM, $proto) ||
        die "cannot create socket\n";
        connect(S,$thatport) || die "cannot connect socket\n";
 
# Set socket to write after each print
select(S); $| = 1; select(STDOUT);
 
#
# Send command
#
printf S "0\0%s\0%s\0%s\0",$user,$passwd,$command;
#
# Read responses from server and print them out 
#
while ( $_ = <S> ) {
        printf ("$_");
};
close(S);
};
 
#
# MAIN
#
#
$port=512;
$host=$ARGV[0];
$user=$ARGV[1];
$passwd=$ARGV[2];
$command=$ARGV[3];
sendcmd;
 
exit 0;

#=========================Reg==============================#

Syslog Configuration:

Syslog is a standard Unix utility for reporting system messages. Messages can be kept on the local system, or forwarded to central loghost machines. Many network devices such as routers and firewalls can utilize syslog as a reporting mechanism.
Messages are processed by the "syslod" daemon process, and are sent to the daemon process either through the logger system call, or through the "logger" command. Syslog configuration is generally controlled via the /etc/syslog.conf file.
Syslog configuration checklist:
  • Create an /etc/syslog.conf file with the desired syslog rules. If you are using a central syslog server, ensure that the rules on the server send the syslog output to the desired files.
  • Ensure that the destination file names are valid for the syslog.conf rules. Create empty files if needed.
  • Refresh the syslogd configuration by either sending a "SIGHUP" signal to the syslogd process, or by restarting the process.
  • Test the syslog configuration using the "logger" command.
  • Implement automatic log pruning and cleanup to prevent old syslog messages from filling up file systems.
There are several sources for Syslog daemons for Windows 95 and Windows NT. In addition, the "swatch" utility can be used to automatically filter syslog messages based on message content.

Syslog scripts

  • sample syslog.conf file
  • sample syslog.conf file for loghost client
  • logmaint - Script to periodically roll over to new syslog files. Can also be used to initially create syslog output files.
  • logdel - Deletes syslog files over the specified age.
  • logtest - Tests syslog configuration with the "logger" command by writing a test message to each facility for each priority.
Platforms supported: Most Unix flavors
#=========================Logmaint===========================#

#!/bin/sh
#
# This program rolls over old log files and creates new ones.
#
# The program loops through the list of files used by syslog, copies
# the old data to a date and time stamped file, then truncates the 
# active log file.
#
# This program supports one command line option "-compress" or "-nocompress",
# which controls whether or not the program compresses the archived log 
# file.  The default behavior is controlled by the COMPRESS variable at the
# start of the program.
#
# Andy Welter 9/23/98
# www.the-welters.com
#
COMPRESS="yes"
USAGE="logroll [-compress|-nocompress]"
LOGDIR=/var/adm/syslog
FILES="auth.log daemon.log kern.log user.log syslog.log local0.log messages" 
DATE=`date +"%y%m%d"`
 
case $1 in 
"-compress") COMPRESS=yes
        ;;
"-nocompress") COMPRESS=no
        ;;
*) echo $USAGE
        exit 1
        ;;
esac
 
for F in $FILES; do
        FF="${LOGDIR}/${F}"
        if [ -f $FF ]; then    
               while [ -f ${FF}.${DATE} ]; do
                       DATE=`date +"%y%m%d.%H%M%S"`
               done
               cp -p $FF $FF.$DATE
               chgrp adm $FF.$DATE
               chmod 660 $FF.$DATE
               if [ "$COMPRESS" = "yes" ]; then
                       /usr/bin/compress $FF.$DATE
               fi
        fi
        cat /dev/null > $FF
        chgrp adm $FF
        chmod 660 $FF
done
 
#=========================Logmaint===========================#

#===========================Logdel===========================#

#!/bin/sh
#
# This program deletes old syslog files
#
# Andy Welter
# www.the-welters.com
#
#
# TIMELIMIT is used to control how long a file is kept by the system.
# every time this script runs, it will delete files that are greater 
# than the specified number of days.
#
# TIMELIMIT must start with a "+" in order to function properly.
#
TIMELIMIT="+14"
LOGDIR=/var/adm/syslog
DATE=`date +"%y%m%d"`
if [ -d $LOGDIR ]; then
        find $LOGDIR -type f -name '*.log.*' -mtime $TIMELIMIT -exec rm {} \;
fi

#===========================Logdel===========================#

#===========================Logtest===========================#

#!/bin/sh
#
# This is a test of the "logger" and syslog configuration.
# It will loop through all the possible facillities and severity levels
# and send a syslog message for each one.
#
# Andy Welter 9/23/98
# www.the-welters.com
#
FACILITIES="auth daemon kern lpr mail news user syslog uucp local0"
SEV="debug info notice warn err crit alert emerg"
DATE=`date +"%D %T"`
 
for F in $FACILITIES; do
        for S in $SEV; do
               echo "$F.$S ..."
               logger -p$F.$S "syslog test $DATE $F.$S"
        done
done
 

#===========================Logtest===========================#

webcat and webload

Webcat is a perl program that takes URLs as input and fetches the specified web page. It can also be used to execute CGI Programs that use the GET method and URL encoding for their parms. When when given an URL on the command line, the script fetches a single web page. When no URL is specified on the command line, the program will read URLs from stdin, one URL per line.
The script does no parsing of the file returned and does not fetch images or URLs listed in frames.
Webload is a simple Bourne shell script that uses webcat in order to retrieve lists of URLs, and reports the amount of time needed to retrieve the page. Webload can save the files to a specified directory or send them to /dev/null. It can also loop through the list and download them repeatedly.
Click here to see webcat
Click here to see webload
Platforms supported: Most Unixs, requires perl5. webcat should work on NT with a good perl port.
#===========================Webcat===========================#

#!/usr/bin/perl 
#
# This script is a command line program for fetching web pages.
# It takes URLs as input and then connects to the specified web 
# server and retrieves the specified page using an HTTP/1.0 GET
# request.  It does not parse the resulting web page, and does
# not retrieve any associated images, included files, or source
# files for embedded frames.
#
# A single URL can be given on the command line, or the program
# will read URLs from stdin, one URL per line.
# 
#
# Andy Welter
# www.the-welters.com
# 9/1/1999
# 
use Socket;
if ( "$ARGV[0]" ne "" ) {
        $url="$ARGV[0]";
} else {
        $interactive=1;
        chop ($url = <STDIN>);
};
#
# quiet means don't print prompts and diagnostics
#
$quiet=1;
 
#
# Read std in and write it to the server
# Open a socket for each command
#
printf ("url: ") unless $quiet;
while ( $url ) {
$url=~s.http://..;
($host,$filename)=split /\//, $url, 2;
($host,$port)=split /:/,$host;
if ($port eq "") {
        $port=80;
};
$filename="/$filename";
 
printf ("set up socket to $host:$port\n") unless $quiet;
$sockaddr = 'S n a4 x8';
($name, $aliases, $proto) = getprotobyname('tcp');
($name, $aliases, $type, $len, $thisaddr) = gethostbyname($host);
$thisport = pack($sockaddr, &AF_INET, 0, $thisaddr);
$thatport = pack($sockaddr, &AF_INET, $port, $thisaddr);
 
 
        printf ("Opening socket...\n") unless $quiet;
        socket(S, &PF_INET, &SOCK_STREAM, $proto) ||
               die "cannot create socket\n";
               connect(S,$thatport) || die "cannot connect socket\n";
 
        # Set socket to write after each print
        select(S); $| = 1; select(STDOUT);
 
        #
        # Send command
        #
        printf ("Sending $filename") unless $quiet;
        print S "GET $filename HTTP/1.0\n\n";
        #
        # Read responses from server
        #
        while ( $_ = <S> ) {
               printf ("$_") unless $opt_n;
        };
        close(S);
        if ($interactive) {
               printf ("url: ") unless $quiet;
               chop ($url=<STDIN>);
               }
        else {
               $url="";
               };
};
 
 
exit 0;

#===========================Webcat===========================#

#===========================Webload==========================#
#!/bin/sh  
#
# Andy Welter
# www.the-welters.com
#
# This script uses the webcat program to download a list of URLs.
# It can be used to repeatadly download the list of files in order to 
# generate a steady traffic load on a web server, and can also save
# the resulting files in a directory.
#
# Options:
# -file <filename> 
#       The file name containing the list of URLS to retrieve.
# -delay <seconds> 
#       The number of seconds to pause between GET requests
#       by default, there is no delay between requests.
# -save <dirname> 
#       The name of an existing directory where the output will
#       be saved
# -loop <count> 
#       The number of times that the script will loop through the file list.  
#       The default is 1.  A negative number will cause an infinite loop.
# 
#
USAGE="webload -file <filename> [-loop <count>] [-save <dirname>] [-delay <seconds>]"
 
DELAY=0
LOOP=1
 
while [ $# -gt 1 ]; do
case $1 in 
-file|-f) URLS=$2
        ;;
-delay|-d) DELAY=$2
        ;;
-save|-s) SAVEDIR=$2
        ;;
-loop|-l) LOOP=$2
        ;;
*) echo $USAGE
        exit 1
        ;;
esac
shift 2
done
 
COUNT=0
echo $URLS
while [ $COUNT -ne $LOOP ]; do
        cat $URLS | while read URL; do
               echo $URL
               date
               if [ -n "$SAVEDIR" ]; then
                       FILE=`echo $URL | sed 's,[ /],.,g`
                       webcat $URL > $SAVEDIR/$FILE
               else
                       webcat $URL > /dev/null
               fi
               date
               echo ---------------------
        sleep $DELAY
        done
COUNT=`expr $COUNT + 1`
done
 
 

#===========================Webload==========================#





logroll

This script is used to manage log files on a system.  It will maintain a specified number of log file copies, renaming the old ones in a format "logfilename", "logfilename.0", "logfilename.1", with "logfilename.0" being the most recent archived log file.
Click here to see the script.
Platforms supported: Most Unixs.
#===========================logroll==========================#
#!/bin/ksh 
#
# Roll log files.
# This script will maintain a specified number of old log files,
# named by appending a number to the end of it, with the older
# files having higher numbers.  Numbering will start at zero.
#
# Andy Welter
# www.the-welters.com
# 1/4/2001
#
 
stat_check () {
RC=$1
MSG="$2" 
if [ "$RC" != "0" ]; then
        print "ERROR: $MSG"
        exit $RC
fi
}       
 
FILE=$1
if [ ! -f "$FILE" ]; then
        stat_check 1 "No such log file $FILE"
fi
        
if [ $# -eq 1 ]; then
        COUNT=6
else
        COUNT=`expr $2 - 1`
fi
 
CUR=$COUNT
 
while [ $COUNT -ge 1 ]; do
        NEXT=`expr $COUNT - 1`
        if [ -f $FILE.$COUNT ]; then
               rm $FILE.$COUNT
               stat_check $? "Removing $FILE.$COUNT"
        fi
        if [ -f $FILE.$NEXT ]; then
               mv $FILE.$NEXT $FILE.$COUNT
               stat_check $? "Moving $FILE.$NEXT"
        fi
        COUNT=`expr $COUNT - 1`
done
#
# Copy then truncate the active log file to avoid problems with
# open file descriptors 
cp -p $FILE $FILE.0
stat_check $? "Moving $FILE.$NEXT"
cat /dev/null > $FILE

#===========================logroll==========================#

format_clone

This script is used to copy the disk partitioning from one disk to another.  This does not copy any data, it simply replicates the partition layout as you could do using the "format" program.  This script comes in handy when setting up a batch of new disk drives, or when setting up disk mirroring using Solstice Disk Suite.
 NOTE: the source and destination disks must have the same geometry. (size, cylinders, sectors, etc).  This script does not check to see if the destination disk is in use, but it does save a backup copy of the old disk partitioning in /tmp/format.dat.<diskname>.bak.
Click here to see the script.
Platforms supported: Solaris 2.x.


#======================Format_closnel==========================#

#!/bin/sh
#
# Clone a disk format.  This can be useful when setting up
# a bunch of new disks, or when setting up a disk that will
# be a mirror of an existing disk.  
#
# NOTE:  This program assumes that the source and destination
# disk drives are the exact same make and model.
#
# Andy Welter
# www.the-welters.com
# 1/4/2001
#
SOURCE=$1
DEST=$2
echo "Copy format from $SOURCE to $DEST"
echo "Are you sure that $DEST is not in use? [y|n]"
read ANS
if [ "$ANS" != "y" ]; then
        echo "Exiting."
        exit 1
fi
 
if [ ! -h /dev/dsk/${SOURCE}s0 -a \
        ! -h /dev/dsk/${SOURCE}s0 ]; then
    echo "no such disk"
fi
FORMATDAT="/tmp/format.dat.$$"
FORMATBAK="/tmp/format.dat.$DEST.bak"
if [ -f $FORMATDAT -o \
        -f $FORMATBAK ]; then
        echo "$FORMATDAT or $FORMATBAK already exists"
        exit 1
fi
echo "Saving source format table..."
format $SOURCE << EOF > /dev/null 2>&1
save
$FORMATDAT
quit
EOF
 
#
# Get the disk type and partition table name from the file
DNAME=`grep "^disk_type" $FORMATDAT | cut -d'"' -f2`
PNAME=`grep "^partition" $FORMATDAT | cut -d'"' -f2`
 
#
# Save the old format table for the destination device
echo "Saving backup copy of $DEST format table in $FORMATBAK..."
format $DEST << EOF > /dev/null
save
$FORMATBAK
quit
EOF
 
#
# 
echo "Copy new format table to $DEST ..."
format -x $FORMATDAT -t $DNAME -p $PNAME $DEST << EOF > /dev/null 
label
y
quit
EOF
 
rm $FORMATDAT
echo "done."
#======================Format_closnel==========================#


inetd_cleanup

Most systems ship with an overly permissive inetd.conf file.  This eliminates services that are potential security hazards. There are more full fledged security tightening scripts than this such as the Bastille Linux project and Titan amongst others. But this is handy if all you want to do is sweep through a bunch of inetd.conf files.
Click hereto see the script.
Platforms supported: Most Unixs, but the service lists are Solaris oriented.




#======================inetd_cleanup==========================#

#!/bin/ksh
#
# Andy Welter
# www.the-welters.com
# 1/3/2001
# 
# This script is used to tighten up the security of a system's 
# inetd.conf file, which is used to control what services the inet daemon
# will start up on a system.
#
# Most Unix systems ship by default with some services that are better
# left disabled.  This script has 4 levels of tightening it can do:
# Default - Only the worst of the default services are turned off. 
#           Suitable for non-mission critical servers on a relatively 
#           trustworthy internal network.
# medium  - Slightly more restrictive, internal servers would be a good
#           candidate for this level.
# high    - Much more restrictive.  Used for systems that are exposed to the
#           internet either directly, or within a DMZ.  Web servers, ftp
#           servers, mail gateways, etc.
# max     - ???
#
# Usage:
USAGE='inetd_lockdown [-medium|-high|-max] [-install] [<inetd.conf filename>]'
#
 
 
#
# Check return codes, and exit if not zero.
rccheck () {
RC=$1
if [ $RC -ne 0 ]; then
        print "Error at $2"
        exit 1
fi
}
        
#
# Define services to disable for each level
# Services that have names are defined in the /etc/services file.  The services with numbers here
# are services that use remote procedure calls. (rpc).  Many rpc based services have a history 
# of buffer overrun security issues.
DEFLIST="comsat exec talk uucp tftp name finger systat netstat echo discard chargen rquotad walld rexed ruserd" 
MEDLIST="$DEFLIST shell login 100232 xaudio"
HIGHLIST="$MEDLIST rstatd printer kerbd ufsd timed dtspc 100068 100083 100235 100221 100229 100230"
MAXLIST="$HIGHLIST ftp"
LIST=$DEFLIST
FILE=/etc/inet/inetd.conf
 
while [ $# -ge 1 ]; do
    case $1 in 
        -medium) LIST=$MEDLIST
               ;;
        -hi|-high) LIST=$HIGHLIST
               ;;
        -m|-max) LIST=$MAXLIST
               ;;
        -i|-install) INSTALL="yes"
               ;;
        -v) VERBOSE="yes"
               ;;
        -*) print "$USAGE"
               exit 1
               ;;
        *) FILE=$1
               ;;
    esac
    shift
done
        
if [ ! -r $FILE ]; then
        print "ERROR: No such file or file unreadable - $FILE"
        exit 1
fi
 
if [ $VERBOSE ]; then
        print "Disabling the following services:"
        print "$LIST"
    if [ $INSTALL ]; then
        print "The new $FILE will be installed automatically"
    fi
fi
 
TMPFILE=$FILE.tmp
NEWFILE=$FILE.new
BAKFILE=`date +"$FILE.%y%m%d"`
cp $FILE $BAKFILE
rccheck $? "backup"
cp $FILE $TMPFILE
cp $FILE $NEWFILE
 
#
# Loop through the list of services and use sed to comment the service out
for SVC in $LIST; do
        sed "s/^$SVC/#&/" < $TMPFILE > $NEWFILE
        rccheck $? "sed"
        cp $NEWFILE $TMPFILE
        rccheck $? "cp"
done
rm $TMPFILE
 
 
#
# Install the new file and make inetd re-read it's config file
if [ "$INSTALL" = "yes" ]; then
        if [ $VERBOSE ]; then
               print "Installing file now..."
        fi
        if [ -w $FILE ]; then 
               cp $NEWFILE $FILE
               rccheck $? "install"
               PID=`ps -eaf -o pid -o comm | grep -w "inetd" |\
                        (read pid cmd; echo $pid)`
               kill -HUP $PID
        fi
fi
if [ $VERBOSE ]; then
        print "Difference between old and new files:"
        diff $NEWFILE $BAKFILE
fi

#======================inetd_cleanup==========================#


ping_scan

Sequentially ping a range of IP addresses. This script is not as efficient as using a program such as nmap, but it is a handy exercise for manipulating IP addresses in Perl.
Click here to see the script
Platforms supported: Most Unixs.

#======================ping_scan==============================#

#!/usr/local/bin/perl 
#
# This script will ping a range of IP addresses given
# a starting and ending address.  There are other faster
# ways to do this, for example, the nmap program, but this 
# is also an example on how to manipulate IP addresses in Perl.
#
# Andy Welter
# www.the-welters.com
# January 2001
#
 
use Socket;
$packet_count=1;
$usage="ping_scan <starting IP address> [ending ip address]\n";
($#ARGV >= 0) || die "$usage";
$cur_str=$ARGV[0];
if ($#ARGV == 0 ) {
        $end_str=$cur_str;
} else {
        $end_str=$ARGV[1];
};
#
# Convert "1.2.3.4" notation address into an integer.
$cur_bin= unpack "L", inet_aton $cur_str;
$end_bin= unpack "L", inet_aton $end_str;
 
while ( $cur_bin <= $end_bin ) {
        #
        # Convert integer into a 1.2.3.4 notation address.
        $cur_str=inet_ntoa (pack "L", $cur_bin);
        print "$cur_str ... ";
        #
        # Ping the host
        open (PING, "ping $cur_str $packet_count |") || 
               die "Cannot execute ping command\n";
        while ( $_ = <PING> ) {
               print $_;
        };
        close PING;
        $cur_bin++;
};

#======================ping_scan==============================#

hostbyaddr

This script does a reverse address lookup, returning a host name when given an IP address. It uses the gethostbyname function call, which means it will use whatever name resolution method the host running the program uses. This is meant to provide a more easily parsed format for output than nslookup provides, and is mostly useful inside other scripts.
Click here to see the script
Platforms supported: Unix and NT with a good Perl port
#======================hostbyaddr=============================#

#!/usr/local/bin/perl
#
# This script does a reverse address lookup, returning
# a host name when given an IP address.  It uses the 
# gethostbyaddr function call, which means it will use 
# whatever name resolution method the host running the 
# program uses.  This is meant to provide a more easily 
# parsed format for output than nslookup provides.
#
# Andy Welter
# www.the-welters.com
# January 16, 2001
#
use Socket;
$addr=$ARGV[0];
$hostname=gethostbyaddr(inet_aton ($addr), AF_INET);
if ( $hostname ) {
        print "$hostname\n";
} else {
        exit 1;
};

#======================hostbyaddr=============================#

hostbyname

When given an IP address, this script does a hostname lookup lookup. It uses the gethostbyaddr function call, which will use whatever name resolution method the host running the program uses. Like the previous script this is meant to provide a more easily parsed format for output than nslookup provides, and is mostly useful inside other scripts.
Click here to see the script
Platforms supported: Unix and NT with a good Perl port
#======================hostbyname=============================#
#!/usr/local/bin/perl
#
# Obtain an IP address for a host name
# The gethostbyname function uses whatever name service the system
# you run it on is configured to use.  For example, this may be 
# local hosts files, NIS, NIS+, or of course, DNS.
# 
# This output is meant to be easier to use than the information 
# returned by nslookup.
#
# Andy Welter
# www.the-welters.com
# January 16, 2001
# 
$host=$ARGV[0];
$addr=gethostbyname($host);
if ( $addr ) {
        ($a,$b,$c,$d)=unpack ('C4', $addr);
        print "$a.$b.$c.$d\n";
} else {
        exit 1;
};
#======================hostbyname=============================#

hostxcheck

When given an IP address or host name, this script will perform a forward and reverse look up using gethostbyaddr and gethostbyname. This is useful for verifying that reverse DNS entries have been set up correctly, or to make sure that an IP address does not have a spoofed reverse entry.
Click here to see the script
Platforms supported Unix and NT with a good Perl port.


#======================hostxcheck=============================#
#!/usr/local/bin/perl
#
# Cross check the a host name using forward and reverse DNS 
# lookups.  If the name passed in is a "cname" (aka alias), 
# then the second hostname returned will not match the first.
# That is ok.  The biggest thing to watch for is that the addresses
# match.
#
# The gethostbyname or gethostbyaddr functions use whatever name service 
# the system you run it on is configured to use.  For example, this may be 
# local hosts files, NIS, NIS+, or of course, DNS.
# 
# Andy Welter
# www.the-welters.com
# May 16, 2001
# 
 
use Socket;
#
# Get the address for the name passed in.  If someone 
# passed us an address, gethostbyname will return the address anyway.
$name1=$ARGV[0];
$addr1=gethostbyname($name1);
if ( $addr1 ) {
        ($a,$b,$c,$d)=unpack ('C4', $addr1);
        $addr1txt="$a.$b.$c.$d";
} else {
        die "Lookup failed for name1=$name1\n";
};
#
# Do a reverse look up to get the name that goes with this address
$name2=gethostbyaddr (inet_aton ($addr1txt), AF_INET);
if ( $name2 ) {
        $addr2=gethostbyname($name2);
} else {
        die "Lookup failed for addr1=$addr1txt\n";
};
#
# Now do a forward lookup on the address to get the name.
if ( $addr2 ) {
        ($a,$b,$c,$d)=unpack ('C4', $addr2);
        $addr2txt="$a.$b.$c.$d";
} else {
        die "Lookup failed for name2=$name2\n";
};
 
printf ("%-32s\t%s\n", "Hostname:","Address:");
printf ("%-32s\t%s\n%-32s\t%s\n", 
        $name1, $addr1txt, $name2, $addr2txt);

#======================hostxcheck=============================#


rc4

This program is an implementation of the "crypt" rc4 encryption program. It is a simple two way encryption program that can encrypt a file or data stream using a supplied key. When the same key and program are used on an encrypted file, it will decrypt the file.
Click here for the script
Platforms supported Unix and NT with Perl.
#===========================RC4============================#
#!/usr/bin/perl 
#
# A perl implementation of the "crypt" program.
#
# This program implements an rc4 encrytion algorythm 
# using a variable length key single piece key.
#
# It takes a file or data stream and encrypts it using the
# provided key.  Running the output of the program back
# through the program with the same key will decrypt it.
#
# USAGE: rc4 <keyval> [file name]
# If no file name is provided, the script will read from 
# STDIN.  
#
# Andy Welter
# www.the-welters.com
# May 2001
#
 
#
# Encrypt a buffer at a type.  Encryption is a stateful
# process, so we use the "@state" global variable to track
# the state.
sub rc4 {
my ($buf) = @_;
my ($ebuf, $char);
for(unpack('C*',$buf)) {
        $x++;
        $y=($state[$x%=256]+$y)%256;
        @state[$x,$y]=@state[$y,$x];
        #&swap;
        $char= pack (C, 
               $_^=$state[ ($state[$x] + $state[$y]) %256 ]);
        $ebuf= $ebuf . $char;
        };
return $ebuf;
};
 
sub prepkey {
#
# Prepare the encryption key
#
my @key=@_;
my @hexkey=unpack('C*',pack('H*',shift @key));
my ($x, $y);
my @t;
my @state;
#
# prepare key
for(@t=@state=0..255){
        $y=($hexkey[$_%@hexkey]+$state[$x=$_]+$y)%256;
        @state[$x,$y]=@state[$y,$x];
        #&swap;
}
return @state;
};
 
local @state=prepkey("$ARGV[0]");
my $x=0;
my $y=0;
my $file;
if ( $ARGV[1] eq "" ) {
        # If no file name was specified, 
        # use standard-in as the file name
        $file="<&=0";
} else {
        $file=$ARGV[1];
};
 
open (IN,"$file") || die "error: can not open $file";
while (read (IN,$buf, 1024)) {
        print rc4 ($buf);
};

#===========================RC4============================#

repack

This script uses the "/var/sadm/install/contents" file in Solaris to recreate a Solaris package file based on the currently installed files on the system. This can be useful as a way of making a backup of a Solaris package prior to removing it, or as a way to recreate a Solaris installation package when you no longer have the package file that it came in. It can also be useful as a way of creating a modified / customized package for installation on other systems. One could change file contents, ownerships, or permissions to suit their needs, repackage the files, and use that package for installation on other systems.
Click here for the script
Platforms Supported: Solaris 2.x
#==========================repack============================#
#!/bin/ksh
#
# Re-create a Solaris package installation file from it's installed 
# components.
#
# Andy Welter
# www.the-welters.com
#
# Limitations:
#   This script will only capture files that have entires in the 
#   /var/sadm/install/contents file.  It will not capture other files such
#   as config files that were added for the package later.  It will also 
#   not capture any pre or post install scripts that may have been used
#   when the package was originally installed.
# 
#   The file ownerships and permissions in the new package are will be the
#   same as the actual file ownerships and permissions, not what they were
#   when the file was originally installed.
#
DIR=/tmp
USAGE="repack <package name>"
if [ $# -lt 1 ]; then
        echo "$USAGE"
        exit 1
fi
PKG=$1
pkginfo $PKG
if [ $? -ne 0 ]; then
        echo "No such package $PKG."
        exit 1
fi
 
TMPDIR=$DIR/$PKG.$$
if [ ! -d $TMPDIR ]; then
        mkdir $TMPDIR
else
        echo "$TMPDIR already exists.  Exiting"
        exit 1
fi
cd $TMPDIR
echo "PKG=$PKG" > pkginfo
echo 'BASEDIR="/"' >> pkginfo
pkginfo -l $PKG | while read KEYWORD VALUE; do
        case $KEYWORD in 
        NAME:)
               # make sure the name reflects the fact that this
               # is a repackaged Solaris package.
               echo "NAME=$VALUE - repackaged" >> pkginfo
               ;;
        CATEGORY:)
               echo "CATEGORY=$VALUE" >> pkginfo
               ;;
        ARCH:)
               echo "ARCH=$VALUE" >> pkginfo
               ;;
        VERSION:)
               # make sure the version reflects the fact that this
               # is a repackaged Solaris package.
               echo "VERSION=$VALUE - repackaged" >> pkginfo
               ;;
        VENDOR:)
               echo "VENDOR=$VALUE" >> pkginfo
               ;;
        EMAIL:)
               echo "EMAIL=$VALUE" >> pkginfo
               ;;
        esac
done
 
echo "i pkginfo=./pkginfo" > prototype
grep $PKG /var/sadm/install/contents | cut -f1 -d" "| pkgproto >> prototype
 
if [ -d /var/spool/pkg/$PKG ]; then
        echo "Package already exists in /var/spool/pkg."
        echo "Do you want to over write this package? "
        read ANS
        if [ "$ANS" = "y" -o \
               "$ANS" = "yes" ]; then
               pkgmk -o -r /
        else
               echo "Ok, exiting"
               exit 1
        fi
else
        pkgmk -r / 
fi
cd /var/spool/pkg
rm -r $TMPDIR
echo "Do you want to turn the pkg directory into a single package file? "
read ANS
if [ "$ANS" = "y" -o \
        "$ANS" = "yes" ]; then
        pkgtrans -s /var/spool/pkg $PKG.pkg
        rm -r /var/spool/pkg/$PKG
fi
#==========================repack============================#

makePackage

This script creates a simple solaris package by interactively prompting for the basic values of a package. It assumes that you already have the files installed on the system in the proper location, with the desired ownerships and permissions.
Click here for the script
Platforms Supported: Solaris 2.x
#========================makepack============================#
#!/usr/bin/ksh
#
# This script creates a simple solaris package by interactively
# prompting for the basic values of a package.  It assumes that
# you already have the files installed on the system in the proper
# location, with the desired ownerships and permissions.
# 
# Andy Welter
# Version 1.0
# 2005
#
 
#
copyScript () {
        if [ "$2" = "" ]; then
               return
        elif [ -d $1 ]; then
               cp $1/$2 $TMPDIR
               print "i $2=./$2" >> prototype
        elif [ -f $1 ]; then
               cp $1 $TMPDIR/$2
               print "i $2=./$2" >> prototype
        else
               print "ERROR!  bad file name or path $1"
        fi
};
 
print "Creating pkginfo file..."
print "Enter values for solaris package variables: "
print -n "Package name (8 chars or less, no spaces [PKG]: "
read pkg
TMPDIR="/var/spool/pkg/$pkg.$$"
if [ -d $TMPDIR ]; then
        print "ERROR: $TMPDIR already exists"
        exit 1
else
        mkdir $TMPDIR
        cd $TMPDIR
fi
print "PKG=$pkg" > pkginfo
 
print -n "\t Package long name [NAME]: "
read name
print "NAME=$name" >> pkginfo
 
print -n "\t package CATEGORY: [ex. utility, application] "
read cat
print "CATEGORY=$cat" >> pkginfo
 
print "ARCH=sparc" >> pkginfo
 
print -n "\t VERSION: "
read version
print "VERSION=$version" >> pkginfo
 
print -n "\t VENDOR: "
read vendor
print "VENDOR=$vendor" >> pkginfo
 
#print -n "\t BASEDIR: "
#read basedir
basedir="/"
print "BASEDIR=$basedir" >> pkginfo
 
print "EMAIL=" >> pkginfo
 
print "Creating package prototype file..."
cat /dev/null > prototype
print "Solaris packages can run scripts at 3 points"
print "= a 'checkinstall' script for checking package dependencies"
print "= a 'preinstall' script that prepares a system for the installation of the files"
print "= a 'postinstall' script that runs after the other package files have been installed"
print "The files must be named checkinstall, preinstall, or postinstall."
print
print "Enter the FULL path name to any checkinstall script you wish to run (optional): "
read script
copyScript $script checkinstall
 
print "Enter the path name to any preinstall script you wish to run (optional): "
read script
copyScript $script preinstall
 
print "Enter the path name to any postinstall script you wish to run (optional): "
read script
copyScript $script postinstall
 
 
 
print -n "Enter the name of a file containing a list of the package files: "
read manifest
if [ -f "$manifest" ]; then
        print "i pkginfo=./pkginfo" >> prototype
        cat $manifest | pkgproto >> prototype
        
else
        print "ERROR: Must specify a file listing the contents of the package"
        exit 1
fi
if [ -d /var/spool/pkg/$pkg ]; then
        echo "Package already exists in /var/spool/pkg."
        echo "Do you want to over write this package? "
        read ANS
        if [ "$ANS" = "y" -o \
               "$ANS" = "yes" ]; then
               pkgmk -o -r /
        else
               echo "Ok, exiting"
               exit 1
        fi
else
        pkgmk -r / 
fi
 
cd /var/spool/pkg
rm -r $TMPDIR
echo "Do you want to turn the pkg directory into a single package file? "
read ANS
if [ "$ANS" = "y" -o \
        "$ANS" = "yes" ]; then
        pkgtrans -s /var/spool/pkg $pkg.pkg
        rm -r /var/spool/pkg/$pkg
fi
 

#========================makepack============================#

sh_ex

This script doesn't do anything...  It is just a file with examples of Bourne shell script syntax.  It can be handy if you don't write in sh often and want your memory jogged, or if you can never remember what test operator checks to see if a file is a symbolic link or not.
Click here to see the script.
Platforms supported: generic Bourne shell script syntax.

#========================sh_ex============================#
#!/bin/ksh
 
#
# Some script syntax examples:
 
#
# reading output from one program to use in a variable
ps -eaf | grep httpd | while read USER PID PPID THEREST; do
        grep "error: $PID" /var/adm/somelogfile
done
 
#
# The problem with the previous example is that you can't do
# something with standard out in the middle of the loop, since 
# you are already using standard out.   Another way to do it is this:
ps -eaf | grep httpd | while read USER PID PPID THEREST; do
        PIDLIST="$PIDLIST $PID"
done
for CURPID in $PIDLIST; do
        grep "error: $PID" /var/adm/somelogfile >> /tmp/someotherlog
done
 
#
# You can also format the output of "ps" the way you want using the 
# "-o" option.
ps -eaf -o pid -o comm | grep "httpd" | while read PID CMD; do
        kill $PID
done
 
#
# You can also use program output this way:
# Suppose you want to see what the permissions and ownerships were on some
# command that was in your path:      
ls -al `which su`
 
#
# Or suppose you wanted to save a date/time stamp so that you could use 
# it multiple times:
DTIME=`date +"%m%d%y.%H%M"`
mv log1 log1.$DTIME
mv log2 log2.$DTIME
 
#
# Some examples of the "test" operation:
# -r  file exists and is readable
# -w  file exists and is writable
# -x file exists and is executable
# -f  file exists and is a regular file. (not a dir)
# -d  file is a directory
# -h  file is a symbolic link
# -c  file is a character special file
# -b  block special file
# -p  named pipe
# -u  setuid file
# -g  setgid file
# -k  sticky bit set
# -s  file exists and has a size greater than 0
# -z  test for zero len string
# -n  non-zero length string
#
# Numeric test operators:
# -lt less than
# -le less than or equal to
# -gt greater than
# -ge greater than or equal to
# -eq equal to
# -ne not equal to
#
# String test operators
# = equal
# != not equal
# > greater than
# < less than
# 
# boolean operators
# -a and
# -o or
# ! not
#
if [ -f /tmp/myfile ]; then
        cat /tmp/myfile
fi
 
#
# elif structure
if [ ! -f $FILE ]; then        
        echo "No such file $FILE"
elif [ ! -r $FILE ]; then
        echo "$FILE not readable"
else 
        echo "File is readable"
fi
 
 
#
# Processing command line options:
while [ $# -ge 2 ]; do
        case $1 in 
        -f) FILE=$2
               shift 2
               ;;
        -d) DEVICE=$2
               shift 2
               ;;
        *) echo "usage: $0 [-f <filename>] [-d <device name>]"
               exit 1
               ;;
        esac
done
 
#
# This is an example of of subroutine definition and call
hup_daemon () {
DAEMON="$1"
ps -e -o pid,comm | grep "$DAEMON" | while read PID COMM; do
        echo "send HUP to $PID $COMM"
        kill -HUP $PID
done
};
 
hup_daemon inetd
 
# Writing data to syslog
/usr/local/bin/someCommand > /var/adm/someCommand.log
if [ $? -eq 0 ]; then
        logger -p user.notice "NOTE:  someCommand worked just fine"
else
        logger -p user.err "ERROR: someCommand had a problem"
fi
 
#sending a file as an attachment in email
uuencode /var/adm/someCommand.log someCommand.log | mailx -s "Log file from
someCommand" someUser@somedomain.com

#========================sh_ex============================#

perl_ex

This script doesn't do anything...  It is just a file with examples of simple Perl syntax.  It can be handy if you don't write in perl often and want your memory jogged.
Click here to see the script.
Platforms supported: generic Perl syntax. 
#========================perl_ex============================#
#!/usr/bin/perl
 
###########################################################################
# This is an example Perl script that doesn't do that much.  It is mostly an 
# example of Perl syntax.  The last part of the example is a basic web 
# server log analysis program.
###########################################################################
 
 
###########################################################################
# Types of variables
###########################################################################
#
# Scalar variables always start with a "$" whether they are on the left or
# right hand side of an expression.  This differs from bourne, korn, 
# and C-shell scripts.
$logDir="/var/log/httpd";
$logFile="$logDir/access_log";
 
#
# arrays 
# Arrays can be referenced two ways, in an array "context", or in a 
# scalar "context".  In an array context, the array name starts with 
# a %.  When referenced with a $, the value of the array is evaluated
# as a scalar value.  Arrays are referenced as scalars when you are 
# accessing a single element of the array by its subscript.   When the
# name of the array is referenced with an $ and no subscript, the 
# value of the expression is the length of the array.
%months=("", "January", "February", "March", "April", "May", "June", 
        "July", "August", "September", "October", "November", "December");
$mar=$months[3];
$monthCount=$months -1;
 
#
# Hashes or associative arrays
# One of the most useful innovations in Perl.  An associative array
# is like an array where the index is a string rather than an integer.
# When referenced with a @, the variable is an array.  When used with 
# a $ and a subscript, you get the value of the array element.  Without
# the subscript, you get the 
%namesAndNicknames ("Andrew", "Andy", "William", "Bill", "James", Jim");
$nickname=$namesAndNicknames {"Andrew");
$namesAndNicknames {"William"} = "Billy Bob";
#
# Get a list of hash keys
@names=keys (%namesAndNicknames);
#
# Get a list of the values in the hash
@values=values (%namesAndNicknames);
 
###########################################################################
# A subroutine definition and call
###########################################################################
sub isEqual {
my ($parm1, $parm2) = @_;
if ( $parm1 eq $parm2) {
        return 1;
} else {
        return 0;
};
};
 
$rc=isEqual ("abc", "def");
 
 
###########################################################################
# Simple control structures
###########################################################################
if ( $nickname eq "Billy Bob" ) {
        nascarfan("true");
} elsif ( $nickname eq "Nigel" ) {
        f1fan("true");
};
 
$length = @names;
for ($ii=0; $ii < $length; $ii++) {
        print ("$names [$ii] aka $namesAndNicknames{$names [$ii]} \n");
};
 
foreach $name (@names) {
        printf ("%s aka %s \n", 
               $name, $namesAndNicknames {$name});
};
 
#
# open a file for output, read from standard in, and write it to the outfile.
open (OUTFILE, "> /var/tmp/junk");
while ( $_ = <>) {
        print (OUTFILE "$_");
};
 
#
# The first parm in the open command is the file handle name, File handles
# have odd syntax... they do not have any special character in front of them
# such as $, %, or &.  
open (LOG,"<$logFile") || die "error: can not open $LOG";
#
# split the lines of the log file.  Ex.
# host.someisp.net - someuserid [01/Jan/1998:08:30:15 -0500] "GET /~welter/index.html HTTP/1.1" 304 -
while (<LOG>) {
        ($host,$junk,$userid,$date,$time,$request,$url,$protocol,$junk2) = 
               split (/\s+/);
        if (($url =~ /welter/) && !($url =~ /jpg/)) {
               $urls {"$url"} ++;
               $hosts {"$host"} ++;
               $dates {"$date"} ++; 
        };
};
 
print "URL Requests by host.\n";
while (($key ,$count) = each %hosts) {
        print "$count\t$key\n";
};
 
print "\nURL Requests by URL.\n";
while (($key ,$count) = each %urls) {
        print "$count\t$key\n";
};
 
# sort some hash by value
@sorted = sort { $hash{$a} cmp $hash{$b} } keys %hash; 
for $key (@sorted) {
        print $hash{$key}\n;
done
 

#========================perl_ex============================#

No comments:

Post a Comment