#!/bin/bash # Script to run daily update of Scientific Linux Linux system using yum # (handles multiple SLC releases) # # Thu Feb 6 10:19:57 CET 2014 Jaroslaw.Polok@cern.ch # # ---------- DO NOT MODIFY THIS FILE -------------------------------- # ---------- change settings in /etc/sysconfig/yum-autoupdate --- # ---------- enable/disable with: --- # ---------- /sbin/chkconfig --add | --del yum-autoupdate --- # ---------- /sbin/service yum-autoupdate start | stop --- # ------------------------------------------------------------------- PATH=/bin:/usr/bin YUMVERSION=4 # sets global variables, use them before the next call to this function get_version () { # FIXME(fuji): cannot handle packages with dashes in their name #_VER=$( rpm -q "$1" | sed -nr 's/[^-]+-([^-]+)-.*$/\1/p' ) # why so complicated ? _VER=$( rpm -q "$1" --queryformat "%{VERSION}" 2>/dev/null ) [ $? -ne 0 ] && _VER="0.0"; _MAJ="${_VER%%.*}" # strip off everything after first dot _MIN="${_VER##${_MAJ}.}" # strip off major *and* dot _MIN="${_MIN%%.*}" # strip any further subversions _VER=${_VER:-0} _MAJ=${_MAJ:-0} _MIN=${_MIN:-0} } init_nc_args () { # is it el7 ? get_version nmap-ncat if [ -z "${_MAJ}" -o -z "${_MIN}" -o "${_MAJ}" -ge 6 ]; then NC_CHECKNETWORK_ARGS="-w5 -e /bin/echo" NC_REMLOG_ARGS="-w5" return fi # default assumes SLC4 NC_REMLOG_ARGS="-w 5" NC_CHECKNETWORK_ARGS="-zw 5" # check for version >= 1.84 get_version nc if [ -z "${_MAJ}" -o -z "${_MIN}" -o "${_MAJ}" -lt 1 ]; then return fi if [ "${_MAJ}" = 1 -a "${_MIN}" -lt 84 ]; then return fi # if we reach this, assume SLC5 NC_REMLOG_ARGS="-4w 5" NC_CHECKNETWORK_ARGS="-d4zw 5" } init_yum_args () { # default assumes SLC4 YUMARGS="-y" # check for version >= 3.2.x get_version yum if [ -z "${_MAJ}" -o -z "${_MIN}" -o "${_MAJ}" -lt 3 ]; then return fi if [ "${_MAJ}" = 3 -a "${_MIN}" -lt 2 ]; then return fi # if we reach this, assume SLC5 YUMARGS="-y --skip-broken" # for 5 and 6 we check secupdates [ $YUMUPDATESECONLY -eq 1 ] && YUMARGS="$YUMARGS --security" } init() { if [ -r /etc/sysconfig/yum-autoupdate ]; then . /etc/sysconfig/yum-autoupdate fi [ -z "$YUMAPPLET" ] && YUMAPPLET=4 [ -z "$YUMHOUR" ] && YUMHOUR=4 [ -z "$YUMMAILTO" ] && YUMMAILTO="root" [ -z "$YUMMAIL" ] && YUMMAIL=1 [ -z "$YUMUPDATE" ] && YUMUPDATE=1 [ -z "$YUMRANDOMWAIT" ] && YUMRANDOMWAIT=30 [ -z "$YUMCLEAN" ] && YUMCLEAN=1 [ -z "$YUMINTERACTIVE" ] && YUMINTERACTIVE=1 [ -z "$YUMLOGFILE" ] && YUMLOGFILE="/var/log/yum-autoupdate.log" [ -z "$YUMSAYYES" ] && YUMSAYYES=0 [ -z "$YUMONBOOT" ] && YUMONBOOT=1 [ -z "$YUMBOOTRUN" ] && YUMBOOTRUN=0 [ -z "$YUMMAINSERVER" ] && YUMMAINSERVER="linuxsoft.cern.ch" [ -z "$YUMDEFARCH" ] && YUMDEFARCH=`/bin/uname -m` [ -z "$YUMLOGSERVER" ] && YUMLOGSERVER=$YUMMAINSERVER [ -z "$YUMREMOTELOG" ] && YUMREMOTELOG=1 [ -z "$YUMUPDATESECONLY" ] && YUMUPDATESECONLY=0 [ -z "$YUMUPDATEMETHOD" ] && YUMUPDATEMETHOD="update" DATE="$(/bin/date)" HOUR="$(/bin/date +%H)" TEMPFILE=`/bin/mktemp /tmp/$$.XXXXXXXX` TEMPFILE2=`/bin/mktemp /tmp/$$.XXXXXXXX` TEMPMAIL=`/bin/mktemp /tmp/$$.XXXXXXXX` TEMPCODE=`/bin/mktemp /tmp/$$.XXXXXXXX` YUMLOCKFILE="/var/lock/subsys/yum-autoupdate" YUMCONFFILE="/etc/sysconfig/yum-autoupdate" YUM="/usr/bin/yum" init_nc_args init_yum_args YUMRANDOMWAIT=$(( $YUMRANDOMWAIT %60 )) [ $(( ($YUMHOUR +1) %24 )) -eq 0 ] && HOUR2=25 || HOUR2=$(( ($YUMHOUR +1) %24 )) [ $HOUR -ge $(( $YUMHOUR %24 )) ] && [ $HOUR -lt $HOUR2 ] && GOAHEAD=1 || GOAHEAD=0 [ $YUMBOOTRUN -eq 1 ] && [ $YUMONBOOT -eq 1 ] && GOAHEAD=1 } log() { [ $YUMINTERACTIVE -eq 1 ] && echo $1 [ $YUMBOOTRUN -eq 1 ] && echo " $1" [ $YUMINTERACTIVE -eq 0 ] && echo $1 >> $YUMLOGFILE } remlog() { REMLOGHEAD1="GET /_remlog_?" REMLOGHEAD2=" HTTP/1.1\r\nHost: $YUMLOGSERVER\r\nConnection: close\r\n\r\n" REMLOGMSG="YUM|$1|$2" [ $YUMBOOTRUN -eq 1 ] && REMLOGMSG="$REMLOGMSG|BOOT" || REMLOGMSG="$REMLOGMSG|AUTO" [ -x /bin/uname ] && REMLOGMSG="$REMLOGMSG|`/bin/uname -n`|`/bin/uname -r`|`/bin/uname -i`" || REMLOGMSG="$REMLOGMSG|Unknown|Unknown|Unknown" REMLOGMSG=${REMLOGMSG// /_} echo -ne "${REMLOGHEAD1}${REMLOGMSG}${REMLOGHEAD2}" | /usr/bin/nc "$NC_REMLOG_ARGS" $YUMLOGSERVER 80 2>&1 >> /dev/null } out() { /bin/rm -f $TEMPFILE /bin/rm -f $TEMPFILE2 /bin/rm -f $TEMPCODE /bin/rm -f $TEMPMAIL exit $1 } count_changes () { local i local u local r i=$( /bin/sed -nr 's/^Install[[:space:]]+([0-9]+).Package.s.*$/\1/p' "$1" ) u=$( /bin/sed -nr 's/^(Update|Upgrade)[[:space:]]+([0-9]+).Package.s.*$/\2/p' "$1" ) r=$( /bin/sed -nr 's/^Remove[[:space:]]+([0-9]+).Package.s.*$/\1/p' "$1" ) i=${i:-0} u=${u:-0} r=${r:-0} CHANGES=$(($i+$u+$r)) } # NOTE(fuji): Unfortunately yum check-update does not have detailed # Install/Update/Remove counters so for the time being count the lines where # package modifications are listed with the architecture appended. count_changed_packages () { CHANGES=$( /bin/egrep -c "\.(noarch|i([356]86|a(32e|64))|athlon|x86_64)" "$1" ) } randomsleep() { [ $YUMRANDOMWAIT -eq 0 ] && return SLEEPTIME=$(( ( $RANDOM % $YUMRANDOMWAIT ) * 60 )) log "sleeping for $SLEEPTIME seconds" /bin/sleep $SLEEPTIME } checknetwork() { /usr/bin/nc ${NC_CHECKNETWORK_ARGS} "$YUMMAINSERVER" 80 2>&1 >> /dev/null if [ $? -ne 0 ]; then log "Repository server ($YUMMAINSERVER) unreachable." log "... Aborting" sleep 1 out 1 fi } checkuserabort() { CD=5 echo -n " Press any key to abort. Starting in: X second(s)." echo -ne "\b\b\b\b\b\b\b\b\b\b\b\b$CD second(s)." while [ $CD != 0 ];do read -s -n 1 -t 1 if [ $? -eq 0 ]; then echo -e "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b aborted. " echo "" log "aborted by user." out 0 fi CD=$(($CD-1)) echo -ne "\b\b\b\b\b\b\b\b\b\b\b\b$CD second(s)." done echo -e "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b. " } msg() { /bin/cat $1 | /bin/egrep -v "(^(---?>|[0-9]+.packages.excluded|[[:space:]]+(Updating|Removing|Cleanup|:[[:space:]])|Added.new|Beginning|Complete|Dependencies|Downloading|Excluding|Finished|Load|RHN|Reading|Resolving|Running|Setting|Skipping|This.system|Total|Transaction)|##|\|=|^$)" >> $2 } msg_toupdate () { echo "Following packages are available for upgrade on your system:" > $2 msg $1 $2 echo "" >> $2 echo "********************************************************" >> $2 echo "* To upgrade manually your system, run as root:" >> $2 echo "*" >> $2 echo "* $YUM $YUMUPDATEMETHOD" >> $2 echo "********************************************************" >> $2 } msg_updated () { echo "Following packages have been upgraded on your system:" > $2 echo "" >> $2 msg $1 $2 echo "" >> $2 } msg_signature () { echo "" >> $1 echo "--" >> $1 echo "message sent by `basename $0` system from $HOSTNAME" >> $1 echo "see: /etc/sysconfig/yum-autoupdate for options." >> $1 } mail() { if [ $YUMINTERACTIVE -eq 0 ]; then /bin/sed -e 's/\r//g' -i $3 /bin/mail -s "[UPDATE] - $1 on $HOSTNAME: $DATE" $2 < $3 #echo "MAILSTART *************************************" #echo "[UPDATE] - $1 on $HOSTNAME: $DATE (to: $2)" #/bin/cat $3 #echo "MAILEND *************************************" fi } check_errors() { ERRCNT=`/bin/egrep -c -i "^((config|options|transaction.check|command.line).error|error(.downloading)?|failure):" $1` if [ $ERRCNT -ne 0 ]; then echo "" >> $1 echo "There was a problem running yum-autoupdate" >> $1 echo "Please check $YUMLOGFILE" >> $1 msg_signature $1 [ $YUMMAIL -eq 1 ] && mail "FAILURE" $YUMMAILTO $1 [ $YUMREMOTELOG -eq 1 ] && remlog "FAIL" "0" out 1 fi } runcomm() { log "running: $1" echo "" > $TEMPFILE if [ $YUMINTERACTIVE -eq 1 ] || [ $YUMBOOTRUN -eq 1 ]; then LANG=C /usr/bin/unbuffer $1 2>&1 | /usr/bin/tee -a $TEMPFILE 2>&1 else LANG=C $1 >> $TEMPFILE 2>&1 RETVAL=$? if [ "$RETVAL" -gt 0 ]; then echo "$1 returned $RETVAL" >> $TEMPFILE fi fi /bin/cat $TEMPFILE | /bin/grep -v " " >> $TEMPFILE2 /bin/cat $TEMPFILE2 >> $YUMLOGFILE check_errors $TEMPFILE2 } usage() { echo echo "`basename $0`: automatic system updater using yum" echo "version: $YUMVERSION, linux.support@cern.ch" echo echo "Usage:" echo " `basename $0` -h|-y" echo echo "Options:" echo " -h - this help" echo " -y - answer yes to all prompts (and perform upgrade)" echo "" echo "if no options are specified defaults from:" echo " $YUMCONFFILE" echo "are used." } init GOTYES=0 if [ $YUMINTERACTIVE -eq 1 ]; then echo "-----------------------------------------------------------" echo "`basename $0` is to be used only from" echo "system cron or init scripts." echo "" echo "To update your system in interactive mode" echo "please use: " echo "" echo "/usr/bin/yum $YUMUPDATEMETHOD - command line interface" echo "/usr/bin/yumex - graphical user interface" echo "-----------------------------------------------------------" out 1 fi [ $YUMINTERACTIVE -eq 0 ] && [ ! -f $YUMLOCKFILE ] && out 0 [ $YUMINTERACTIVE -eq 0 ] && [ $GOAHEAD -eq 0 ] && out 0 log "-----------------------------------------------------------" log "`basename $0` started at $DATE" [ $YUMINTERACTIVE -eq 0 ] && [ $YUMBOOTRUN -eq 0 ] && randomsleep [ $YUMBOOTRUN -eq 1 ] && checknetwork if [ $YUMUPDATE -eq 0 ]; then runcomm "$YUM $YUMARGS check-update" if [ -s $TEMPFILE ]; then count_changed_packages $TEMPFILE [ $CHANGES -ne 0 ] && msg_toupdate $TEMPFILE $TEMPMAIL [ $YUMREMOTELOG -eq 1 ] && remlog "CHECK" $CHANGES fi else runcomm "$YUM $YUMARGS $YUMUPDATEMETHOD" if [ -s $TEMPFILE ]; then count_changes $TEMPFILE [ $CHANGES -ne 0 ] && msg_updated $TEMPFILE $TEMPMAIL [ $YUMREMOTELOG -eq 1 ] && remlog "UPDATE" $CHANGES fi fi [ -s $TEMPMAIL ] && msg_signature $TEMPMAIL [ $YUMCLEAN -eq 1 ] && runcomm "$YUM $YUMARGS clean packages" [ $YUMUPDATE -eq 1 ] && MAILSUBJ="SUCCESS" || MAILSUBJ="UPDATES AVAILABLE" [ -s $TEMPMAIL ] && [ $YUMMAIL -eq 1 ] && mail "$MAILSUBJ" $YUMMAILTO $TEMPMAIL out 0 # TODO(fuji): get rid of absolute pathnames # End of file.