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