#!/bin/bash
#
# Script for completely patching a system and sending success or failure
# email.

# print help and exit
function printhelp () {
    pod2text $0
    exit $1
}

# send success email
# semail(toemail, contents)
function semail () {
    echo "$2" | mail -s "Success updating `hostname -s`" "$1"
}

# send failure email
# femail(toemail, contents)
function femail () {
    echo "$2" | mail -s "Failure updating `hostname -s`" "$1"
}

# update packages
# updatepackages(results,success,failure,reboot)
function updatepackages() {
    results=$1
    successto=$2
    failto=$3
    reboot=$4
    if [ -f /etc/redhat-release ]; then
        if [ -f /usr/sbin/up2date ]; then
            pkgmgr=up2date
            /usr/sbin/up2date -uf 2>&1 >> $results
            rc=$?
        elif [ -f /usr/bin/yum ]; then
            pkgmgr=yum
            /usr/bin/yum clean all 2>&1 > /dev/null
            /usr/bin/yum -y update 2>&1 >> $results
            rc=$?
        else
            echo "Could not find RHEL package manager. Exiting..." >&2
            exit 2;
        fi
    elif [ -f /etc/debian_version ]; then
        pkgmgr=aptitude
        /usr/bin/aptitude update 2>&1 > /dev/null
        # stop puppet
        /etc/init.d/puppet stop 2>&1 >> $results
        /usr/bin/aptitude -y -o DPkg::Options::=--force-confdef dist-upgrade 2>&1 >> $results
        rc=$?
    else
        echo "Unknown OS. Exiting..." >&2
        exit 2;
    fi
    
    echo >> $results
    echo >> $results
    echo "return code: $rc" >> $results
    
    # Can we trust the return code from aptitude and up2date?
    # I've seen some inconsistent behavior in my tests...
    if `echo $pkgmgr | egrep -q "aptitude|up2date"`; then
        if [ "$rc" -eq 0 ]; then
            semail "$successto" "`cat $results`"
            if [ "$reboot" != "" ]; then /sbin/shutdown -r "$reboot"; fi
        else 
            femail "$failto" "See $results on `hostname -s` for the error(s). Return code was: $rc"
            exit $rc
        fi
    # yum doesn't exit with useful return codes most of the time
    elif `echo $pkgmgr | grep -q "yum"`; then
        if `egrep -q '^Complete!$' $results`; then
            semail "$successto" "`cat $results`"
            if [ "$reboot" != "" ]; then /sbin/shutdown -r "$reboot"; fi
        else
            femail "$failto" "See $results on `hostname -s` for the error(s). Return code was: $rc"
            exit $rc
        fi
    else 
        echo "Unknown package manager. Exiting..." >&2
        exit 2;
    fi
}


#################
# main program
#################

while getopts ":hnr:f:s:" Option
do
    case $Option in
        f ) 
            failto=${OPTARG} 
            ;;
        s ) 
            successto=${OPTARG} 
            ;;
        r ) 
            reboot=${OPTARG}
            ;;
        h ) 
            printhelp 0 
            ;;
        * ) 
            echo "Invalid option." >&2 
            printhelp 2 
            ;;
    esac
done

shift $(($OPTIND - 1))

if [ -z $failto ]; then
    echo "You must provide the failure email address option -f" >&2
    exit 2;
fi

if [ -z $successto ]; then
    echo "You must provide the success email address option -s" >&2
    exit 2;
fi

### main program ###
results=`mktemp`

# update packages
updatepackages $results $successto $failto $reboot
exit

# Documentation.  Use a hack to hide this from the shell.  Because of the
# above exit line, this should never be executed.
DOCS=<<__END_OF_DOCS__

=for stopwords
SMS

=head1 NAME 

patch-system - Patch system completely and email success or failure

=head1 SYNOPSIS

B<patch-system> B<-s> I<success-address> B<-f> I<fail-address>
    [B<-r> I<time>]

=head1 DESCRIPTION

B<patch-system> completely patches a system and emails success or failure.
Optionally, it can also reboot the system after the specified time period.

This script was designed to be used in an automated fashion with B<at> so
that patching can be completed at a particular time.

=head1 OPTIONS

=over 4

=item B<-f> I<fail-address>

Email address to send a possible failure to.  This will normally be a SMS
address to send a page on failure.

=item B<-h>

Print help and exit.

=item B<-r> I<time>

Optional argument to reboot the system after the time period specified.
I<time> is passed as the argument to C<shutdown -r>, so can take any of
the forms supported by that command.

=item B<-s> I<success-address>

Email address to which to send success report.

=back

=head1 AUTHOR

Darren Patterson <darrenp1@stanford.edu>

=cut

__END_OF_DOCS__
