Home | History | Annotate | Download | only in scripts
      1 #!/bin/ksh -p
      2 #
      3 # CDDL HEADER START
      4 #
      5 # The contents of this file are subject to the terms of the
      6 # Common Development and Distribution License (the "License").
      7 # You may not use this file except in compliance with the License.
      8 #
      9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10 # or http://www.opensolaris.org/os/licensing.
     11 # See the License for the specific language governing permissions
     12 # and limitations under the License.
     13 #
     14 # When distributing Covered Code, include this CDDL HEADER in each
     15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16 # If applicable, add the following below this CDDL HEADER, with the
     17 # fields enclosed by brackets "[]" replaced with your own identifying
     18 # information: Portions Copyright [yyyy] [name of copyright owner]
     19 #
     20 # CDDL HEADER END
     21 #
     22 #
     23 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24 # Use is subject to license terms.
     25 #
     26 #
     27 # usage: acr [root [archivedir]]
     28 #
     29 # examples:  acr
     30 #	     acr /export/home/zone/root
     31 #	     acr /export/home/zone/root ${CODEMGR_WS}/archives/sparc/nightly
     32 #
     33 
     34 if [ $# -gt 2 ] ; then
     35 	print -u2 "usage:  $0 <root> <archivedir>"
     36 	exit 1
     37 fi
     38 
     39 root=${1-/}
     40 archivedir=$2
     41 if [ -z "$archivedir" -o "$archivedir" = again ]; then
     42 	if [ ! -s $root/etc/motd ]; then
     43 		print -u2 "$root/etc/motd not found; this doesn't look like a" \
     44 		    "valid root."
     45 		exit 1
     46 	fi
     47 	archivedir=$(nawk '/^bfu.ed from / { print $3; exit }' $root/etc/motd)
     48 fi
     49 
     50 if [ ! -d "$archivedir" ]; then
     51     	print -u2 "Archive directory '$archivedir' not found."
     52 	exit 1
     53 fi
     54 
     55 #
     56 # temporary file scorecard:
     57 #
     58 # conflictscripts	list of scripts we need to run.
     59 #
     60 # installnew		list of editable files without class action scripts
     61 #
     62 # processedscript	basename of class action script edited to NOP
     63 #			installf/removef's and use /tmp/bfubin
     64 #
     65 # allresults		log of all class action script output.
     66 #
     67 # thisresult		log of most recent class action script
     68 #
     69 
     70 tmpdir=$(mktemp -t -d acr.XXXXXX)
     71 
     72 if [ -z "$tmpdir" ] ; then
     73     	print -u2 "mktemp failed to produce output; aborting."
     74 	exit 1
     75 fi
     76 
     77 if [ ! -d $tmpdir ] ; then
     78     	print -u2 "mktemp failed to create a directory; aborting."
     79 	exit 1
     80 fi
     81 
     82 conflictscripts=$tmpdir/conflictscripts
     83 installnew=$tmpdir/installnew
     84 allresults=$tmpdir/allresults
     85 thisresult=$tmpdir/thisresult
     86 processedscript=$tmpdir/processedscript
     87 
     88 #
     89 # This file is left over (on purpose) by BFU so that in a post-BFU environment
     90 # we know which zones BFU processed.
     91 #
     92 bfu_zone_list=$root/.bfu_zone_list
     93 
     94 get_cr_archive() {
     95 	compressed_archive=$archivedir/conflict_resolution.gz
     96 	if [ ! -s $compressed_archive ] ; then
     97 		print -u2 "Failed to find conflict resolution information" \
     98 		    "at $compressed_archive."
     99 		return 1
    100 	fi
    101 
    102 	print -n "Getting ACR information from $archivedir... "
    103 
    104 	gzip -d -c $compressed_archive | \
    105 	    (cd $tmpdir; cpio -idmucB > /dev/null 2>&1) || return 1
    106 
    107 	crdir=$tmpdir/conflict_resolution
    108 
    109 	if [ ! -d $crdir ] ; then
    110 		print -u2 "The conflict resolution archive is missing the" \
    111 		    "conflict_resolution directory."
    112 		return 1
    113 	fi
    114 
    115 	if [ ! -f $crdir/editable_file_db ] ; then
    116 		print -u2 "The conflict resolution archive is missing the" \
    117 			"editable file list."
    118 		return 1
    119 	fi
    120 	print "ok"
    121 	return 0
    122 }
    123 
    124 #
    125 # If we're running after a BFU, some behaviors are different.
    126 #
    127 if [ -d /tmp/bfubin ] ; then
    128 	bfu_alt_reality="true"
    129 else
    130 	bfu_alt_reality="false"
    131 fi
    132 
    133 
    134 acr_a_root() {
    135 	typeset root
    136 	typeset zone
    137 
    138 	root=$1
    139 	zone=$2
    140 
    141 	print "ZONE $2 on $1" >> $allresults
    142 
    143 
    144 	rm -f $conflictscripts
    145 	rm -f $installnew
    146 
    147 	#
    148 	# The files that need to be processed are those that were stored by
    149 	# bfu in bfu.conflicts.  Just process those that changed in the
    150 	# distribution since the last bfu (those that are listed in the
    151 	# $root/bfu.conflicts/NEW file).
    152 	#
    153 	if [ ! -d $root/bfu.conflicts ] ; then
    154 		print -u2 "No BFU conflict information."
    155 		return 1
    156 	fi
    157 
    158 	if [ ! -s $root/bfu.conflicts/NEW ] ; then
    159 		print "No conflicts to resolve."
    160 		return 0
    161 	fi
    162 
    163 	#
    164 	# Some class-action scripts rely on being run in the order defined in
    165 	# packages.  The $crdir/editable_file_db file contains the classes
    166 	# in the correct order, so we preserve that order.
    167 	#
    168 	cat $crdir/editable_file_db | \
    169 	while read filename script pkg pkginst isa mach unique pkgdef
    170 	do
    171 		grep "^$filename\$" $root/bfu.conflicts/NEW >> /dev/null || \
    172 		    continue
    173 
    174 		if [ "$mach" != "-" -a  $(uname -m) != "$mach" ] ; then
    175 			continue
    176 		fi
    177 
    178 		print $filename $script $pkg $pkginst $isa $mach $unique \
    179 		    $pkgdef >> $conflictscripts
    180 	done
    181 
    182 	if [ ! -s $conflictscripts ] ; then
    183 		print "\nNo upgrade scripts were found for any of the" \
    184 		    "conflicting files."
    185 		return 1
    186 	fi
    187 
    188 
    189 	#
    190 	# Look for files that are in the conflict list, but don't have
    191 	# entries in the $conflictscripts file.  These have no
    192 	# install scripts, so should just be copied. (The fact that such
    193 	# files exist indicates a bug in bfu or possibly in the Solaris
    194 	# packaging.  If these are really editable files, they should have
    195 	# class action scripts.  If not, bfu shouldn't special-case them.)
    196 	#
    197 	cat $root/bfu.conflicts/NEW | while read filename ; do
    198 		grep "$filename " $conflictscripts >> /dev/null
    199 		if [ $? != 0 ] ; then
    200 			print $filename >> $installnew
    201 		fi
    202 	done
    203 
    204 	if [ -s $installnew ] ; then
    205 		print "\n    The following files did not have conflict" \
    206 		    "resolution scripts; this may"
    207 		print "    indicate a bug in BFU.  The new versions will be" \
    208 		    "installed.  The previous"
    209 		print "    versions of these files can be found in" \
    210 		    "$root/bfu.child:\n"
    211 		cat $installnew | sed 's/^/        /'
    212 		print
    213 	fi
    214 
    215 	UPDATE=yes
    216 	BASEDIR=$root
    217 	PKGSAV=/tmp
    218 	PKG_INSTALL_ROOT=$root
    219 	export UPDATE BASEDIR PKGSAV PKG_INSTALL_ROOT
    220 
    221 	column_fmt='    %-35s  %-20s '
    222 
    223 	printf "\n$column_fmt %s\n" "FILE" "ACTION" "STATUS"
    224 	cat $conflictscripts | while read filename script pkg pkginst isa mach \
    225 	    unique pkgdef ; do
    226 		if [ "$script" = "upgrade_default" ] ; then
    227 			msg=`printf "$column_fmt" \
    228 			    $filename "upgrade_default_copy"`
    229 			cp $root/bfu.conflicts/$filename $root/$filename
    230 			if [ $? = 0 ]; then
    231 				printf "$msg ok\n"
    232 				continue
    233 			else
    234 				printf "$msg FAIL\n" 1>&2
    235 				return 1
    236 			fi
    237 		fi
    238 
    239 		if [ "$unique" = "c" ] ; then
    240 			scriptloc=$crdir/$pkgdef/$script
    241 		elif [ "$unique" = "s" ] ; then
    242 			scriptloc=$crdir/$pkgdef/$pkginst/$script
    243 		else
    244 			scriptloc=$root/usr/sadm/install/scripts/$script
    245 		fi
    246 		msg=`printf "$column_fmt" $filename $script`
    247 
    248 		#
    249 		# If we are running in the post-BFU alternate reality, we need
    250 		# to modify the class action script to work in that alternate
    251 		# reality.  Otherwise, we merely need to "neuter" installf
    252 		# and removef.  In any event, skip this one and go to the next
    253 		# if the sed fails.
    254 		#
    255 		if [ $bfu_alt_reality = "true" ] ; then
    256 			sed -e 's,^#!/bin/sh,#!/tmp/bfubin/sh,' \
    257 			    -e 's,/usr/bin/,/tmp/bfubin/,g' \
    258 			    -e 's,/usr/bin:,/tmp/bfubin:,' \
    259 			    -e 's,installf,/tmp/bfubin/true,' \
    260 			    -e 's,removef,/tmp/bfubin/true,' \
    261 			    $scriptloc > $processedscript.$script
    262 			error=$?
    263 		else
    264 			sed -e 's,installf,/usr/bin/true,' \
    265 			    -e 's,removef,/usr/bin/true,' \
    266 			    $scriptloc > $processedscript.$script
    267 			error=$?
    268 		fi
    269 
    270 		if [ $error != 0 ] ; then
    271 			printf "$msg FAIL (sed surgery->$error)\n" 1>&2
    272 			continue
    273 		fi
    274 
    275 		chmod +x $processedscript.$script
    276 		error=$?
    277 		if [ $error != 0 ] ; then
    278 			printf "$msg FAIL (chmod->$error)\n" 1>&2
    279 			continue
    280 		fi
    281 
    282 		PKG=$pkg
    283 		PKGINST=$pkg
    284 		if [ $mach = "-" ] ; then
    285 			ARCH=$isa
    286 		else
    287 			ARCH=$isa.$mach
    288 		fi
    289 		export PKG PKGINST ARCH
    290 
    291 		print "PROCESSING $filename with $script" >> $allresults
    292 		if [ "$script" = "i.build" ] ; then
    293 		    print $crdir/$pkgdef/$pkginst/$filename $root/$filename |
    294 			$processedscript.$script > $thisresult 2>&1
    295 		else     
    296 		    print $root/bfu.conflicts/$filename $root/$filename |
    297 			$processedscript.$script > $thisresult 2>&1
    298 		fi
    299 		error=$?
    300 		if [ $error != 0 ] ; then
    301 			printf "$msg FAIL (exit $error)\n" 1>&2
    302 			print -u2 "    Output of upgrade script:"
    303 			sed 's/^/        /' < $thisresult >&2
    304 		else
    305 			printf "$msg ok\n"
    306 		fi
    307 		cat $thisresult >> $allresults
    308 		print "RETURN CODE: $error" >> $allresults
    309 	done
    310 
    311 	if [ -s $installnew ] ; then
    312 		cat $installnew | while read filename ; do
    313 
    314 			msg=`printf "$column_fmt" $filename \
    315 			    "cp from new version"`
    316 			cp $root/bfu.conflicts/$filename $root/$filename
    317 			error=$?
    318 			if [ $error != 0 ] ; then
    319 				printf "$msg FAIL (exit $error)\n" 1>&2
    320 			else
    321 				printf "$msg ok\n"
    322 			fi
    323 
    324 		done
    325 	fi
    326 }
    327 
    328 #
    329 # If we're post-BFU, then BFU should have left us a file listing which zones it
    330 # processed.  If we're not post-BFU, just process all installed native and
    331 # Sn-1 zones.
    332 #
    333 if [ $bfu_alt_reality = "false" ]; then
    334 	zoneadm list -pi | nawk -F: '{
    335 		if ($3 == "installed" &&
    336 		    ($6 == "native" || $6 == "" || $6 == "sn1")) {
    337 			printf "%s %s\n", $2, $4
    338 		}
    339 	}' > $bfu_zone_list
    340 fi
    341 
    342 #
    343 # To be terse, check whether there is any work to do at all; if not,
    344 # just print one line and exit.
    345 #
    346 need_resolve=false
    347 if [ -s $root/bfu.conflicts/NEW ]; then
    348 	need_resolve=true
    349 else
    350 	if [ -s $bfu_zone_list ]; then
    351 		cat $bfu_zone_list | while read zone zonepath; do
    352 			if [ -s $zonepath/root/bfu.conflicts/NEW ] ; then
    353 				need_resolve=true
    354 			fi
    355 		done
    356 	fi
    357 fi
    358 
    359 if [ "$need_resolve" = "false" ]; then
    360 	print "No conflicts to resolve."
    361 	exit 0
    362 fi
    363 
    364 get_cr_archive || exit 1
    365 
    366 printf "\nProcessing global zone:\t"
    367 acr_a_root $root "global"
    368 
    369 if [ $root != "/" ]; then
    370 	printf "\nSkipping non-global zones (root is not /)"
    371 else
    372 	if [ -s $bfu_zone_list ]; then
    373 		cat $bfu_zone_list | while read zone zonepath; do
    374 			printf "\nProcessing zone $zone:\t"
    375 			acr_a_root $zonepath/root $zone
    376 		done
    377 	fi
    378 fi
    379 
    380 echo
    381 
    382 # workaround for 6644920
    383 BIN=bin
    384 cr_args=${root:+ -R $root}
    385 LD_LIBRARY_PATH=/tmp/bfulib PATH=/tmp/bfubin \
    386     /tmp/bfubin/ksh $root/boot/solaris/$BIN/create_ramdisk $cr_args
    387 
    388 print "Finished.  See $allresults for complete log."
    389