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 2007 Sun Microsystems, Inc.  All rights reserved.
     24 # Use is subject to license terms.
     25 # 
     26 #ident	"%Z%%M%	%I%	%E% SMI"
     27 #
     28 # This script builds the overhead information used by bfu to do
     29 # automatic conflict resolution.  This overhead information is stored
     30 # in a gzip'ed cpio archive called "conflict_resolution.gz" in the
     31 # archive directory. It contains all of the class-action script
     32 # required to upgrade the editable files, plus a control file
     33 # (editable_file_db) which lists the editable files and the
     34 # class-action scripts needed to upgrade them.
     35 #
     36 
     37 parse_pkginfo() {
     38 
     39 	isa=$1
     40 	dir=$2
     41 
     42 	nawk -v matchisa=$isa -v pkginst=$dir -F= '
     43 
     44 	# This clause matches architecture specific entries. e.g. CLASSES_i386=
     45 	# It has a different format to the other ERE entries as this allows
     46 	# the variable substition.
     47 
     48 	$1 ~ "CLASSES_"matchisa"[\t ]*$" {
     49 		gsub(/"/, "", $2);
     50 		numisaclasses = split($2, isaclasses, " ");
     51 		next;
     52 	}
     53 	/^CLASSES *=/ {
     54 	  	gsub(/"/, "", $2);
     55 		numclasses = split($2, classes, " ");
     56 	  	next;
     57 	}
     58 	/^PKG *=/  {
     59 	  	gsub(/"/, "", $2);
     60 		pkg = $2;
     61 		next;
     62 	}
     63 	/^ARCH *=/ {
     64 		mach = "-";
     65 	  	gsub(/"/, "", $2);
     66 		if ($2 ~ /ISA/) {
     67 			pkgisa = matchisa;
     68 		} else {
     69 			dotpos = index($2, ".");
     70 			if (dotpos != 0 ) {
     71 				pkgisa = substr($2, 1, dotpos - 1);
     72 				mach = substr($2, dotpos + 1);
     73 			} else {
     74 				pkgisa = $2
     75 			}
     76 		}
     77 		if (pkgisa != matchisa)
     78 			exit 0;
     79 		next;
     80 	}
     81 	END {
     82 		if (numclasses == 0 && numisaclasses == 0)
     83 			exit 0;
     84 
     85 		for (i in isaclasses) {
     86 		    	if (isaclasses[i] == "none") 
     87 			    	continue;
     88 
     89 			printf("%s %s %s %s %s\n", pkg, pkginst, pkgisa, mach, 
     90 				isaclasses[i]);
     91 		}
     92 		for (i in classes) {
     93 		    	if (classes[i] == "none") 
     94 			    	continue;
     95 
     96 			printf("%s %s %s %s %s\n", pkg, pkginst, pkgisa, mach, 
     97 				classes[i]);
     98 		}
     99 	}
    100 	' $dir/pkginfo.tmpl 
    101 }
    102 
    103 #
    104 # the process_pkdefs_directory function generates the conflict
    105 # resolution information for a single pkgdefs directory (there can
    106 # be more than one in an ON workspace).
    107 # 
    108 # It gets two arguments explicitly:
    109 #	$1 - the location of the pkgdefs directory
    110 #	$2 - a string to be used as a "uniquifier" for generating
    111 #	     pathnames for class files (there can be more than one
    112 #	     class action script with the same name, but they are all
    113 #	     stored in one directory in the conflict resolution
    114 #	     database).
    115 #
    116 # It gets two pieces of data globally:  the values of the "corepkgs"
    117 # and the "bfu_incompatible_classes" variables.
    118 #
    119 process_pkgdefs_directory() {
    120 
    121 	pkgdefsdir=$1
    122 	un=$2
    123 
    124 	cd $pkgdefsdir
    125 
    126 	# Step 1: Generate a list of packages to be processed, with the
    127 	# "core" packages at the head of the list.
    128 
    129 	if [ "$ACR_DEBUG" = "yes" ] ; then
    130 		print "Step 1: Generating list of packages to be processed"
    131 	fi
    132 
    133 	for dir in $corepkgs; do
    134 		if [ -d $dir -a -s $dir/pkginfo.tmpl -a \
    135 		     -s $dir/prototype_$isa ] ; then
    136 			print $dir
    137 		fi
    138 	done | sort > $pkglist
    139 
    140 	for dir in *; do
    141 		if [ -d $dir -a -s $dir/pkginfo.tmpl -a \
    142 		    -s $dir/prototype_$isa ] ; then
    143 			print $dir
    144 		fi
    145 	done | sort > $allpkglist
    146 
    147 	# make copy of pkglist so comm doesn't keep going because it's
    148 	# appending to an input file
    149 
    150 	cp $pkglist $pkgcopy
    151 	comm -13 $pkgcopy $allpkglist >> $pkglist
    152 
    153 	#
    154 	# Step 2: build a list of all of the classes in all the packages
    155 	# (except for the "none" class).  The order of each package's class
    156 	# list must match the order in the pkginfo.tmpl file.
    157 	#
    158 
    159 	if [ "$ACR_DEBUG" = "yes" ] ; then
    160 		print "Step 2: Build list of all classes in all packages."
    161 	fi
    162 
    163 	cat $pkglist | while read dir; do
    164 	    	parse_pkginfo $isa $dir 
    165 	done > $allclasslist_t
    166 
    167 	cat $allclasslist_t | while read pkg pkginst p_isa mach class; do
    168 		if [ -s common_files/i.$class -o \
    169 		     -s common_files/i.${class}_$isa ] ; then
    170 			print $pkg $pkginst $p_isa $mach $class c
    171 		else
    172 			print $pkg $pkginst $p_isa $mach $class s
    173 		fi
    174 	done > $allclasslist
    175 
    176 	#
    177 	# Step 3: For each package with at least one installation class,
    178 	# scan the package's prototype files and look for files that are
    179 	# editable or volatile and which have class-action scripts.  Make
    180 	# a list of those files, with their packages and script names.
    181 	#
    182 
    183 	if [ "$ACR_DEBUG" = "yes" ] ; then
    184 		print "Step 3: Build list of editable files."
    185 	fi
    186 
    187 	nawk '$3 == "'$isa'" {print $2}' $allclasslist | sort -u |
    188 	while read pkginst; do
    189 		if [ -s $pkginst/prototype_com ] ; then
    190 			protos="$pkginst/prototype_com $pkginst/prototype_$isa"
    191 		else
    192 			protos="$pkginst/prototype_$isa"
    193 		fi
    194 		
    195 		cat $protos | nawk -v pkginst=$pkginst \
    196 		    '(/^[ev] /) && ($2 != "none") {
    197 				printf("%s %s %s\n", $3, pkginst, $2);}'
    198 	done > $editablefilelist
    199 
    200 	#
    201 	# Step 4: Use the information in $allclasslist and
    202 	# $editablefilelist to generate the list of files
    203 	# to be copied to the bfu archive and the
    204 	# editable-file/class-action-script database to be installed
    205 	# in the archive.
    206 	#
    207 
    208 	if [ "$ACR_DEBUG" = "yes" ] ; then
    209 		print "Step 4: Merge class list and editable files list"
    210 	fi
    211 
    212 	cat $allclasslist | while read pkg pkgdir classisa mach class iscommon
    213 	do
    214 		nawk -v pkgdir=$pkgdir -v class=$class -v pkg=$pkg \
    215 		    -v isa=$classisa -v mach=$mach -v iscommon=$iscommon \
    216 		    -v uniquifier=$un '
    217 			{ if ($2 == pkgdir && $3 == class)
    218 				printf("%s i.%s %s %s %s %s %s %s\n", $1,
    219 					class, pkg, $2, isa, mach, iscommon,
    220 					uniquifier);
    221 			}' $editablefilelist
    222 	done > $db
    223 
    224 	for badclass in $bfu_incompatible_classes; do
    225 		nawk -v badclass=$badclass -v replclass="upgrade_default" '{
    226 			if ($2 == badclass)
    227 				class = replclass;
    228 			else
    229 				class = $2;
    230 			printf("%s %s %s %s %s %s %s %s\n", 
    231 					$1, class, $3, $4, $5, $6, $7, $8)
    232 		    }' $db > $tmpdb
    233 		mv $tmpdb $db
    234 	done
    235 
    236 	#
    237 	# Step 5 - Copy the editable-file/class-action-script database file
    238 	#   to the class scripts to the archive directory.
    239 	#
    240 
    241 	if [ "$ACR_DEBUG" = "yes" ] ; then
    242 		print "Step 5: Create bfu conflict resolution directory"
    243 	fi
    244 
    245 	mkdir -p $tmpdir/conflict_resolution/$un
    246 
    247 	nawk '{ print $3 }' $editablefilelist | sort -u | while read class; do
    248 		if [ -s common_files/i.$class ] ; then
    249 			cp common_files/i.$class \
    250 			    $tmpdir/conflict_resolution/$un
    251 		elif [ -s common_files/i.${class}_$isa ] ; then
    252 			cp common_files/i.${class}_$isa \
    253 			    $tmpdir/conflict_resolution/$un/i.$class
    254 		else
    255 			nawk -v class=$class '$3 == class { print $2 }' \
    256 			    $editablefilelist | sort -u > $classpk
    257 			if [ $(wc -l < $classpk) -ne 1 ]
    258 			then
    259 				cat >&2 <<EOF
    260 mkacr: The class script i.$class cannot be found in the pkgdefs common files
    261 directory, and there is more than one package that uses it.
    262 EOF
    263 				exit 1
    264 			fi
    265 			pkgdir=$(cat $classpk)
    266 			if [ -s $pkgdir/i.$class ] ; then
    267 				mkdir -p $tmpdir/conflict_resolution/$un/$pkgdir
    268 				cp $pkgdir/i.$class \
    269 				    $tmpdir/conflict_resolution/$un/$pkgdir
    270 			elif [ -s $pkgdir/i.${class}_$isa ] ; then
    271 				mkdir -p $tmpdir/conflict_resolution/$un/$pkgdir
    272 				cp $pkgdir/i.${class}_$isa \
    273 				    $tmpdir/conflict_resolution/$un/$pkgdir/i.$class
    274 			else
    275 				print -u2 "mkacr: Can't find class script i.$class"
    276 				exit 1
    277 			fi
    278 		fi
    279 	done
    280 
    281 	cat $db >> $tmpdir/conflict_resolution/editable_file_db
    282 
    283 	if [ "$ACR_DEBUG" = "yes" ] ; then
    284 		mkdir $tmpdir/$un
    285 		mv $tmpdir/ps.* $tmpdir/$un
    286 	else
    287 		rm -fr $tmpdir/ps.*
    288 	fi
    289 }
    290 
    291 #
    292 # Execution starts here
    293 #
    294 
    295 export LC_ALL=C
    296 ACR_DEBUG=${ACR_DEBUG-no}
    297 
    298 USAGE="Usage: $0 <workspace> <instruction-set-architecture> <archive-dir>"
    299 
    300 if [ $# -ne 3 ] ; then
    301 	print -u2 $USAGE
    302 	exit 1
    303 fi
    304 
    305 workspace=$1
    306 isa=$2
    307 if [ -d $workspace/pkgdefs ] ; then
    308 	:
    309 elif [ -d $workspace/usr/src/pkgdefs ] ; then
    310 	workspace=$workspace/usr/src
    311 else 
    312 	print -u2 $USAGE
    313 	exit 1
    314 fi
    315 
    316 if [ ! -d $3 ] ; then
    317 	print -u2 $USAGE
    318 	exit 1
    319 fi
    320 archivedir=$(cd $3; pwd)
    321 
    322 if [ "$isa" != "sparc" -a "$isa" != "i386" ] ; then
    323 	print -u2 "$0: Instruction set architecture must be \"sparc\" or \"i386\""
    324 	exit 1
    325 fi
    326 
    327 #
    328 # temporary file scorecard, in order of appearance:
    329 # (Temporary files that begin with "ps." are pass-specific.  mkacr
    330 # generates its database in multiple passes:  one for each pkgdef
    331 # directory in the ON source base.  Currently there are 2:
    332 # usr/src/pkgdefs and usr/src/realmode/pkgdefs.  The temp files
    333 # that begin with "ps." are deleted at the end of each pass.)
    334 #
    335 # ps.pkglist	package names, starting with core pkgs
    336 #
    337 # ps.allpkglist 	pass 1 additional package list
    338 #
    339 # ps.pkgcopy	pass 1 temporary copy of core package names 
    340 #
    341 # ps.allclasslist	list of all classes
    342 #
    343 # ps.allclasslist_t	preliminary version of ps.allclasslist
    344 #
    345 # ps.editablefilelist	list of editable files.
    346 #
    347 # ps.db, tmpdb	temporary files used in construction of editable_file_db
    348 #
    349 # ps.cpioerr 	stderr from cpio.
    350 #
    351 
    352 tmpdir=$(mktemp -t -d mkacr.XXXXXX)
    353 
    354 if [ -z "$tmpdir" ] ; then
    355         print -u2 "mktemp failed to produce output; aborting"
    356         exit 1
    357 fi
    358 
    359 if [ ! -d "$tmpdir" ] ; then
    360     	print -u2 "$0: Couldn't create temporary directory $tmpdir"
    361 	exit 1
    362 fi
    363 
    364 if [ "$ACR_DEBUG" = "yes" ] ; then
    365     	print "Temporary files will be left in $tmpdir"
    366 else
    367 	trap 'rm -rf $tmpdir' 0
    368 fi
    369 
    370 cpioerr=$tmpdir/ps.cpioerr
    371 pkglist=$tmpdir/ps.pkglist
    372 allpkglist=$tmpdir/ps.allpkglist
    373 pkgcopy=$tmpdir/ps.pkgcopy
    374 allclasslist=$tmpdir/ps.allclasslist
    375 allclasslist_t=$tmpdir/ps.allclasslist_t
    376 editablefilelist=$tmpdir/ps.editablefilelist
    377 db=$tmpdir/ps.db
    378 tmpdb=$tmpdir/ps.tmpdb
    379 classpk=$tmpdir/ps.classpk
    380 
    381 #
    382 # set up the list of corepkgs and bfs-incompatible classes for the
    383 # processing of the usr/src/pkgdefs directory
    384 #
    385 
    386 corepkgs="
    387 	SUNWcar.*
    388 	SUNWcakr.*
    389 	SUNWckr
    390 	SUNWcsd
    391 	SUNWcsr
    392 	SUNWcsu
    393 	SUNWcsl
    394 	SUNWcslr
    395 	SUNWkvm.*
    396 "
    397 bfu_incompatible_classes="
    398 	i.initd
    399 "
    400 
    401 process_pkgdefs_directory $workspace/pkgdefs std
    402 
    403 if [[ -d $workspace/../closed/pkgdefs && "$CLOSED_IS_PRESENT" != no ]]; then
    404 	process_pkgdefs_directory $workspace/../closed/pkgdefs std-closed
    405 fi
    406 
    407 #
    408 # set up the list of corepkgs and bfs-incompatible classes for the
    409 # processing of the usr/src/realmode/pkgdefs directory
    410 #
    411 
    412 corepkgs="SUNWrmodr"
    413 bfu_incompatible_classes=""
    414 
    415 if [ -d $workspace/realmode/pkgdefs ] ; then
    416     	process_pkgdefs_directory $workspace/realmode/pkgdefs realmode
    417 fi
    418 
    419 if [ "$ACR_DEBUG" = "yes" ] ; then
    420 	print "Final processing: Create bfu conflict resolution archive"
    421 fi
    422 
    423 print "Creating conflict resolution archive: \c";
    424 
    425 (cd $tmpdir
    426 find conflict_resolution -print | cpio -ocB 2>$cpioerr |
    427     gzip -c > $archivedir/conflict_resolution.gz ) || exit 1
    428 
    429 awk '/^[0-9]* blocks$/ { blocks=1; print $0; next }
    430 { print $0 > "/dev/stderr" }
    431 END {
    432 	if (!blocks) {
    433 		# Terminate the "print \c" line above.
    434 		print
    435 		print "No cpio block count" > "/dev/stderr"
    436 	}
    437 }' <$cpioerr
    438 
    439 exit 0
    440