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