mkacr.sh revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This script builds the overhead information used by bfu to do
# automatic conflict resolution. This overhead information is stored
# in a gzip'ed cpio archive called "conflict_resolution.gz" in the
# archive directory. It contains all of the class-action script
# required to upgrade the editable files, plus a control file
# (editable_file_db) which lists the editable files and the
# class-action scripts needed to upgrade them.
#
parse_pkginfo() {
isa=$1
dir=$2
nawk -v matchisa=$isa -v pkginst=$dir -F= '
# This clause matches architecture specific entries. e.g. CLASSES_i386=
# It has a different format to the other ERE entries as this allows
# the variable substition.
$1 ~ "CLASSES_"matchisa"[\t ]*$" {
gsub(/"/, "", $2);
numisaclasses = split($2, isaclasses, " ");
next;
}
/^CLASSES *=/ {
gsub(/"/, "", $2);
numclasses = split($2, classes, " ");
next;
}
/^PKG *=/ {
gsub(/"/, "", $2);
pkg = $2;
next;
}
/^ARCH *=/ {
mach = "-";
gsub(/"/, "", $2);
if ($2 ~ /ISA/) {
pkgisa = matchisa;
} else {
dotpos = index($2, ".");
if (dotpos != 0 ) {
pkgisa = substr($2, 1, dotpos - 1);
mach = substr($2, dotpos + 1);
} else {
pkgisa = $2
}
}
if (pkgisa != matchisa)
exit 0;
next;
}
END {
if (numclasses == 0 && numisaclasses == 0)
exit 0;
for (i in isaclasses) {
if (isaclasses[i] == "none")
continue;
printf("%s %s %s %s %s\n", pkg, pkginst, pkgisa, mach,
isaclasses[i]);
}
for (i in classes) {
if (classes[i] == "none")
continue;
printf("%s %s %s %s %s\n", pkg, pkginst, pkgisa, mach,
classes[i]);
}
}
' $dir/pkginfo.tmpl
}
process_non_on_classes () {
# $1 is one of non_on_classes
# $2 is editablefilelist
nononclass=$1
efilelist=$2
pkgdir=$3
if [ "$1" = "build" ] ; then
# print the target file name and pkg name from editablefilelist
nawk -v class=${nononclass} '$3 == class { print $1,$2 }' $efilelist | \
while read tgtfile pkgname; do
mkdir -p ${pkgdir}/${pkgname}/`dirname ${tgtfile}`
if [ -s ${pkgname}/`basename ${tgtfile}` ] ; then
cp ${pkgname}/`basename ${tgtfile}` \
${pkgdir}/${pkgname}/${tgtfile}
else
print -u2 "mkacr: Can't find i.build source script."
fi
done
fi
}
#
# the process_pkdefs_directory function generates the conflict
# resolution information for a single pkgdefs directory (there can
# be more than one in an ON workspace).
#
# It gets two arguments explicitly:
# $1 - the location of the pkgdefs directory
# $2 - a string to be used as a "uniquifier" for generating
# pathnames for class files (there can be more than one
# class action script with the same name, but they are all
# stored in one directory in the conflict resolution
# database).
#
# It gets two pieces of data globally: the values of the "corepkgs"
# and the "bfu_incompatible_classes" variables.
#
process_pkgdefs_directory() {
pkgdefsdir=$1
un=$2
cd $pkgdefsdir
# Step 1: Generate a list of packages to be processed, with the
# "core" packages at the head of the list.
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Step 1: Generating list of packages to be processed"
fi
for dir in $corepkgs; do
if [ -d $dir -a -s $dir/pkginfo.tmpl -a \
-s $dir/prototype_$isa ] ; then
print $dir
fi
done | sort > $pkglist
for dir in *; do
if [ -d $dir -a -s $dir/pkginfo.tmpl -a \
-s $dir/prototype_$isa ] ; then
print $dir
fi
done | sort > $allpkglist
# make copy of pkglist so comm doesn't keep going because it's
# appending to an input file
cp $pkglist $pkgcopy
comm -13 $pkgcopy $allpkglist >> $pkglist
#
# Step 2: build a list of all of the classes in all the packages
# (except for the "none" class). The order of each package's class
# list must match the order in the pkginfo.tmpl file.
#
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Step 2: Build list of all classes in all packages."
fi
cat $pkglist | while read dir; do
parse_pkginfo $isa $dir
done > $allclasslist_t
cat $allclasslist_t | while read pkg pkginst p_isa mach class; do
if [ -s common_files/i.$class -o \
-s common_files/i.${class}_$isa ] ; then
print $pkg $pkginst $p_isa $mach $class c
else
echo ${non_on_classes} |
/usr/bin/grep -w i.${class} > /dev/null
if [ $? -eq 0 ] ; then
print $pkg $pkginst $p_isa $mach $class n
else
print $pkg $pkginst $p_isa $mach $class s
fi
fi
done > $allclasslist
#
# Step 3: For each package with at least one installation class,
# scan the package's prototype files and look for files that are
# editable or volatile and which have class-action scripts. Make
# a list of those files, with their packages and script names.
#
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Step 3: Build list of editable files."
fi
nawk '$3 == "'$isa'" {print $2}' $allclasslist | sort -u |
while read pkginst; do
if [ -s $pkginst/prototype_com ] ; then
protos="$pkginst/prototype_com $pkginst/prototype_$isa"
else
protos="$pkginst/prototype_$isa"
fi
cat $protos | nawk -v pkginst=$pkginst \
'(/^[ev] /) && ($2 != "none") && ($2 != "build") {
printf("%s %s %s\n", $3, pkginst, $2);}
(/^[ev] /) && ($2 == "build") {
split($3,buildtgt,"=");
printf("%s %s %s\n", buildtgt[1], pkginst,$2);}'
done > $editablefilelist
#
# Step 4: Use the information in $allclasslist and
# $editablefilelist to generate the list of files
# to be copied to the bfu archive and the
# editable-file/class-action-script database to be installed
# in the archive.
#
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Step 4: Merge class list and editable files list"
fi
cat $allclasslist | while read pkg pkgdir classisa mach class iscommon
do
nawk -v pkgdir=$pkgdir -v class=$class -v pkg=$pkg \
-v isa=$classisa -v mach=$mach -v iscommon=$iscommon \
-v uniquifier=$un '
{ if ($2 == pkgdir && $3 == class)
printf("%s i.%s %s %s %s %s %s %s\n", $1,
class, pkg, $2, isa, mach, iscommon,
uniquifier);
}' $editablefilelist
done > $db
for badclass in $bfu_incompatible_classes; do
nawk -v badclass=$badclass -v replclass="upgrade_default" '{
if ($2 == badclass)
class = replclass;
else
class = $2;
printf("%s %s %s %s %s %s %s %s\n",
$1, class, $3, $4, $5, $6, $7, $8)
}' $db > $tmpdb
mv $tmpdb $db
done
#
# Step 5 - Copy the editable-file/class-action-script database file
# to the class scripts to the archive directory.
#
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Step 5: Create bfu conflict resolution directory"
fi
mkdir -p $tmpdir/conflict_resolution/$un
nawk '{ print $3 }' $editablefilelist | sort -u | while read class; do
if [ -s common_files/i.$class ] ; then
cp common_files/i.$class \
$tmpdir/conflict_resolution/$un
elif [ -s common_files/i.${class}_$isa ] ; then
cp common_files/i.${class}_$isa \
$tmpdir/conflict_resolution/$un/i.$class
else
echo ${non_on_classes} |
/usr/bin/grep -w i.${class} > /dev/null
if [ $? -eq 0 ] ; then
#
# process_non_on_classes is called only once
# per non_on_class due to sort -u above.
#
process_non_on_classes ${class} \
${editablefilelist} \
$tmpdir/conflict_resolution/$un
continue;
else
nawk -v class=$class '$3 == class { print $2 }' \
$editablefilelist | sort -u > $classpk
if [ $(wc -l < $classpk) -ne 1 ] ; then
cat >&2 <<EOF
mkacr: The class script i.$class cannot be found in the pkgdefs common files
directory, and there is more than one package that uses it.
EOF
exit 1
fi
fi
pkgdir=$(cat $classpk)
if [ -s $pkgdir/i.$class ] ; then
mkdir -p $tmpdir/conflict_resolution/$un/$pkgdir
cp $pkgdir/i.$class \
$tmpdir/conflict_resolution/$un/$pkgdir
elif [ -s $pkgdir/i.${class}_$isa ] ; then
mkdir -p $tmpdir/conflict_resolution/$un/$pkgdir
cp $pkgdir/i.${class}_$isa \
$tmpdir/conflict_resolution/$un/$pkgdir/i.$class
else
print -u2 "mkacr: Can't find class script i.$class"
exit 1
fi
fi
done
cat $db >> $tmpdir/conflict_resolution/editable_file_db
if [ "$ACR_DEBUG" = "yes" ] ; then
mkdir $tmpdir/$un
mv $tmpdir/ps.* $tmpdir/$un
else
rm -fr $tmpdir/ps.*
fi
}
#
# Execution starts here
#
export LC_ALL=C
ACR_DEBUG=${ACR_DEBUG-no}
USAGE="Usage: $0 <workspace> <instruction-set-architecture> <archive-dir>"
if [ $# -ne 3 ] ; then
print -u2 $USAGE
exit 1
fi
workspace=$1
isa=$2
if [ -d $workspace/pkgdefs ] ; then
:
elif [ -d $workspace/usr/src/pkgdefs ] ; then
workspace=$workspace/usr/src
else
print -u2 $USAGE
exit 1
fi
if [ ! -d $3 ] ; then
print -u2 $USAGE
exit 1
fi
archivedir=$(cd $3; pwd)
if [ "$isa" != "sparc" -a "$isa" != "i386" ] ; then
print -u2 "$0: Instruction set architecture must be \"sparc\" or \"i386\""
exit 1
fi
#
# temporary file scorecard, in order of appearance:
# (Temporary files that begin with "ps." are pass-specific. mkacr
# generates its database in multiple passes: one for each pkgdef
# directory in the ON source base. Currently there are 2:
# usr/src/pkgdefs and usr/src/realmode/pkgdefs. The temp files
# that begin with "ps." are deleted at the end of each pass.)
#
# ps.pkglist package names, starting with core pkgs
#
# ps.allpkglist pass 1 additional package list
#
# ps.pkgcopy pass 1 temporary copy of core package names
#
# ps.allclasslist list of all classes
#
# ps.allclasslist_t preliminary version of ps.allclasslist
#
# ps.editablefilelist list of editable files.
#
# ps.db, tmpdb temporary files used in construction of editable_file_db
#
# ps.cpioerr stderr from cpio.
#
tmpdir=$(mktemp -t -d mkacr.XXXXXX)
if [ -z "$tmpdir" ] ; then
print -u2 "mktemp failed to produce output; aborting"
exit 1
fi
if [ ! -d "$tmpdir" ] ; then
print -u2 "$0: Couldn't create temporary directory $tmpdir"
exit 1
fi
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Temporary files will be left in $tmpdir"
else
trap 'rm -rf $tmpdir' 0
fi
cpioerr=$tmpdir/ps.cpioerr
pkglist=$tmpdir/ps.pkglist
allpkglist=$tmpdir/ps.allpkglist
pkgcopy=$tmpdir/ps.pkgcopy
allclasslist=$tmpdir/ps.allclasslist
allclasslist_t=$tmpdir/ps.allclasslist_t
editablefilelist=$tmpdir/ps.editablefilelist
db=$tmpdir/ps.db
tmpdb=$tmpdir/ps.tmpdb
classpk=$tmpdir/ps.classpk
#
# set up the list of corepkgs and bfs-incompatible classes for the
# processing of the usr/src/pkgdefs directory
#
corepkgs="
SUNWcar.*
SUNWcakr.*
SUNWckr
SUNWcsd
SUNWcsr
SUNWcsu
SUNWcsl
SUNWcslr
SUNWkvm.*
"
bfu_incompatible_classes="
i.initd
"
non_on_classes="
i.CONFIG.prsv
i.CompCpio
i.awk
i.build
i.ipsecalgs
i.kcfconf
i.kmfconf
i.pkcs11conf
i.sed
"
process_pkgdefs_directory $workspace/pkgdefs std
if [[ -d $workspace/../closed/pkgdefs && "$CLOSED_IS_PRESENT" != no ]]; then
process_pkgdefs_directory $workspace/../closed/pkgdefs std-closed
fi
#
# set up the list of corepkgs and bfs-incompatible classes for the
# processing of the usr/src/realmode/pkgdefs directory
#
corepkgs="SUNWrmodr"
bfu_incompatible_classes=""
if [ -d $workspace/realmode/pkgdefs ] ; then
process_pkgdefs_directory $workspace/realmode/pkgdefs realmode
fi
if [ "$ACR_DEBUG" = "yes" ] ; then
print "Final processing: Create bfu conflict resolution archive"
fi
print "Creating conflict resolution archive: \c";
(cd $tmpdir
find conflict_resolution -print | cpio -ocB 2>$cpioerr |
gzip -c > $archivedir/conflict_resolution.gz ) || exit 1
awk '/^[0-9]* blocks$/ { blocks=1; print $0; next }
{ print $0 > "/dev/stderr" }
END {
if (!blocks) {
# Terminate the "print \c" line above.
print
print "No cpio block count" > "/dev/stderr"
}
}' <$cpioerr
exit 0