#!/bin/ksh # $Id: lupatch.sh 209 2008-12-08 06:06:22Z elkner $ # (C) 2008-2010 by Jens Elkner jel+lu@cs.uni-magdeburg.de # Licence: CDDL - see http://opensource.org/licenses/cddl1.php # last change: # 2010-02-01 want to see PCA patch info at the top of each README (see -r) # path to pca PCA="/local/misc/sbin/pca" # additional options to use for all pca operations PCA_OPTS="-a" export PATH="/usr/bin:/usr/sbin" usage() { printf 'Usage: %s [-h] [-t tmpdir] [-R root_path] [-d] [-r] [-i] [zone ...] zone .. the name of the zone, whoms patches should be installed. If no zone is given, all available zones will be used instead. -t tmpdir .. directory, where zone patch lists should be stored. Default: /var/tmp -R root_path .. Define the full path name of a directory to use as the root_path (same as in pca(1M) and lumount(1M)). Default: /mnt -h .. print this help and exit -d .. download all patches for the given zones. Also creates the patchlists for the given zone in tmpdir as patchList.$zone -r .. list all patch READMEs for the patch list of the given zones, created by -d . -i .. install patches from the patch list of the given zones, created by -d . -D .. Dry. Just show, what this script would finally do. ' `basename $0` } D="" R="" I="" T="/var/tmp" RPATH="/mnt" DRY="" while getopts "ht:driR:D" option ; do case "$option" in "h") usage; exit 1;; "t") T="${OPTARG}" if [ ! -d "$T" ]; then echo "directory $T does not exist." exit 2 fi ;; "R") RPATH="${OPTARG}" if [ ! -d "$RPATH" ]; then echo "root directory $RPATH does not exist." exit 2 fi ;; "d") D="true";; "r") R="true";; "i") I="true";; "D") DRY="echo";; esac done shift $((OPTIND-1)) if [ -z "$D" -a -z "$R" -a -z "$I" ]; then usage exit 3 fi integer OSR OSR=`uname -r | cut -f2 -d.` if [ -z "$OSR" -o $OSR -lt 10 ]; then print -u2 "This script runs on Solaris 5.10 or higher, only." exit 4 fi if [ "$RPATH" = "/" ]; then RZPATH="/root" else RZPATH="/lu/a" fi if [ -z "$1" ]; then ZONES=`zoneadm -R "$RPATH" list -pi | cut -f2 -d: | xargs` ZPATHS=`zoneadm -R "$RPATH" list -pi | cut -f2,4 -d: | \ nawk -F: -v SP=$RZPATH '{ if ( $1=="global" ) { print $2 " " } else { print $2 SP " " } }'` else ZONES="" ZPATHS="" while [ -n "$1" ]; do ZP=`zoneadm -R "$RPATH" -z "$1" list -p 2>/dev/null | cut -f4 -d:` if [ -z "$ZP" ]; then echo "Zone \"$1\" does not exist - ignored" elif [ "$1" = "global" ]; then ZONES="global $ZONES" ZPATHS="$ZP $ZPATHS" else ZONES="$ZONES $1" ZPATHS="$ZPATHS ${ZP}${RZPATH}" fi shift done fi ZDIRS="" UNAMETAIL=`uname -a | cut -f4- -d\ ` getZoneInfo() { # $1 zonename , $2 zonepath incl. trailing /lu/a for none-global zones [ ! -f "$2"/etc/release ] && return typeset ZN="$1" typeset BN="zoneinfo.${ZN}.$$" typeset ZIDIR="${T}/$BN" typeset ZPATH="$2" if [ ! -d $ZIDIR ]; then mkdir -p $ZIDIR 2>/dev/null if [ $? -ne 0 ]; then print -u2 "Unable to create $ZIDIR - exiting." exit 5 fi fi if [ ! -f "${ZIDIR}/uname.out" ]; then typeset LI=`head -1 ${ZPATH}/etc/release | awk '{ if ( $1 == "Oracle" ) { print $2 ":" $3 } else { print $1 ":" $2 } }'` [ "${LI%:*}" != "Solaris" ] && return if [ "${LI}" = "Solaris:Express" ]; then typeset -i ZOR=11 else typeset -i ZOR=${LI#*:} >/dev/null fi [ $? -ne 0 ] && return echo "SunOS ${ZN} 5.${ZOR} ${UNAMETAIL}" >${ZIDIR}/uname.out fi if [ ! -f "${ZIDIR}/showrev.out" ]; then showrev -p -R "${ZPATH}" >${ZIDIR}/showrev.out fi if [ ! -f "${ZIDIR}/pkginfo.out" ]; then pkginfo -x -R "${ZPATH}" >${ZIDIR}/pkginfo.out fi echo "$ZIDIR" } # no ksh93 -> no assoc arrays set -A ZN $ZONES set -A ZP $ZPATHS integer N integer COUNT COUNT=${#ZN[@]} if [ "$D" = "true" ]; then N=0 while [ $N -lt $COUNT ]; do [ $N -eq 1 ] && PCA_OPTS="-y ${PCA_OPTS}" ZNAME=${ZN[$N]} ZPATH=${ZP[$N]} echo "\n####### $ZNAME ######\n" ZIPATH=`getZoneInfo "$ZNAME" "$ZPATH"` if [ -z "$ZIPATH" ]; then echo "Skipping unsupported zone $ZNAME" else ZDIRS="${ZDIRS} \\ \n ${ZIPATH}" $DRY $PCA -d $PCA_OPTS -R "$ZPATH" -f "${ZIPATH}/" PL="${T}/patchList.${ZNAME}" echo "# $ZNAME" >$PL $PCA -l $PCA_OPTS -R "$ZPATH" -f "${ZIPATH}/" \ --format "%p-%c %i %r%s%b %a %y" >>$PL X=`wc -l ${PL} | awk '{ print $1 }'` [ "$X" = "6" -o "$X" = "1" ] && rm $PL fi N=$((N+1)) done echo "\n###### Available patch lists ######\n" LIST=`ls -1 ${T}/patchList.* 2>/dev/null` if [ -z "$LIST" ]; then Z=`echo $ZONES | tr ' ' ','` echo "No new patches - $Z seem to be clean." else echo "$LIST" fi echo fi if [ "$R" = "true" ]; then N=0 PFL="" while [ $N -lt $COUNT ]; do ZNAME=${ZN[$N]} if [ -r "${T}/patchList.${ZNAME}" ]; then PFL="${PFL} ${T}/patchList.${ZNAME}" fi N=$((N+1)) done if [ -z "$PFL" ]; then Z=`echo $ZONES | tr ' ' ','` echo "No patch lists found for $Z" else # insert more PCA info at the top of each tmp README file OLD_PAGER="$PAGER" [ -z "$OLD_PAGER" ] && OLD_PAGER=/usr/bin/more export OLD_PAGER TPAGER=$(mktemp -t) export PFL print '#!/bin/ksh LIST="$@" TR=$(mktemp -t) if [ -n "$TR" ]; then while [ -n "$1" ]; do if [ -w "$1" ]; then if [ -z "$HEAD" ]; then HEAD=$(egrep "^(Patch|--)" $PFL | cut -f2- -d: | sort -ur) fi TF="$1" PN=$(head -1 "$TF") PN=${PN##* } # do not insert twice if [ "$PN" != "Synopsis" ]; then TI=$(egrep "^$PN" $PFL | cut -f2- -d: | sort -u) # dumb version of gsed -i if [ -n "$TI" ]; then printf "%s\n%s\n\n" "$HEAD" "$TI" >$TR cat "$TF" >>$TR cp "$TR" "$TF" fi fi fi shift done fi $OLD_PAGER $LIST ' >>"$TPAGER" chmod 711 "$TPAGER" export PAGER="$TPAGER" PATCHES=`cat $PFL | /usr/xpg4/bin/egrep '^[0-9]{6}-[0-9]{2} ' | \ cut -f1 -d\ | sort | uniq | tr '\n' ' '` $DRY $PCA -r $PCA_OPTS $PATCHES export PAGER="$OLD_PAGER" [ -n "$TPAGER" ] && rm -f "$TPAGER" fi fi if [ "$I" = "true" ]; then N=0 while [ $N -lt $COUNT ]; do [ $N -eq 1 ] && PCA_OPTS="-y ${PCA_OPTS}" ZNAME=${ZN[$N]} ZPATH=${ZP[$N]} PL="${T}/patchList.${ZNAME}" [ $N -eq 1 ] && PCA_OPTS="-y ${PCA_OPTS}" if [ -r "$PL" ]; then PATCHES=`cat $PL | /usr/xpg4/bin/egrep '^[0-9]{6}-[0-9]{2} ' | \ cut -f1 -d\ ` if [ -n "$PATCHES" ]; then ZIPATH=`getZoneInfo "$ZNAME" "$ZPATH"` if [ -z "$ZIPATH" ]; then echo "Skipping unsupported zone $ZNAME" else ZDIRS="${ZDIRS} \\ \n ${ZIPATH}" # regenerate showrev.out - might have change via global zone mv -f ${ZIPATH}/showrev.out ${ZIPATH}/showrev.out.old ZIPATH=`getZoneInfo "$ZNAME" "$ZPATH"` NPATCHES=`$PCA -l -H $PCA_OPTS -R "$ZPATH" -f "${ZIPATH}/" \ --format "%p-%c"` NPATCHES=`echo "${PATCHES} ${NPATCHES}" | sort | uniq -d` if [ -n "$NPATCHES" ]; then # recreate PL before $DRY $PCA -i $PCA_OPTS -R "$ZPATH" -f "${ZIPATH}/" $NPATCHES fi echo "$ZNAME zone finished." fi else echo "$ZNAME zone is clean." fi else echo "Skipping $ZNAME - no patchlist found." fi N=$((N+1)) done fi if [ -n "$ZDIRS" ]; then echo "\nPlease cleanup the following directories using:\n" print "rm -rf $ZDIRS" fi