1#!/usr/bin/perl -w 2# IBM_PROLOG_BEGIN_TAG 3# This is an automatically generated prolog. 4# 5# bos52S src/bos/usr/sbin/install/insttools/makebff.pl 1.9.1.1 6# 7# Licensed Materials - Property of IBM 8# 9# COPYRIGHT International Business Machines Corp. 2003,2008 10# All Rights Reserved 11# 12# US Government Users Restricted Rights - Use, duplication or 13# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 14# 15# IBM_PROLOG_END_TAG 16# @(#)10 1.9.1.1 src/bos/usr/sbin/install/insttools/makebff.pl, cmdmkinstallp, bos52S, s2008_51A3 9/30/08 16:43:46 17use strict; 18 19my $CONFIGDIR="./.info"; # Directory containing all the fileset config files 20my $MESG=""; # Message for dspmsg 21my $STRING=""; # Status string 22 23# Maps associating filesets with their variables 24my %bosboot=(); # BOS Boot flag 25my %description=(); 26my %laf=(); # License Agreement File 27my %lar=(); # License Agreement Requirement 28my %requisite=(); 29my %version=(); # VRMF 30 31# Globals 32my $configFileBlocks=0; # Number of blocks for all cfg files (for INSTWORK) 33my @copyrights=(); # CRs go into the archive first, so keep a list of them 34my $fileset=""; 35my $filesetDir=""; # Part of the dir for storing update fileset liblpp.a 36my $hasRoot=0; # Keep track of whether or not we have a ROOT part 37my $hasRootFiles=0; # Keep track of whether or not we have ROOT part files 38my $hasUsrFiles=0; # Keep track of whether or not we have USR part files 39my $instrootDir=""; # Part of the dir for storing ROOT part files in an update's liblpp.a 40my @liblpp=(); # Update pkgs may have more than one liblpp 41my @listFileLine=(); # One line of list file data 42my $listFileLineNum=0; 43my $numFiles=0; # Total number of files for this package 44my $package=""; 45my $packageType=""; # I - regular, S - update 46my $packageVersion=""; # Pkg VRMF 47my %rootSize=(); # Maps ROOT part directories with their sizes for each fileset 48my %size=(); # Maps USR part directories with their sizes for each fileset 49my $symlinkKey=0; 50my @updateLibDirs=(); # Need the liblpp.a directories for listing in the backup tree 51my $vrmfDir=""; # Part of the dir for storing update fileset liblpp.a 52 53my @usrFilesForArchive=(); # USR part config files from all filesets for the non-update liblpp.a 54my @rootFilesForArchive=(); # ROOT part config files from all filesets for the non-update liblpp.a 55my @configFiles=( 56 "al","cfginfo","cfgfiles","config","config_u","copyright","err","fixdata", 57 "inventory","namelist","odmadd","odmdel","post_i","post_u","pre_d","pre_i", 58 "pre_rm","pre_u","productid","README","rm_inv","size","trc","unconfig","unconfig_u", 59 "unodmadd","unpost_i","unpost_u","unpre_i","unpre_u" 60); 61 62mkdir("./usr",0755) if ( ! -d "./usr"); 63symlink("/etc","./etc") if ( ! -d "./etc"); 64symlink("/var","./var") if ( ! -d "./var"); 65symlink("/opt","./opt") if ( ! -d "./opt"); 66symlink("/usr/local","./usr/local") if ( ! -s "./usr/local"); 67 68# Open our lpp_name for writing data based on package info 69open (LPP,">lpp_name"); 70 71unless ( -f "$CONFIGDIR/list" ){ 72 $STRING="0503-884 makebff: $CONFIGDIR/list does not exist.\n"; 73 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 1 "$STRING"); 74 die "$MESG"; 75} 76 77# Collect package info one colon-delimitted line at a time 78open(LIST,"$CONFIGDIR/list"); 79while (<LIST>){ 80 $listFileLineNum++; 81 chomp; # Get rid of the newline 82 next if (/^#/ || /^$/); # Skip if we have a blank line 83 84 @listFileLine=split(/:/,$_); 85 if ($package eq ""){ 86 $package=$listFileLine[0]; 87 $packageVersion=$listFileLine[1]; 88 if ($listFileLine[2]){ 89 $packageType=$listFileLine[2]; 90 } else { 91 $packageType="I"; 92 } 93 printf(LPP "4 R %s %s {\n",$packageType,$package); 94 $STRING="processing %s %s %s package\n"; 95 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 2 "$STRING" "$package" "$packageVersion" "$packageType"); 96 printf "$MESG" 97 } elsif (/^\*/){ # If the line starts with a '*', we have a requisite 98 if ($fileset){ 99 $requisite{$fileset}="@listFileLine"; 100 } else { 101 $STRING="0503-885 makebff: Requisite line for empty fileset in $CONFIGDIR/list. (%ld)\n"; 102 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 3 "$STRING" "$listFileLineNum"); 103 die "$MESG"; 104 } 105 } elsif (/^LAR/){ # If the line starts with 'LAR', we have a LAR 106 if ($fileset){ 107 $lar{$fileset}="@listFileLine"; 108 } else { 109 $STRING="0503-886 makebff: License agreement line for empty fileset in $CONFIGDIR/list. (%ld)\n"; 110 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 4 "$STRING" "$listFileLineNum"); 111 die "$MESG"; 112 } 113 } elsif (/^LAF/){ # If the line starts with 'LAF', we have a LAF. Ha. 114 if ($fileset){ 115 $laf{$fileset}="@listFileLine"; 116 } else { 117 $STRING="0503-887 makebff: License file line for empty fileset in $CONFIGDIR/list. (%ld)\n"; 118 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 5 "$STRING" "$listFileLineNum"); 119 die "$MESG"; 120 } 121 } else { 122 # If we have a fileset name already (and it's not the name at the beginning 123 # of this line), then we need to process this fileset with the data we 124 # collected last time through the loop. The last fileset of the package gets 125 # processed when we exit the while loop. 126 if ($fileset && $fileset ne $listFileLine[0]){ 127 &FilesetInfo; 128 } 129 $fileset=$listFileLine[0]; 130 $version{$fileset}=$listFileLine[1]; 131 $description{$fileset}=$listFileLine[2]; 132 $bosboot{$fileset}=$listFileLine[3]; 133 134 $STRING="processing %s %s fileset\n"; 135 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 7 "$STRING" "$fileset" "$version{$fileset}"); 136 printf "$MESG"; 137 138 # Copyrights have to go into the liblpp.a first, so keep a 139 # separate array of them handy. 140 if ( -f "$CONFIGDIR/$fileset.copyright"){ 141 push @copyrights, "$CONFIGDIR/$fileset.copyright"; 142 } 143 144 if ( -f "$CONFIGDIR/$fileset.al" ){ 145 $hasUsrFiles=1; 146 %size=&MakeInv("$CONFIGDIR/$fileset.al","$CONFIGDIR/$fileset.inventory"); 147 } 148 149 # Check for ROOT part 150 if ( -f "$CONFIGDIR/.create_root" ){ 151 $hasRoot=1; 152 153 if ( -f "$CONFIGDIR/root/$fileset.al" ){ 154 $hasRootFiles=1; 155 %rootSize=&MakeInv("$CONFIGDIR/root/$fileset.al","$CONFIGDIR/root/$fileset.inventory"); 156 } 157 } 158 } 159} 160&FilesetInfo; 161printf(LPP "}\n"); 162close(LPP); 163close(LIST); 164 165mkdir("./usr/lpp",0755) if ( ! -d "./usr/lpp"); 166mkdir("./usr/lpp/$package",0755) if ( ! -d "./usr/lpp/$package"); 167 168# create big liblpp.a for install packages, and fileset liblpp.a's for update packages 169if ($packageType eq "I"){ 170 $STRING="creating ./usr/lpp/$package/liblpp.a\n"; 171 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 9 "$STRING"); 172 printf "$MESG"; 173 unlink("./usr/lpp/$package/liblpp.a"); 174 system("ar -crlg ./usr/lpp/$package/liblpp.a @copyrights @usrFilesForArchive"); 175 176 if ( $hasRoot ){ 177 mkdir("./usr/lpp/$package/inst_root",0755) if ( ! -d "./usr/lpp/$package/inst_root"); 178 unlink("./usr/lpp/$package/inst_root/liblpp.a"); 179 system("ar -crlg ./usr/lpp/$package/inst_root/liblpp.a @rootFilesForArchive"); 180 } 181} else { 182 # The update fileset.a files are created in sub FilesetInfo 183 foreach my $fileset (keys %version){ 184 $filesetDir=sprintf("./usr/lpp/%s/%s",$package,$fileset); 185 mkdir($filesetDir,0755) if ( ! -d $filesetDir); 186 push @updateLibDirs, $filesetDir; 187 188 $vrmfDir=sprintf("./usr/lpp/%s/%s/%s",$package,$fileset,$version{$fileset}); 189 mkdir($vrmfDir,0755) if ( ! -d $vrmfDir); 190 push @updateLibDirs, $vrmfDir; 191 192 $STRING="copying $CONFIGDIR/%s.a to %s/liblpp.a\n"; 193 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 10 "$STRING" "$fileset" "$vrmfDir"); 194 printf "$MESG"; 195 system("cp $CONFIGDIR/$fileset.a $vrmfDir/liblpp.a"); 196 push @liblpp, "$vrmfDir/liblpp.a"; 197 198 if ($hasRoot){ 199 $instrootDir=sprintf("./usr/lpp/%s/%s/%s/inst_root",$package,$fileset,$version{$fileset}); 200 mkdir($instrootDir,0755) if ( ! -d $instrootDir); 201 push @updateLibDirs, $instrootDir; 202 203 system("cp $CONFIGDIR/root/$fileset.a $instrootDir/liblpp.a"); 204 push @liblpp, "$instrootDir/liblpp.a"; 205 } 206 } 207} 208 209mkdir("./tmp",0755) if ( ! -d "./tmp"); 210$STRING="creating ./tmp/%s.%s.bff\n"; 211$MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 11 "$STRING" "$package" "$packageVersion"); 212printf "$MESG"; 213 214# ./usr/lpp/<pkg> needs to immediately follow lpp_name 215open(TT,"|backup -irqpf ./tmp/$package.$packageVersion.bff -b1"); 216print TT "./\n"; 217print TT "./lpp_name\n"; 218print TT "./usr\n"; 219print TT "./usr/lpp\n"; 220print TT "./usr/lpp/$package\n"; 221 222if ($packageType eq "I"){ 223 print TT "./usr/lpp/$package/liblpp.a\n"; 224 if ( $hasRoot ){ 225 print TT "./usr/lpp/$package/inst_root\n"; 226 print TT "./usr/lpp/$package/inst_root/liblpp.a\n"; 227 } 228} else { 229 # Backup all the libdirs (may be multiple for update packages) 230 foreach my $libDir (@updateLibDirs){ 231 print TT "$libDir\n"; 232 } 233 234 # Backup all liblpp.a files (may be multiple for update packages) 235 foreach my $archive (@liblpp){ 236 print TT "$archive\n"; 237 } 238} 239 240# Backup all files in each fileset's .al, and the LAFs if they exist 241foreach my $fileset (keys %version){ 242 if ( $hasUsrFiles ){ 243 my $applyListFile="$CONFIGDIR/$fileset.al"; 244 open(AL,"<$applyListFile"); 245 while (<AL>){ 246 print TT $_; 247 } 248 close(AL); 249 } 250 251 if ( $hasRootFiles ){ 252 my $rootAL="$CONFIGDIR/root/$fileset.al"; 253 open(RAL,"<$rootAL"); 254 while (<RAL>){ 255 print TT $_; 256 } 257 close(RAL); 258 } 259 260 # Put LAFs in the backup 261 if ($laf{$fileset}) { 262 my @lafs=split (/;/, $laf{$fileset}); 263 foreach my $laf (@lafs) { 264 $laf =~ s/^LAF//g; 265 $laf =~ s/^<.._..>//; 266 print TT "." . $laf . "\n"; 267 } 268 } 269} 270 271close(TT); 272exit(0); 273 274 275# Gather fileset-specific info. Called for each fileset in this package. 276sub FilesetInfo { 277 # some fileset-specific vars 278 my $extraSizeFile=""; 279 my @lafs=(); 280 my @reqs=(); 281 my $rootSizeFile=""; 282 my @rootConfigFiles=(); 283 my $usrSizeFile=""; 284 my @usrConfigFiles=(); 285 my $totalSize=0; 286 287 # stat output vars 288 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 289 $atime, $mtime, $ctime, $blksize, $blocks); 290 291 $usrSizeFile = "$CONFIGDIR/$fileset.size"; 292 $rootSizeFile = "$CONFIGDIR/root/$fileset.size" if ( $hasRootFiles ); 293 $extraSizeFile = "$CONFIGDIR/$fileset.upsize" if ( -f "$CONFIGDIR/$fileset.upsize"); 294 $extraSizeFile = "$CONFIGDIR/$fileset.insize" if ( -f "$CONFIGDIR/$fileset.insize"); 295 296 # Print fileset info to lpp_name. Set correct header if we have a ROOT part. 297 if ( $hasRoot ){ 298 printf(LPP "%s %s 01 %s B en_US %s\n", 299 $fileset,$version{$fileset},$bosboot{$fileset},$description{$fileset}); 300 } else { 301 printf(LPP "%s %s 01 %s U en_US %s\n", 302 $fileset,$version{$fileset},$bosboot{$fileset},$description{$fileset}); 303 } 304 printf(LPP "[\n"); 305 306 # Print reqs on separate lines in lpp_name (if we have any) 307 if ($requisite{$fileset}){ 308 # If the line starts with "*." read in the lines of the file 309 if ($requisite{$fileset} =~ m/^\*\./) { 310 my $req = $requisite{$fileset}; 311 $req =~ s/^\*//; 312 open(RF,"<$req"); 313 while (<RF>){ 314 print LPP $_; 315 } 316 close(RF); 317 } else { 318 # Else process the requisite list 319 @reqs=split (/;/, $requisite{$fileset}); 320 foreach my $req (@reqs){ 321 printf(LPP "%s\n",$req); 322 } 323 } 324 } 325 printf(LPP "%%\n"); 326 327 # Open our fileset.size file for writing (data is dup'd in lpp_name). 328 open(SF,">$usrSizeFile"); 329 if ( $hasRootFiles ){ 330 open(RSF,">$rootSizeFile"); 331 } 332 333 # If we don't have an extra size file, just use the size data stored in %size. 334 # We have to put this data in the lpp_name AND fileset.size file. 335 if ($extraSizeFile eq ""){ 336 foreach my $dir (sort keys %size){ 337 printf(LPP "%s %d\n",$dir,$size{$dir}); 338 printf(SF "%s %d\n",$dir,$size{$dir}); 339 $totalSize+=$size{$dir}; 340 } 341 } 342 # Otherwise, include our extra size file's data 343 else{ 344 my @extraSizeFileEntryParts=(); 345 my $extraSizeFileEntryPath=""; 346 my $extraSizeFileEntryPathNotFound=1; 347 my $extraSizeFileEntrySize=0; 348 349 foreach my $dir (sort keys %size){ 350 open (FUSIZE, $extraSizeFile); 351 while (<FUSIZE>){ 352 $extraSizeFileEntryPathNotFound = 1; 353 @extraSizeFileEntryParts=split(/ /, $_); 354 $extraSizeFileEntryPath=$extraSizeFileEntryParts[0]; 355 $extraSizeFileEntrySize=$extraSizeFileEntryParts[1]; 356 357 if ($dir eq "$extraSizeFileEntryPath"){ 358 printf(LPP "%s %d\n",$dir,$size{$dir}+$extraSizeFileEntrySize); 359 printf(SF "%s %d\n",$dir,$size{$dir}+$extraSizeFileEntrySize); 360 $totalSize+=$size{$dir}; 361 $extraSizeFileEntryPathNotFound = 0; 362 last; 363 } 364 } 365 close (FUSIZE); 366 if ($extraSizeFileEntryPathNotFound){ 367 printf(LPP "%s %d\n",$dir,$size{$dir}); 368 printf(SF "%s %d\n",$dir,$size{$dir}); 369 $totalSize+=$size{$dir}; 370 } 371 } 372 373 open (FUSIZE, $extraSizeFile); 374 while (<FUSIZE>){ 375 @extraSizeFileEntryParts=split(/ /, $_); 376 $extraSizeFileEntryPath=$extraSizeFileEntryParts[0]; 377 $extraSizeFileEntryPathNotFound = 1; 378 $extraSizeFileEntrySize=$extraSizeFileEntryParts[1]; 379 380 foreach my $dir (sort keys %size){ 381 if ($dir eq "$extraSizeFileEntryPath"){ 382 $extraSizeFileEntryPathNotFound = 0; 383 } 384 } 385 if ($extraSizeFileEntryPathNotFound){ 386 printf(LPP "%s %d\n", "$extraSizeFileEntryPath", $extraSizeFileEntrySize); 387 printf(SF "%s %d\n", "$extraSizeFileEntryPath", $extraSizeFileEntrySize); 388 $totalSize+=$extraSizeFileEntrySize; 389 } 390 } 391 close (FUSIZE); 392 } 393 394 # Gather ROOT part size info (there's not insize/upsize for ROOT parts) 395 if ( $hasRootFiles ){ 396 foreach my $dir (sort keys %rootSize){ 397 printf(LPP "%s %d\n",$dir,$rootSize{$dir}); 398 printf(RSF "%s %d\n",$dir,$rootSize{$dir}); 399 $totalSize+=$rootSize{$dir}; 400 } 401 } 402 403 # Gather USR part size info for each existing config file 404 foreach my $ext (@configFiles){ 405 my $configFile=""; 406 407 if ($ext eq "README"){ 408 $configFile="$CONFIGDIR/lpp.README"; 409 } elsif ($ext eq "productid") { 410 $configFile="$CONFIGDIR/productid"; 411 } else { 412 $configFile="$CONFIGDIR/$fileset.$ext"; 413 } 414 if ( -f $configFile ){ 415 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 416 $atime, $mtime, $ctime, $blksize, $blocks) = stat "$configFile"; 417 $configFileBlocks+=$blocks; 418 419 # Dont push the copyright on - it has to be first in the liblpp.a 420 next if ($ext eq "copyright"); 421 push @usrConfigFiles, $configFile; 422 } 423 } 424 425 # Gather ROOT part size info for root config files 426 if ( $hasRoot ){ 427 # Gather size info for each existing config file 428 foreach my $ext (@configFiles){ 429 my $configFile=""; 430 $configFile="$CONFIGDIR/root/$fileset.$ext"; 431 432 if ( -f $configFile ){ 433 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 434 $atime, $mtime, $ctime, $blksize, $blocks) = stat "$configFile"; 435 $configFileBlocks+=$blocks; 436 437 push @rootConfigFiles, $configFile; 438 } 439 } 440 } 441 442 # Archive the config files 443 if ($packageType=~/^S/){ 444 # SAVESPACE is what's needed if this update is removed 445 printf(LPP "/usr/lpp/SAVESPACE %d\n",$totalSize); 446 printf(SF "/usr/lpp/SAVESPACE %d\n",$totalSize); 447 448 $STRING="creating $CONFIGDIR/%s.a\n"; 449 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 6 "$STRING" "$fileset"); 450 printf "$MESG"; 451 unlink("$CONFIGDIR/$fileset.a"); 452 system("ar -crlg $CONFIGDIR/$fileset.a @usrConfigFiles"); 453 if ( $hasRoot ){ 454 unlink("$CONFIGDIR/root/$fileset.a"); 455 system("ar -crlg $CONFIGDIR/root/$fileset.a @rootConfigFiles"); 456 } 457 } else { 458 # All of this fileset's config files will be archived with 459 # other filsets' config files (if they exist) 460 push @usrFilesForArchive, @usrConfigFiles; 461 462 if ( $hasRoot ){ 463 push @rootFilesForArchive, @rootConfigFiles; 464 } 465 } 466 467 # Assuming 1 block per file for objrepos, and equal perm/temp space for INSTWORK 468 if ( $hasRoot ){ 469 printf(LPP "/etc/objrepos $numFiles\n"); 470 471 if ($hasRootFiles) { 472 printf(RSF "/etc/objrepos $numFiles\n"); 473 printf(RSF "INSTWORK $configFileBlocks $configFileBlocks\n"); 474 } 475 } 476 printf(LPP "/usr/lib/objrepos $numFiles\n"); 477 printf(LPP "INSTWORK $configFileBlocks $configFileBlocks\n"); 478 printf(SF "/usr/lib/objrepos $numFiles\n"); 479 printf(SF "INSTWORK $configFileBlocks $configFileBlocks\n"); 480 481 # Put LAFs/LAR in lpp_name 482 if ($laf{$fileset}) { 483 @lafs=split (/;/, $laf{$fileset}); 484 foreach my $laf (@lafs) { 485 my $lafString = $laf; 486 $laf =~ s/^LAF//g; 487 $laf =~ s/^<.._..>//; 488 if ( -f ".$laf") { 489 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 490 $atime, $mtime, $ctime, $blksize, $blocks) = stat ".$laf"; 491 492 printf(LPP "%s %d\n", $lafString, $blocks); 493 } 494 } 495 } 496 if ($lar{$fileset}) { 497 printf(LPP "%s 0\n", $lar{$fileset}); 498 } 499 500 printf(LPP "%%\n"); 501 502 # Put supersede info in lpp_name 503 if ( -f "$CONFIGDIR/$fileset.supersede") { 504 open (SUPER, "<$CONFIGDIR/$fileset.supersede"); 505 while (<SUPER>) { 506 printf(LPP $_); 507 } 508 close (SUPER); 509 } 510 printf(LPP "%%\n"); 511 printf(LPP "%%\n"); 512 printf(LPP "]\n"); 513 close (SF); 514 if ( $hasRootFiles ){ 515 close (RSF); 516 } 517} 518 519 520# Gather file-specific data and create .inventory for each fileset in this package. 521sub MakeInv { 522 # The .al and .inventory filenames are passed in 523 my ($al, $inv)=@_; 524 525 my $dir=""; # Dir name for keeping track of dir size reqs 526 my %dirSize=(); # Map associating directories and their size 527 my $fileName=""; # Filename for .inventory 528 my %gname=(); # Map group names/gids 529 my @ilist=(); # Stores files to be listed in the .inventory 530 my $key=""; # Key for referencing files 531 my $passwd=""; # Needed for getgrent 532 my $sum=""; # Output of the sum command 533 my $sysname=""; # Needed for getgrent 534 my $type=""; # File/Link/Dir 535 my %uname=(); # Map user names/uids 536 537 # stat output vars 538 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 539 $atime, $mtime, $ctime, $blksize, $blocks); 540 541 # .inventory related 542 my (%name, %owner, %group, %mode, %type, %class, %size, %checksum); 543 544 # link related 545 my (%hardlinkList, %nlink, %target); 546 547 # Maps associating files and their attributes 548 %name=(); 549 %owner=(); 550 %group=(); 551 %mode=(); 552 %type=(); 553 %class=(); 554 %size=(); 555 %checksum=(); 556 %hardlinkList=(); # List of hard links to a file 557 %nlink=(); # Number of hard links to a file 558 %target=(); # Symlink target 559 560 # Create maps of gids to groups and uids to users 561 while (($sysname, $passwd, $gid) = getgrent){ 562 next if ($sysname =~ /^\+/); # skip NIS password lines (begin with plus sign) 563 $gname{$gid}=$sysname; 564 } 565 endgrent(); 566 while (($sysname, $passwd, $uid) = getpwent){ 567 next if ($sysname =~ /^\+/); # skip NIS password lines (begin with plus sign) 568 $uname{$uid}=$sysname; 569 } 570 endpwent(); 571 572 # Ensure a uid/gid of 0 is root/system 573 $gname{0}="system"; 574 $uname{0}="root"; 575 576 open(AL,"<$al"); 577 open(INV,">$inv"); 578 579 unlink("$al.withoutlinks"); 580 open(ALWOL,">$al.withoutlinks"); # Need to strip hard links out of the applylist 581 while (<AL>){ 582 chomp; 583 $dir=$_; 584 if (-l){ 585 $type="SYMLINK"; 586 $dir=~s?/[^/]*$??; 587 } elsif (-d){ 588 $type="DIRECTORY"; 589 } elsif (-f){ 590 $type="FILE"; 591 $dir=~s?/[^/]*$??; 592 } else { 593 $STRING="no such file: %s\n"; 594 $MESG=qx(/usr/bin/dspmsg -s 21 cmdinstl_e.cat 8 "$STRING" "$_"); 595 printf(STDERR "$MESG"); 596 next; 597 } 598 599 # Increment our file count 600 $numFiles++; 601 602 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, 603 $atime, $mtime, $ctime, $blksize, $blocks) = lstat "$_"; 604 if ($type eq "SYMLINK"){ 605 $key=$symlinkKey++; 606 } else { 607 $key="$dev.$ino"; 608 } 609 610 # If we have this key already, then make a hardlink list 611 if ($name{$key} && ($nlink > 1) && ($type eq "FILE")){ 612 if ($hardlinkList{$key}){ 613 $hardlinkList{$key} .= "," . substr $_, 1; 614 } else { 615 $hardlinkList{$key} = substr $_, 1; 616 } 617 } else { 618 printf(ALWOL "%s\n", $_); 619 push(@ilist,$key); 620 $name{$key}=$_; 621 $owner{$key}=$uname{$uid}; 622 $group{$key}=$gname{$gid}; 623 $mode{$key}=$mode; 624 $type{$key}=$type; 625 $class{$key}="apply,inventory,$fileset"; 626 $size{$key}=$size; 627 if ($type eq "FILE"){ 628 $sum=`/usr/bin/sum $_`; 629 $sum=~s/ +/ /g; 630 ($a, $b)=(split(/ /,$sum))[0,1]; 631 $checksum{$key}=sprintf("\"%s %s \"",$a,$b); 632 } elsif ($type eq "SYMLINK"){ 633 $target{$key}=readlink($_); 634 } 635 $hardlinkList{$key}=""; 636 $dirSize{substr $dir, 1}+=$blocks; 637 } 638 } 639 640 # Print out the inventory file; spacing and order is done 641 # on purpose to look like BOS install images. 642 foreach my $key (@ilist){ 643 $fileName=$name{$key}; 644 $fileName=~s/^.//; 645 printf(INV "%s:\n",$fileName); 646 if ($type{$key} eq "FILE" || $type{$key} eq "DIRECTORY"){ 647 printf(INV " owner = %s\n",$owner{$key}); 648 printf(INV " group = %s\n",$group{$key}); 649 printf(INV " mode = %o\n",$mode{$key} & 07777); 650 } 651 printf(INV " type = %s\n",$type{$key}); 652 if ($hardlinkList{$key}){ 653 printf(INV " links = %s\n",$hardlinkList{$key}); 654 } 655 printf(INV " class = %s\n",$class{$key}); 656 if ($type{$key} eq "FILE"){ 657 printf(INV " size = %d\n",$size{$key}); 658 printf(INV " checksum = %s\n",$checksum{$key}); 659 } elsif ($type{$key} eq "SYMLINK"){ 660 printf(INV " target = %s\n",$target{$key}); 661 } 662 printf(INV "\n"); 663 } 664 close(AL); 665 close(ALWOL); 666 close(INV); 667 668 # Get rid of our original apply list in favor of the non-hardlink'd one 669 unlink($al); 670 rename("$al.withoutlinks", $al); 671 672 return %dirSize; 673} 674