#!/bin/sh # # This script initializes the backout data for a patch package # directory format options. # #pragma ident "@(#)preinstall 1.18 06/09/07 SMI" # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PATH=/usr/sadm/bin:$PATH recovery="no" if [ "$PKG_INSTALL_ROOT" = "/" ]; then PKG_INSTALL_ROOT="" fi # Check to see if this is a patch installation retry. if [ "$INTERRUPTION" = "yes" ]; then if [ -d "$PKG_INSTALL_ROOT/var/tmp/$SUNW_PATCHID.$PKGINST" ] || [ -d "$PATCH_BUILD_DIR/$SUNW_PATCHID.$PKGINST" ]; then recovery="yes" fi fi if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then BUILD_DIR="$PATCH_BUILD_DIR/$SUNW_PATCHID.$PKGINST" else BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$SUNW_PATCHID.$PKGINST" fi FILE_DIR=$BUILD_DIR/files RELOC_DIR=$BUILD_DIR/files/reloc ROOT_DIR=$BUILD_DIR/files/root PROTO_FILE=$BUILD_DIR/prototype ORIGPKGINFO=$PKG_INSTALL_ROOT/var/sadm/pkg/$PKGINST/pkginfo PKGINFO_FILE=$BUILD_DIR/pkginfo THIS_DIR=`dirname $0` INSTALLINGPKGINFO="`dirname $SCRIPTS_DIR`/pkginfo" if [ "$PATCH_PROGRESSIVE" = "true" ]; then # If this is being used in an old-style patch, insert # the old-style script commands here. #XXXOld_CommandsXXX# exit 0 fi # # Unless specifically denied, initialize the backout patch data by # creating the build directory and copying over the original pkginfo # which pkgadd saved in case it had to be restored. # if [ "$PATCH_NO_UNDO" != "true" ] && [ "$recovery" = "no" ]; then if [ -d $BUILD_DIR ]; then rm -r $BUILD_DIR fi # If this is a retry of the same patch then recovery is set to # yes. Which means there is a build directory already in # place with the correct backout data. if [ "$recovery" = "no" ]; then mkdir $BUILD_DIR mkdir -p $RELOC_DIR mkdir $ROOT_DIR fi # # Here we initialize the backout pkginfo file by first # copying over the old pkginfo file and then adding the # ACTIVE_PATCH parameter so the backout will know what patch # it's backing out. # # NOTE : Within the installation, pkgparam returns the # original data. # pkgparam -v $PKGINST | nawk ' $1 ~ /PATCHLIST/ { next; } $1 ~ /CLASSES/ { next; } $1 ~ /PATCH_OBSOLETES/ { next; } $1 ~ /ACTIVE_OBSOLETES/ { next; } $1 ~ /SUNW_OBSOLETES/ { next; } $1 ~ /ACTIVE_PATCH/ { next; } $1 ~ /SUNW_PATCHID/ { next; } $1 ~ /UPDATE/ { next; } $1 ~ /SCRIPTS_DIR/ { next; } $1 ~ /PATCH_NO_UNDO/ { next; } $1 ~ /INSTDATE/ { next; } $1 ~ /PKGINST/ { next; } $1 ~ /OAMBASE/ { next; } $1 ~ /PATH/ { next; } { print; } ' | sed s,\'\"\'\"\',ApOsTrOpHe,g > $PKGINFO_FILE # The previous is needed to workaround pkgparam # inserting '"'"' for every ' it finds in the # pkginfo file. see bugid 4052001. # If there is an undo script delivered with this patch pkg # there is a possibility that when the patch gets backed out # it may not get executed due to the CLASSES macro in the # original pkginfo not containing the class # identifier. Thus we need to merge the old CLASSES macro and # the installing patch pkgs CLASSES macro. nawk ' $1 ~ /CLASSES/ {print $0} ' $ORIGPKGINFO \ | sed s/CLASSES=// > /tmp/installingCLASSES.$$ classIDs=`nawk ' $1 ~ /CLASSES/ {print $0} ' $INSTALLINGPKGINFO \ | sed s/CLASSES=//` for instClass in $classIDs; do notFound=`grep "$instClass" /tmp/installingCLASSES.$$` if [ -z "$notFound" ]; then newCLASSESlist="$instClass $newCLASSESlist" fi notFound="" done classes=`nawk ' $1 ~ /CLASSES/ {print $0} ' $ORIGPKGINFO` newCLASSESlist="$classes $newCLASSESlist" echo "$newCLASSESlist" >> $PKGINFO_FILE echo "ACTIVE_PATCH=$SUNW_PATCHID" >> $PKGINFO_FILE echo "ACTIVE_OBSOLETES=$ACTIVE_OBSOLETES" >> $PKGINFO_FILE rm /tmp/installingCLASSES.$$ # And now initialize the backout prototype file with the # pkginfo file just formulated. echo "i pkginfo" > $PROTO_FILE # Copy over the backout scripts including the undo class # action scripts for script in $SCRIPTS_DIR/*; do srcscript=`basename $script` targscript=`echo $srcscript | nawk ' { script=$0; } /u\./ { sub("u.", "i.", script); print script; next; } /patch_/ { sub("patch_", "", script); print script; next; } { print "dont_use" } '` if [ "$targscript" = "dont_use" ]; then continue fi echo "i $targscript=$FILE_DIR/$targscript" >> $PROTO_FILE cp $SCRIPTS_DIR/$srcscript $FILE_DIR/$targscript done # # Now add entries to the prototype file that won't be passed to # class action scripts. If the entry is brand new, add it to the # deletes file for the backout package. # Our_Pkgmap=`dirname $SCRIPTS_DIR`/pkgmap BO_Deletes=$FILE_DIR/deletes # # Adding hard link entries into the proto file. # nawk -v basedir=${BASEDIR:-/} ' { ftype = $1; } $1 ~ /[0123456789]/ { if ( NF >= 3) { ftype = $2; } else { next; } } { if (ftype == "l") { print $0; } else { next; } } ' < $Our_Pkgmap 1>> $PROTO_FILE 2> /dev/null nawk -v basedir=${BASEDIR:-/} ' BEGIN { count=0; } { token = $2; ftype = $1; } $1 ~ /[#\!:]/ { next; } $1 ~ /[0123456789]/ { if ( NF >= 3) { token = $3; ftype = $2; } else { next; } } { if (ftype == "l" || ftype == "i" || ftype == "e" || ftype == "f" || ftype == "v" || ftype == "d") { next; } } { equals=match($4, "=")-1; if ( equals == -1 ) { print $3, $4; } else { print $3, substr($4, 0, equals); } } ' < $Our_Pkgmap | while read class path; do # # If this isn't replacing something, then it # just goes to the deletes list. # if valpath -l $path; then Chk_Path="$BASEDIR/$path" Build_Path="$RELOC_DIR/$path" Proto_From="$BASEDIR" else # It's an absolute path Chk_Path="$PKG_INSTALL_ROOT$path" Build_Path="$ROOT_DIR$path" Proto_From="$PKG_INSTALL_ROOT" fi # If we're up against a file system that can't be # written to, skip adding the link to the backout # package. Check the links parent directory for # writablility. If the parent directory does # not exist yet, check its parent directory until # the parent directory is $BASEDIR or # $PKG_INSTALL_ROOT dirPath=`dirname "$Chk_Path"` while [ "$dirPath" != "$Proto_From" ]; do # If path doesn't exist check parent path if valpath -n $dirPath; then dirPath=`dirname "$dirPath"` else break fi done if [ "$dirPath" != "$Proto_From" ]; then /usr/bin/touch $dirPath/.testpatchadd.$$ \ > /dev/null 2>&1 if [ $? != 0 ]; then continue fi rm -f $dirPath/.testpatchadd.$$ fi if [ -f "$Chk_Path" -a ! -h "$Chk_Path" ] ; then mkdir -p `dirname $Build_Path` cp -p $Chk_Path $Build_Path cd $Proto_From pkgproto -c $class "$Build_Path=$path" 1>> $PROTO_FILE 2> /dev/null cd $THIS_DIR elif [ -h "$Chk_Path" -o \ -c "$Chk_Path" -o \ -b "$Chk_Path" -o \ -p "$Chk_Path" ]; then pkgproto -c $class "$Chk_Path=$path" \ 1>> $PROTO_FILE 2> /dev/null else echo $path >> $BO_Deletes fi done fi # If additional operations are required for this package, place # those package-specific commands here. #XXXSpecial_CommandsXXX# ## ## variables which are set by checkinstall for us ## ## SP_ACTION ## LIBS_TO_OVERLAY_SYMMETRIC ## LIBS_TO_OVERLAY_LATEST ## PATCH_LIBS_STORE ## SP_LD_LIBRARY_PATH ## # If we are not in alternate root, we want to backup certain libs for overlay # mount later in the process and if they have been already overlayed, unmount # or fail. LAST="/bin/last" NAWK="/bin/nawk" MKDIR="/bin/mkdir" DIRNAME="/bin/dirname" CP="/bin/cp" MOUNT="/sbin/mount" UMOUNT="/sbin/umount" FIND="/bin/find" SORT="/bin/sort" RebootID() # because I do not know how to get on solaris kernel incarnation number (if there is one) # I am using last system reboot time # # prints last reboot time in form Thu_Aug_3_09_47 { TZ=C $LAST 'system boot'|$NAWK 'NR==1 && $7 !~ /^$/ { gsub(/[.:-]/,"_",$7); print $4"_"$5"_"$6"_"$7; }' } CP_OBJ() # $object $pathto # copy $object into $pathto preserving $object pathname # and creating all needed subdirectories if needed # CP_OBJ /lib/libc.so.1 /tmp/.aa will copy /lib/libc.so.1 into /tmp/.aa/lib/libc.so.1 # Do not do anything if target already exists. { if [ -n "$2" -a ! -f "$2/$1" ]; then $MKDIR -p "`$DIRNAME \"$2/$1\"`" \ && $CP -rp "$1" "$2/$1" fi } GetMount() # $mountpoint # prints how mount command should look like to get it mounted back # if there is more overlay mounts it prints last one { [ -n "$1" ] \ && $MOUNT -p \ | $NAWK '{ gsub(/\/+/,"/",XM);}; $3 ~ XM {X="-O -F "$4" -o "$7" "$1" "$3; }; END{ print X; }' XM="^$1\$" } GetDeviceMount() # $device # prints how mount should look like to get it mounted back # if there is more overlay mounts it prints last one { [ -n "$1" ] \ && $MOUNT -p \ | $NAWK '{ gsub(/\/+/,"/",XM);}; $1 ~ XM {X="-O -F "$4" -o "$7" "$1" "$3; }; END{ print X; }' XM="^$1\$" } GetLibStroreLibPath() # $libstore { if [ -n "$1" -a -d "$1" ]; then echo `$FIND "$1" -type f -exec $DIRNAME {} \;|$SORT -u`|$NAWK '{ gsub(/ /,":"); print }' fi } AlternateRoot() # returns 0 if $PKG_INSTALL_ROOT - { if [ -n "$PKG_INSTALL_ROOT" ]; then if [ "/" = "`echo $PKG_INSTALL_ROOT|$NAWK '{gsub(/\/+/,"/"); print}'`" ]; then return 1 else return 0 fi else return 1 fi } Umount() # $mount1 [ $mount2 ... ] # Umount will umount all objects from its parameters # it will exit 1 if an object can not be unmounted { for LIB_NAME in "$@"; do if [ -n "`GetMount $PKG_INSTALL_ROOT/$LIB_NAME`" ]; then $UMOUNT "$PKG_INSTALL_ROOT/$LIB_NAME" \ || { echo "ERROR: can not umount $PKG_INSTALL_ROOT/$LIB_NAME, please reboot and try $SP_ACTION again." exit 1 } fi done } PATCHADD_LIBS="$PATCH_LIBS_STORE/patchadd" PATCHRM_LIBS="$PATCH_LIBS_STORE/patchrm" if [ "$SP_ACTION" = "patchadd" ]; then LIB_STORE_1="$PATCHRM_LIBS" LIB_STORE_2="$PATCHADD_LIBS" LIB_PATCHID="$SUNW_PATCHID" else LIB_STORE_2="$PATCHRM_LIBS" LIB_STORE_1="$PATCHADD_LIBS" LIB_PATCHID="$ACTIVE_PATCH" fi if AlternateRoot; then : else LD_LIBRARY_PATH="`GetLibStroreLibPath $PATCH_LIBS_STORE`" export LD_LIBRARY_PATH Umount $LIBS_TO_OVERLAY_SYMMETRIC $LIBS_TO_OVERLAY_LATEST # Store only SYMMETRIC libraries in patchadd for LIB_NAME in $LIBS_TO_OVERLAY_SYMMETRIC ; do if [ ! -f $PATCH_LIBS_STORE/*/*/$LIB_NAME ]; then CP_OBJ "$PKG_INSTALL_ROOT/$LIB_NAME" "$LIB_STORE_2/$LIB_PATCHID" fi done fi exit 0