#!/bin/sh

# up2datecd.sh
#  Can be used to keep linux distribution ISO's current with
#  published security updates and bugfixes.  Originally written
#  for RedHat ISO's, it should not be hard to extend and modify.
#

# Set up some variables and stuff.

# First, the RedHat names and stuff
DISTRO="psyche-i386"
DISTROV="8.0"

# Then, the paths and stuff
STARTPWD=`pwd`
ISODIR=$STARTPWD/iso
UPDDIR=$STARTPWD/updates
MOUNTPOINT=$STARTPWD/mnt
# Now STARTPWD, ISODIR, UPDDIR, and MOUNTPOINT are absolute paths

# Set some color info.  See console_codes(4)
TBLUE="\033[1;34m"
TCYAN="\033[1;36m"
TYELLOW="\033[1;33m"
TGREEN="\033[1;32m"
TRED="\033[1;31m"
TNORM="\033[0m"

# Long RPM query
QUERY="%{NAME} %{VERSION} %{RELEASE} %{ARCH}"

# Now unalias inconvenient problem children
unalias -a

#
# Check for external program
#
function fextcheck()
{
   t=`which $1 2>/dev/null`
   if [ $? != 0 ] ; then
      echo -e "${TRED}Can't find $1 in your path!${TNORM}" 
      failure
   fi
}

#
# Define some functions to perform common tasks with error checking
#
function fmkdir() 
{
   mkdir -p $@ 2>/dev/null
   if [ ! -d $@ ] ; then
      echo
      echo -e "${TRED}Creation of directory $@ failed!${TNORM}" 
      failure
   fi
}

function fcp()
{
   SRC=$1
   DEST=$2
   if [ -e $DEST/`basename $SRC` ] ; then
      echo -e "${TYELLOW}Warning: $DEST/`basename $SRC` exists!${TNORM}"
      rm -rf $DEST/`basename $SRC` 2>/dev/null
      if [ -e $DEST/`basename $SRC` ] ; then
         echo -e "${TRED}And I can't delete it!${TNORM}"
         failure
      fi
   fi
   cp -r $SRC $DEST
   if [ ! -e $DEST/`basename $SRC` ] ; then
      echo 
      echo -e "${TRED}Copying `basename $SRC` to $DEST failed${TNORM}"
      failure
   fi
}

function failure()
{
   echo -e "${TRED}Critical failure!${TNORM}"
   cd $STARTPWD
   umount $MOUNTPOINT 2>/dev/null
   rm -rf $ISODIR 2>/dev/null
   exit 1
}

function success()
{
   echo -e "${TGREEN}... OK.${TNORM}"
}

#
# Function to update the CD numbered $1
#
function fupdate()
{
   #
   # Create an empty ISO directory
   #
   echo -n -e "${TCYAN}Creating working directory ${TNORM}"
   rm -rf $ISODIR 2>/dev/null
   fmkdir $ISODIR
   success

   #
   # Next, we create a mount point
   #
   grep -s -q $MOUNTPOINT /proc/mounts
   if [ $? == 0 ] ; then
      umount $MOUNTPOINT 2>/dev/null
   fi
   grep -s -q $MOUNTPOINT /proc/mounts
   if [ $? == 0 ] ; then
      echo 
      echo -e "${TRED}We're screwed!"
      echo "...There's already a mount on $MOUNTPOINT"
      echo -e "...and I can't umount it.${TNORM}"
      failure
   fi
   fmkdir $MOUNTPOINT

# mount the iso
   mount $DISTRO-disc$1.iso $MOUNTPOINT -o loop
   if [ $? != 0 ] ; then
      echo
      echo -e "${TRED}Unable to mount the iso!${TNORM}"
      failure
   fi

# copy the iso to the iso directory
   echo -n -e "${TCYAN}Copying iso #$1 for updates ${TNORM}"
   cp -ar $MOUNTPOINT/* $ISODIR
   if [ $? != 0 ] ; then
      echo -e "${TRED}Couldn't copy the ISO!${TNORM}"
      failure
   else
      success
   fi
   
# unmount the iso
   umount $MOUNTPOINT
   if [ $? != 0 ] ; then
      echo
      echo -e "${TRED}Unable to unmount the iso!${TNORM}"
      failure
   fi

# iterate through the rpm's, checking for updates on each
   echo -e "${TCYAN}Scanning for updated rpms ${TNORM}"
   for r in $ISODIR/RedHat/RPMS/*rpm ; do
      rpm=`basename $r`
      t=`rpm -qp $r --queryformat "$QUERY"`
      NAME=`echo $t | cut -f1 -d' '`
      VERSION=`echo $t | cut -f2 -d' '`
      RELEASE=`echo $t | cut -f3 -d' '`
      ARCH=`echo $t | cut -f4 -d' '`
      CANDIDATES=`/bin/ls $UPDDIR/$ARCH/$NAME-*-*.$ARCH.rpm 2>/dev/null`
      if [ $? == 0 ] ; then
         UPDLIST=$VERSION-$RELEASE
         for c in $CANDIDATES ; do
            t=`rpm -qp $c --queryformat "%{NAME} %{VERSION} %{RELEASE}"`
            N=`echo $t | cut -f1 -d' '`
            V=`echo $t | cut -f2 -d' '`
            R=`echo $t | cut -f3 -d' '`
            if [ "$N" == "$NAME" ] ; then
               bc=`basename $c`
               UPDLIST="$UPDLIST\012$V-$R"
            fi
         done
         MOSTRECENT=`echo -e $UPDLIST | sort -rn - | head -n 1`
         RPMU=$NAME-$MOSTRECENT.$ARCH.rpm
         echo -e "$rpm ==> $RPMU"
         t="$UPDDIR/$ARCH/$RPMU"
         if [ -e "$t" ] ; then
            fcp $t $ISODIR/RedHat/RPMS
            rm -f $ISODIR/RedHat/RPMS/$rpm
         else
            echo -e "${TYELLOW}Possible algorithm flaw!"
            echo -e "Please report this to the TACLUG mailing list"
            echo -e "${TNORM}"
         fi
      fi
   done
   success
}

function fmake_bootable()
{
   echo -e "${TCYAN}Creating Bootable CD${TNORM}"

#
#  Run genhdlist
#
   echo -e "${TCYAN}Generating hdlists${TNORM}"
   fmkdir iso2
   mount $DTG-$DISTRO-disc2.iso iso2 -t iso9660 -o loop || failure
   ./genhdlist --withnumbers --hdlist hdlist $ISODIR $STARTPWD/iso2
   rm -f $ISODIR/RedHat/base/hdlist $ISODIR/RedHat/base/hdlist2
   fcp $STARTPWD/hdlist $ISODIR/RedHat/base
   fcp $STARTPWD/hdlist2 $ISODIR/RedHat/base 
   umount iso2
   rmdir iso2
   success

   echo -e "${TCYAN}Making iso image${TNORM}"

   mkisofs -o $STARTPWD/$DTG-$DISTRO-disc$1.iso \
           -b isolinux/isolinux.bin \
           -c isolinux/boot.cat \
           -no-emul-boot \
           -boot-load-size 4 \
           -boot-info-table \
           -A "TACLUG auto-updated RedHat $DISTROV generated $DTG" \
           -p "TACLUG up2datecd script" \
           -R -J -U -quiet\
           $ISODIR

   if [ $? != 0 ] ; then
      echo -e "${TRED}Failed to mkisoofs!${TNORM}"
      failure
   fi

   echo -e "${TCYAN}Implant the md5 checksum${TNORM}"
   ./implantisomd5 --supported-iso --force $STARTPWD/$DTG-$DISTRO-disc1.iso
   success
}

function fmake_normal()
{
   echo -e "${TCYAN}Creating iso image${TNORM}"
   mkisofs -o $STARTPWD/$DTG-$DISTRO-disc$1.iso \
           -A "TACLUG auto-updated RedHat $DISTROV" \
           -p "TACLUG up2datecd script" \
           -R -U -J -quiet\
           $ISODIR

   if [ $? != 0 ] ; then
      echo -e "${TRED}Failed to mkisofs!${TNORM}"
      failure
   fi
   echo -e "${TCYAN}Implant md5 checksum${TNORM}"
   ./implantisomd5 --supported-iso --force $STARTPWD/$DTG-$DISTRO-disc$1.iso
   success
}

# This is where we start.....
#

#
# First, perform paranoid check for external program availability
#
for prog in cp echo grep ls mkdir mkisofs mount rm rsync umount; do
   fextcheck $prog
done

#
# We should only run this as root, since we need to mount
#
if [ $UID != 0 ] ; then
   echo -e "${TYELLOW}Only root should try to run this script${TNORM}"
   exit 1
fi

#
# Now check for genhdlist and implantisomd5
#
echo -n -e "${TCYAN}Do we have anaconda bins?  ${TNORM}"
if [ ! -x ./genhdlist ] ; then
   mkdir -p foo
   mount $STARTPWD/$DISTRO-disc2.iso foo -t iso9660 -o loop
   t=foo/RedHat/RPMS/anaconda-runtime*rpm
   rpm2cpio $t  | cpio -id *genhdlist *implantisomd5  2>/dev/null 
   mv usr/lib/anaconda-runtime/* .
   rmdir -p usr/lib/anaconda-runtime
   umount foo
   rmdir foo
fi

if [ ! -x ./implantisomd5 ] ; then
   mkdir -p foo
   mount $STARTPWD/$DISTRO-disc2.iso foo -t iso9660 -o loop
   t=foo/RedHat/RPMS/anaconda-runtime*rpm
   rpm2cpio $t 2>/dev/null  | cpio -id *genhdlist *implantisomd5  2>/dev/null 
   mv usr/lib/anaconda-runtime/* .
   rmdir -p usr/lib/anaconda-runtime
   umount foo
   rmdir foo
fi

if [ -x ./genhdlist ]  && [ -x ./implantisomd5 ] ; then
   success
else
   failure
fi



#
# Next step is to create the updates directory
#
echo -n -e "${TCYAN}Verifying \"updates\" exists ${TNORM}"
fmkdir $UPDDIR
success

  
#
# You can perform the mirroring using any method you like and the server
# supports, such as the various "mirror" commands, rsync, or wget.  We use
# rsync, since this particular mirror supports its use.

MIRROR=ftp.rpmfind.net
MIRRORPATH=linux/redhat/updates/$DISTROV/en/os/
MIRROROPTS='-avz --delete --exclude *src.rpm'

echo -n -e "${TCYAN}(Slowly) Mirroring updates ${TNORM}"

rsync $MIRROROPTS rsync://$MIRROR/$MIRRORPATH $UPDDIR >> rsync.log 2>&1
if [ $? != 0 ] ; then
   echo 
   echo -e "${TRED}Mirroring failed for some reason!"
   failure
fi
success

#
# Bugfixes and security updates are now all mirrored to $UPDDIR
# We can start updating CD's.
#
DTG=`date +%Y%m%d`
for i in 3 2 1 ; do
   fupdate $i
   if [ "$i" == "1" ] ; then
      fmake_bootable $i
   else
      fmake_normal $i
   fi
done

echo -e "${TCYAN}Performing cleanup${TNORM}"
rm -rf $ISODIR
rmdir mnt
echo -e "${TGREEN} Done! ${TNORM}"
exit 0



