1#************************************************************** 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19# 20#************************************************************** 21 22 23 24package installer::packagepool; 25 26use Digest::MD5; 27use installer::exiter; 28use installer::globals; 29use installer::logger; 30use installer::pathanalyzer; 31use installer::worker; 32 33###################################################### 34# Checking the md5sum of a file 35###################################################### 36 37sub get_md5sum 38{ 39 my ($filename) = @_; 40 41 open(FILE, "<$filename") or die "ERROR: Can't open $filename for creating file hash"; 42 binmode(FILE); 43 my $digest = Digest::MD5->new->addfile(*FILE)->hexdigest; 44 close(FILE); 45 46 return $digest; 47} 48 49#################################################### 50# Setting a unique sessionid to identify this 51# packaging process. 52#################################################### 53 54sub set_sessionid 55{ 56 my $pid = $$; # process id 57 my $timer = time(); # time 58 $installer::globals::sessionid = $pid . $timer; 59 $installer::globals::sessionidset = 1; 60 $installer::logger::Lang->print("\n"); 61 $installer::logger::Lang->print("Pool: Setting session id: $installer::globals::sessionid.\n"); 62} 63 64#################################################### 65# Setting and creating pool path. 66#################################################### 67 68sub set_pool_path 69{ 70 $installer::globals::unpackpath =~ s/\Q$installer::globals::separator\E\s*$//; # removing ending slashes and backslashes 71 $installer::globals::poolpath = $installer::globals::unpackpath . $installer::globals::separator . "pool_" . $installer::globals::packageformat; 72 installer::systemactions::create_directory($installer::globals::poolpath); 73 $installer::globals::poolpathset = 1; 74} 75 76#################################################### 77# Comparing the content of two epm files. 78#################################################### 79 80sub compare_epm_content 81{ 82 my ($oldcontent, $newcontent) = @_; 83 84 my $identical = 1; 85 my $diffinfo = ""; 86 87 # Removing empty lines and files from $newcontent 88 89 my @newlocalcontent = (); 90 for ( my $i = 0; $i <= $#{$newcontent}; $i++ ) 91 { 92 if ( ${$newcontent}[$i] =~ /^\s*$/ ) { next; } # Removing empty lines from $newcontent. Empty lines are also not included into pcf file, from where $oldcontent was read. 93 if ( ${$newcontent}[$i] =~ /^\s*f\s+/ ) { next; } # Ignoring files, they can contain temporary pathes 94 if (( ${$newcontent}[$i] =~ /^\s*%readme\s+/ ) || ( ${$newcontent}[$i] =~ /^\s*%license\s+/ )) { next; } # ignoring license and readme (language specific!) 95 my $oneline = ${$newcontent}[$i]; 96 $oneline =~ s/\s*$//; # Removing line ends. Also not included in old epm file, that is read from pcf file. 97 push(@newlocalcontent, $oneline); 98 } 99 100 my $oldmember = $#{$oldcontent} + 1; 101 my $newmember = $#newlocalcontent + 1; 102 103 # comparing the count 104 if ( $oldmember != $newmember ) 105 { 106 $identical = 0; 107 $installer::logger::Info->print("\n"); 108 $installer::logger::Info->print("...... changed length of EPM file\n"); 109 $diffinfo = "Pool: EPM, different line count: old epm file: $oldmember, new epm file: $newmember\n"; 110 push(@installer::globals::epmdifflist, $diffinfo); 111 } 112 113 # comparing the content line for line, so the order must not change 114 115 if ( $identical ) 116 { 117 for ( my $i = 0; $i <= $#{$oldcontent}; $i++ ) 118 { 119 if ( ${$oldcontent}[$i] ne $newlocalcontent[$i] ) 120 { 121 $identical = 0; 122 my $line = $i + 1; 123 $installer::logger::Info->print("\n"); 124 $installer::logger::Info->print("...... different content in EPM file\n"); 125 $diffinfo = "Pool: EPM, line $line changed from \"${$oldcontent}[$i]\" to \"$newlocalcontent[$i]\".\n"; 126 push(@installer::globals::epmdifflist, $diffinfo); 127 last; 128 } 129 } 130 } 131 132 return $identical; 133} 134 135#################################################### 136# Comparing the content of two pcf files. 137#################################################### 138 139sub compare_package_content 140{ 141 my ($oldcontent, $newcontent) = @_; 142 143 my $identical = 1; 144 my $infoline = ""; 145 146 my $oldmember = scalar keys %{$oldcontent}; 147 my $newmember = scalar keys %{$newcontent}; 148 149 # comparing the count 150 151 if ( $oldmember != $newmember ) 152 { 153 # Logging the difference 154 $identical = 0; 155 $installer::logger::Info->print("\n"); 156 $installer::logger::Info->printf("...... different number of files in packages. New number: %s, old number: %s\n", $newmember, $oldmember); 157 $infoline = "Different number of files in packages. New number: $newmember, old number: $oldmember\n"; 158 push(@installer::globals::pcfdiffcomment, $infoline); 159 } 160 161 # comparing the keys 162 163 if ( $identical ) 164 { 165 my $first = 1; 166 foreach my $dest ( keys %{$newcontent} ) 167 { 168 if ( ! exists($oldcontent->{$dest}) ) 169 { 170 $identical = 0; 171 $installer::logger::Info->print("\n") if $first; 172 $installer::logger::Info->printf("...... file only in one package (A): %s\n", $dest); 173 $infoline = "File only in existing pool package: $dest\n"; 174 push(@installer::globals::pcfdiffcomment, $infoline); 175 $first = 0; 176 } 177 } 178 179 # collecting all differences 180 if ( ! $identical ) 181 { 182 foreach my $dest ( keys %{$oldcontent} ) 183 { 184 if ( ! exists($newcontent->{$dest}) ) 185 { 186 $identical = 0; 187 $installer::logger::Info->print("\n") if $first; 188 $installer::logger::Info->printf("...... file only in one package (B): %s\n", $dest); 189 $infoline = "File only in new package: $dest\n"; 190 push(@installer::globals::pcfdiffcomment, $infoline); 191 $first = 0; 192 } 193 } 194 } 195 } 196 197 # comparing the checksum 198 199 if ( $identical ) 200 { 201 my $first = 1; 202 203 foreach my $dest ( keys %{$newcontent} ) 204 { 205 if ( $newcontent->{$dest}->{'md5sum'} ne $oldcontent->{$dest}->{'md5sum'} ) 206 { 207 $identical = 0; 208 if ( $first == 1 ) 209 { 210 $installer::logger::Info->print("\n"); 211 $first = 0; 212 } 213 $installer::globals::pcfdifflist{$dest} = 1; 214 $installer::logger::Info->printf("...... different file: %s\n", $dest); 215 # last; 216 } 217 218 if ( $installer::globals::iswindowsbuild ) 219 { 220 if ( $newcontent->{$dest}->{'uniquename'} ne $oldcontent->{$dest}->{'uniquename'} ) 221 { 222 $identical = 0; 223 $installer::globals::pcfdifflist{$dest} = 1; 224 $installer::logger::Info->print("\n"); 225 $installer::logger::Info->printf("...... different file: %s", $dest); 226 # last; 227 } 228 } 229 } 230 } 231 232 return $identical; 233} 234 235#################################################### 236# Calculating content of pcf file. 237#################################################### 238 239sub calculate_current_content 240{ 241 my ($filesarray, $packagename) = @_; 242 243 $installer::logger::Lang->print("\n"); 244 $installer::logger::Lang->add_timestamp("Calculating content for package content file ($packagename), start"); 245 246 my %globalcontent = (); 247 248 for ( my $i = 0; $i <= $#{$filesarray}; $i++ ) 249 { 250 my %onefilehash = (); 251 252 my $onefile = ${$filesarray}[$i]; 253 if ( ! $onefile->{'sourcepath'} ) { installer::exiter::exit_program("ERROR: No sourcepath found for file $onefile->{'gid'}", "calculate_current_content"); } 254 my $source = $onefile->{'sourcepath'}; 255 if ( $onefile->{'zipfilesource'} ) { $source = $onefile->{'zipfilesource'}; } 256 if ( ! -f $source ) { installer::exiter::exit_program("ERROR: Sourcefile not found: $source ($onefile->{'gid'})", "calculate_current_content"); } 257 258 # For Windows the unique name inside the cabinet file also has to be saved 259 my $uniquename = ""; 260 if ( $installer::globals::iswindowsbuild ) { $uniquename = $onefile->{'uniquename'};} 261 262 my $destination = $onefile->{'destination'}; 263 my $checksum = get_md5sum($source); 264 265 $onefilehash{'md5sum'} = $checksum; 266 $onefilehash{'uniquename'} = $uniquename; 267 268 if ( exists($globalcontent{$destination}) ) { installer::exiter::exit_program("ERROR: Destination not unique: $destination ($onefile->{'gid'})", "calculate_current_content"); } 269 $globalcontent{$destination} = \%onefilehash; 270 } 271 272 $installer::logger::Lang->print("\n"); 273 $installer::logger::Lang->add_timestamp("Calculating content for package content file ($packagename), start"); 274 275 return \%globalcontent; 276} 277 278#################################################### 279# Writing pcf file. 280#################################################### 281 282sub create_pcfcontent_file 283{ 284 my ($realpackagename, $md5sum, $filesize, $fullpackagename, $pkgversion, $epmfilecontent, $pcffilename) = @_; 285 286 my @content = (); 287 my $oneline = "PackageName: $realpackagename\n"; 288 push(@content, $oneline); 289 290 $oneline = "md5sum: $md5sum\n"; 291 push(@content, $oneline); 292 293 $oneline = "FileSize: $filesize\n"; 294 push(@content, $oneline); 295 296 $oneline = "FullPackageName: $fullpackagename\n"; 297 push(@content, $oneline); 298 299 $oneline = "PkgVersion: $pkgversion\n"; 300 push(@content, $oneline); 301 302 foreach my $dest (keys %{$installer::globals::newpcfcontent} ) 303 { 304 $oneline = "Files:\t$dest\t$installer::globals::newpcfcontent->{$dest}->{'md5sum'}\t$installer::globals::newpcfcontent->{$dest}->{'uniquename'}\n"; 305 push(@content, $oneline); 306 } 307 308 for ( my $i = 0; $i <= $#{$epmfilecontent}; $i++ ) 309 { 310 if ( ${$epmfilecontent}[$i] =~ /^\s*$/ ) { next; } # avoiding empty lines 311 if ( ${$epmfilecontent}[$i] =~ /^\s*f\s+/ ) { next; } # ignoring files, because they can contain temporary pathes 312 if (( ${$epmfilecontent}[$i] =~ /^\s*%readme\s+/ ) || ( ${$epmfilecontent}[$i] =~ /^\s*%license\s+/ )) { next; } # ignoring license and readme (language specific!) 313 $oneline = "EPM:\t${$epmfilecontent}[$i]"; 314 push(@content, $oneline); 315 } 316 317 installer::files::save_file($pcffilename, \@content); 318} 319 320####################################################### 321# Reading the content of the package content file. 322####################################################### 323 324sub read_pcf_content 325{ 326 my ($pcffilename) = @_; 327 328 my %allcontent = (); 329 my @epmfile = (); 330 my $realpackagename = ""; 331 332 my $content = installer::files::read_file($pcffilename); 333 334 for ( my $i = 0; $i <= $#{$content}; $i++ ) 335 { 336 my $line = ${$content}[$i]; 337 338 if ( $line =~ /^\s*PackageName\:\s*(.*?)\s*$/ ) 339 { 340 $realpackagename = $1; 341 $installer::globals::xpdpackageinfo{'RealPackageName'} = $realpackagename; 342 next; 343 } 344 345 if ( $line =~ /^\s*FullPackageName\:\s*(.*?)\s*$/ ) 346 { 347 $installer::globals::xpdpackageinfo{'FullPackageName'} = $1; 348 next; 349 } 350 351 if ( $line =~ /^\s*FileSize\:\s*(.*?)\s*$/ ) 352 { 353 $installer::globals::xpdpackageinfo{'FileSize'} = $1; 354 next; 355 } 356 357 if ( $line =~ /^\s*PkgVersion\:\s*(.*?)\s*$/ ) 358 { 359 $installer::globals::xpdpackageinfo{'PkgVersion'} = $1; 360 next; 361 } 362 363 if ( $line =~ /^\s*md5sum\:\s*(.*?)\s*$/ ) 364 { 365 $installer::globals::xpdpackageinfo{'md5sum'} = $1; 366 next; 367 } 368 369 if ( $line =~ /^\s*Files:\t(.+?)\t(.+?)\t(.*?)\s*$/ ) 370 { 371 my $destination = $1; 372 my $checksum = $2; 373 my $uniquename = $3; 374 375 my %onefilehash = (); 376 $onefilehash{'md5sum'} = $checksum; 377 $onefilehash{'uniquename'} = $uniquename; 378 379 $allcontent{$destination} = \%onefilehash; 380 next; 381 } 382 383 if ( $line =~ /^\s*EPM:\t(.*?)\s*$/ ) # A line can be empty in epm file 384 { 385 my $epmcontent = $1; 386 push(@epmfile, $epmcontent); 387 next; 388 } 389 } 390 391 if ( $realpackagename eq "" ) { installer::exiter::exit_program("ERROR: Real package name not found in pcf file: \"$pcffilename\"", "read_pcf_content"); } 392 393 return ($realpackagename, \%allcontent, \@epmfile); 394} 395 396#################################################### 397# Checking, if a specific package can be 398# created at the moment. 399#################################################### 400 401sub check_package_availability 402{ 403 my ($packagename) = @_; 404 405 my $package_is_available = 1; 406 407 my $checkfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.check"; 408 my $lockfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.lock"; 409 410 if (( -f $checkfilename ) || ( -f $lockfilename )) { $package_is_available = 0; } 411 412 return $package_is_available; 413} 414 415#################################################### 416# Check, if the existence of the check or lock 417# file requires an exit of packaging process. 418#################################################### 419 420sub check_pool_exit 421{ 422 my ( $lockfilename, $timecounter ) = @_; 423 424 # How old is this lock file? 425 my $timeage = installer::logger::get_file_age($lockfilename); 426 427 # if ( $timeage > 1800 ) # file is older than half an hour 428 if ( $timeage > 3600 ) # file is older than an hour 429 { 430 my $timestring = installer::logger::convert_timestring($timeage); 431 my $infoline = "\nPool: Attention: \"$lockfilename\" is too old ($timestring). Removing file!\n"; 432 $installer::logger::Info->print("\n"); 433 $installer::logger::Info->printf("... %s", $infoline); 434 $installer::logger::Lang->print("\n"); 435 $installer::logger::Lang->print($infoline); 436 unlink $lockfilename; 437 # installer::exiter::exit_program("ERROR: Waiting too long for removal of lock file \"$lockfilename\"", "check_pool_exit (packagepool)"); 438 } 439 else 440 { 441 my $filecontent = installer::files::read_file($lockfilename); 442 my $waittime = $timecounter * 10; 443 $waittime = installer::logger::convert_timestring($waittime); 444 my $infoline = "Pool: Warning: \"$lockfilename\" blocks this process for $waittime. Lock content: \"${$filecontent}[0]\"\n"; 445 $installer::logger::Info->print("\n"); 446 $installer::logger::Info->printf("... %s", $infoline); 447 $installer::logger::Lang->print("\n"); 448 $installer::logger::Lang->print($infoline); 449 } 450} 451 452############################################################################ 453# This function logs some information, that can be used to find 454# pool problems. 455############################################################################ 456 457sub log_pool_info 458{ 459 my ( $file_exists ) = @_; 460 461 my $infoline = ""; 462 463 # Content saved in 464 # $installer::globals::savelockfilecontent = installer::files::read_file($filename); 465 # $installer::globals::savelockfilename = $filename; 466 467 if ( $file_exists ) 468 { 469 $installer::logger::Lang->print("\n"); 470 $installer::logger::Lang->printf( 471 "Pool Problem: Lock file \"%s\" belongs to another process. This process has session id: %s.\n", 472 $installer::globals::savelockfilename, 473 $installer::globals::sessionid); 474 $installer::logger::Lang->print("Content of Lock file:\n"); 475 foreach my $line ( @{$installer::globals::savelockfilecontent} ) 476 { 477 $installer::logger::Lang->print($line); 478 } 479 } 480 else 481 { 482 $installer::logger::Lang->print("\n"); 483 $installer::logger::Lang->printf( 484 "Pool Problem: Lock file \"%s\" does not exist anymore (this process has session id: %s).\n", 485 $installer::globals::savelockfilename, 486 $installer::globals::sessionid); 487 } 488} 489 490############################################################################ 491# Checking, if this process is the owner of the lock file in the pool. 492# This can be determined by the Process ID, that is written at the 493# beginning of the first line into the lock file. 494############################################################################ 495 496sub process_is_owner 497{ 498 my ( $filename ) = @_; 499 500 my $process_is_owner = 0; 501 502 $installer::globals::savelockfilecontent = installer::files::read_file($filename); 503 $installer::globals::savelockfilename = $filename; 504 505 if ( ${$installer::globals::savelockfilecontent}[0] =~ /^\s*\Q$installer::globals::sessionid\E\s+/ ) { $process_is_owner = 1; } 506 507 return $process_is_owner; 508} 509 510#################################################### 511# Removing a package from installation set, if 512# there were pooling problems. 513#################################################### 514 515sub remove_package_from_installset 516{ 517 my ($newpackagepath) = @_; 518 519 $installer::logger::Lang->printf("Pool problem: Removing package \"%s\" from installation set!\n", 520 $newpackagepath); 521 522 if ( -f $newpackagepath ) { unlink $newpackagepath; } 523 if ( -d $newpackagepath ) { installer::systemactions::remove_complete_directory($newpackagepath, 1); } 524 525 # Keeping the content of @installer::globals::installsetcontent up to date. Removing the last package. 526 pop(@installer::globals::installsetcontent); 527} 528 529#################################################### 530# Check, if the package is in the pool and if 531# there are no changes in the package. 532#################################################### 533 534sub package_is_up_to_date 535{ 536 my ($allvariables, $onepackage, $packagename, $newepmcontent, $filesinpackage, $installdir, $subdir, $languagestringref) = @_; 537 538 $installer::logger::Info->printf("... checking pool package ...\n", $packagename); 539 540 installer::logger::include_header_into_logfile("Checking package in pool: $packagename"); 541 542 if ( ! $installer::globals::poolpathset ) { installer::packagepool::set_pool_path(); } 543 if ( ! $installer::globals::sessionidset ) { installer::packagepool::set_sessionid(); } 544 545 my $infoline = ""; 546 # Resetting some variables for this package 547 my $package_is_up_to_date = 0; 548 my $realpackagename = ""; 549 my $oldepmcontent = ""; 550 my $waited_for_check = 0; 551 my $waited_for_lock = 0; 552 $installer::globals::newpcfcontentcalculated = 0; 553 %installer::globals::pcfdifflist = (); 554 @installer::globals::pcfdiffcomment = (); 555 @installer::globals::epmdifflist = (); 556 557 # Reading the package content file, if this file exists (extension *.pcf) 558 my $filename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf"; 559 my $checkfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.check"; 560 my $lockfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.lock"; 561 # Saving name in global variable, so that this file can be removed somewhere else (at the end of "put_content_into_pool"). 562 $installer::globals::poolcheckfilename = $checkfilename; 563 $installer::globals::poollockfilename = $lockfilename; 564 565 my @checkfilecontent = ("$installer::globals::sessionid $installer::globals::product $$languagestringref $checkfilename"); # $$ is the process id 566 my @lockfilecontent = ("$installer::globals::sessionid $installer::globals::product $$languagestringref $lockfilename"); # $$ is the process id 567 568 # Waiting, step 1 569 # Checking, if another process checks this package at the moment 570 my $timecounter = 0; 571 while ( -f $checkfilename ) 572 { 573 $timecounter++; 574 575 # including an exit to enable creation of other packages 576 if (( $timecounter == 1 ) && ( ! exists($installer::globals::poolshiftedpackages{$packagename}) )) 577 { 578 $package_is_up_to_date = 3; # repeat this package later 579 return $package_is_up_to_date; 580 } 581 582 $infoline = "Pool: $checkfilename exists. WAITING 10 seconds ($timecounter).\n"; 583 if ( $timecounter == 1 ) 584 { 585 $installer::logger::Info->print("\n"); 586 } 587 $installer::logger::Info->printf("... %s", $infoline); 588 $installer::logger::Lang->print($infoline); 589 if ( $timecounter % 100 == 0 ) { check_pool_exit($checkfilename, $timecounter); } 590 sleep 10; # process sleeps 10 seconds 591 $waited_for_check = 1; 592 } 593 594 # Creating file, showing that this package is checked at the moment by this process. No other process can reach this. 595 installer::files::save_file($checkfilename, \@checkfilecontent); # Creating the Lock, to check this package. This blocks all other processes. 596 $installer::globals::processhaspoolcheckfile = 1; 597 598 # Check, if the Lock file creation was really successful 599 if ( ! -f $checkfilename ) 600 { 601 $infoline = "Pool problem: Pool lock file \"$checkfilename\" could not be created successfully or was removed by another process (A)!\n"; 602 $installer::logger::Lang->print($infoline); 603 log_pool_info(0); 604 $package_is_up_to_date = 4; # repeat this package 605 return $package_is_up_to_date; 606 } 607 608 if ( ! process_is_owner($checkfilename) ) 609 { 610 $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (A)!\n"; 611 $installer::logger::Lang->print($infoline); 612 log_pool_info(1); 613 $package_is_up_to_date = 4; # repeat this package 614 return $package_is_up_to_date; 615 } 616 617 $infoline = "Pool: Created file: $checkfilename\n"; 618 $installer::logger::Lang->print($infoline); 619 if ( $waited_for_check ) 620 { 621 $installer::logger::Info->printf("... %s", $infoline); 622 } 623 624 # Waiting, step 2 625 # Checking, if another process creates this package at the moment 626 $timecounter = 0; 627 while ( -f $lockfilename ) 628 { 629 $timecounter++; 630 $infoline = "Pool: $lockfilename exists. WAITING 10 seconds ($timecounter).\n"; 631 if ( $timecounter == 1 ) 632 { 633 $installer::logger::Info->print("\n"); 634 } 635 $installer::logger::Info->printf("... %s", $infoline); 636 $installer::logger::Lang->print($infoline); 637 if ( $timecounter % 100 == 0 ) { check_pool_exit($lockfilename, $timecounter); } 638 sleep 10; # process sleeps 10 seconds 639 $waited_for_lock = 1; 640 } 641 642 # No lock file exists, therefore no process creates this package at the moment. Check can be done now. 643 if ( $waited_for_lock ) 644 { 645 $installer::logger::Info->printf("... Pool: Proceeding, %s was removed.\n", $lockfilename); 646 } 647 648 my $package_already_exists = 0; 649 650 if ( -f $filename ) 651 { 652 # Calculating content for pcf file 653 $installer::globals::newpcfcontent = calculate_current_content($filesinpackage, $packagename); 654 $installer::globals::newpcfcontentcalculated = 1; 655 656 # reading the existing pcf file 657 ($realpackagename, $oldpcfcontent, $oldepmcontent) = read_pcf_content($filename); 658 659 # First check: Package has to exist in pool (directories on Solaris) 660 my $fullpackage = $installer::globals::poolpath . $installer::globals::separator . $realpackagename; 661 if ( $installer::globals::issolarisbuild ) { $fullpackage = $fullpackage . ".tar"; } 662 if ( -f $fullpackage ) 663 { 664 $package_already_exists = 1; 665 # Second check: Only files 666 my $content_is_identical = compare_package_content($oldpcfcontent, $installer::globals::newpcfcontent); 667 668 # Third check for Unix: Changes in the epm file? 669 if (( $content_is_identical ) && ( ! $installer::globals::iswindowsbuild )) 670 { 671 $content_is_identical = compare_epm_content($oldepmcontent, $newepmcontent); 672 } 673 674 if ( $content_is_identical ) { $package_is_up_to_date = 1; } 675 } 676 } 677 678 if ( $package_is_up_to_date ) 679 { 680 $infoline = "Pool: $packagename: No new content, using existing package\n"; 681 $installer::logger::Lang->print($infoline); 682 $installer::logger::Info->printf("... using package from pool\n"); 683 } 684 else 685 { 686 if ( $package_already_exists ) 687 { 688 $infoline = "Pool: $packagename: Contains new content, creating new package. Differences:\n"; 689 $installer::logger::Lang->print($infoline); 690 foreach my $dest ( sort keys %installer::globals::pcfdifflist ) 691 { 692 $installer::logger::Lang->printf("%s\n", $dest); 693 } 694 foreach my $dest ( @installer::globals::pcfdiffcomment ) 695 { 696 $installer::logger::Lang->printf("%s\n", $dest); 697 } 698 foreach my $dest ( @installer::globals::epmdifflist ) 699 { 700 $installer::logger::Lang->printf("%s\n", $dest); 701 } 702 } 703 else 704 { 705 $infoline = "Pool: $packagename: Does not exist in pool.\n"; 706 $installer::logger::Lang->print($infoline); 707 } 708 709 $installer::logger::Info->printf("... packaging required\n"); 710 %installer::globals::xpdpackageinfo = (); # reset the filled hash, because the package cannot be used. 711 712 # Creating lock mechanism, so that other processes do not create this package, too. 713 installer::files::save_file($lockfilename, \@lockfilecontent); # Creating the Lock, to create this package (Lock for check still exists). 714 $installer::globals::processhaspoollockfile = 1; 715 716 # Check if creation of Lock file was really successful 717 718 if ( ! -f $lockfilename ) 719 { 720 $infoline = "Pool problem: Pool lock file \"$lockfilename\" could not be created successfully or was removed by another process (D)!\n"; 721 $installer::logger::Lang->print($infoline); 722 log_pool_info(0); 723 $package_is_up_to_date = 4; # repeat this package 724 return $package_is_up_to_date; 725 } 726 727 if ( ! process_is_owner($lockfilename) ) 728 { 729 $infoline = "Pool problem: Pool lock file \"$lockfilename\" belongs to another process (D)!\n"; 730 $installer::logger::Lang->print($infoline); 731 log_pool_info(1); 732 $package_is_up_to_date = 4; # repeat this package 733 return $package_is_up_to_date; 734 } 735 736 $infoline = "Pool: Created file: $lockfilename\n"; 737 $installer::logger::Lang->print($infoline); 738 } 739 740 my $newpackagepath = ""; 741 742 if ( $package_is_up_to_date ) 743 { 744 # Before the package is copied into the installation set, it has to be checked, if this process is really the owner of this lock file.. 745 # Check, if lock file still exists and if this process is the owner. 746 747 if ( ! -f $checkfilename ) 748 { 749 $infoline = "Pool problem: Pool lock file \"$checkfilename\" was removed by another process (B)!\n"; 750 $installer::logger::Lang->print($infoline); 751 log_pool_info(0); 752 $package_is_up_to_date = 4; # repeat this package 753 return $package_is_up_to_date; 754 } 755 756 if ( ! process_is_owner($checkfilename) ) 757 { 758 $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (B)!\n"; 759 $installer::logger::Lang->print($infoline); 760 log_pool_info(1); 761 $package_is_up_to_date = 4; # repeat this package 762 return $package_is_up_to_date; 763 } 764 765 # Copying the package from the pool into the installation set 766 $newpackagepath = copy_package_from_pool($installdir, $subdir, $realpackagename); 767 } 768 769 # Before the lock file in the pool can be removed, it has to be checked, if this process is still the owner of this lock file. 770 # Check, if lock file still exists and if this process is the owner. 771 if ( ! -f $checkfilename ) 772 { 773 $infoline = "Pool problem: Pool lock file \"$checkfilename\" was removed by another process (C)!\n"; 774 $installer::logger::Lang->print($infoline); 775 log_pool_info(0); 776 777 # removing new package from installation set 778 if ( $newpackagepath ne "" ) { remove_package_from_installset($newpackagepath); } # A file was copied and a problem occured with pooling 779 780 $package_is_up_to_date = 4; # repeat this package 781 return $package_is_up_to_date; 782 } 783 784 if ( ! process_is_owner($checkfilename) ) 785 { 786 $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (C)!\n"; 787 $installer::logger::Lang->print($infoline); 788 log_pool_info(1); 789 790 # removing new package from installation set 791 if ( $newpackagepath ne "" ) { remove_package_from_installset($newpackagepath); } # A file was copied and a problem occured with pooling 792 793 $package_is_up_to_date = 4; # repeat this package 794 return $package_is_up_to_date; 795 } 796 797 # Removing the check file, releasing this package for the next process. 798 # The Lock to create this package still exists, if required. 799 unlink $checkfilename; 800 $installer::globals::processhaspoolcheckfile = 0; 801 $infoline = "Pool: Removing file: $checkfilename\n"; 802 $installer::logger::Lang->print($infoline); 803 804 # Last chance before packaging starts, to check, if this process is really still owner 805 # of the packaging lock file. If not, this packaging process can be repeated. 806 if ( $installer::globals::processhaspoollockfile ) 807 { 808 if ( ! -f $lockfilename ) 809 { 810 $infoline = "Pool problem: Pool lock file \"$lockfilename\" was removed by another process (E)!\n"; 811 $installer::logger::Lang->print($infoline); 812 log_pool_info(0); 813 $package_is_up_to_date = 4; # repeat this package 814 return $package_is_up_to_date; 815 } 816 817 if ( ! process_is_owner($lockfilename) ) 818 { 819 $infoline = "Pool problem: Pool lock file \"$lockfilename\" belongs to another process (E)!\n"; 820 $installer::logger::Lang->print($infoline); 821 log_pool_info(1); 822 $package_is_up_to_date = 4; # repeat this package 823 return $package_is_up_to_date; 824 } 825 } 826 827 # Collecting log information 828 if ( $package_is_up_to_date == 1 ) { $installer::globals::poolpackages{$packagename} = 1; } 829 if ( $package_is_up_to_date == 0 ) 830 { 831 my @packreasons = (); 832 if ( $package_already_exists ) 833 { 834 $infoline = "\t\tPool: $packagename: Contains new content, creating new package. Differences:\n"; 835 push( @packreasons, $infoline); 836 foreach my $dest ( sort keys %installer::globals::pcfdifflist ) { push( @packreasons, "\t\t$dest\n"); } 837 foreach my $dest ( @installer::globals::pcfdiffcomment ) { push( @packreasons, "\t\t$dest"); } 838 foreach my $dest ( @installer::globals::epmdifflist ) { push( @packreasons, "\t\t$dest"); } 839 } 840 else 841 { 842 $infoline = "\t\tPool: $packagename: Does not exist in pool.\n"; 843 push( @packreasons, $infoline); 844 } 845 846 $installer::globals::createpackages{$packagename} = \@packreasons; 847 } 848 849 return $package_is_up_to_date; 850} 851 852################################################### 853# Determine, which package was created newly 854################################################### 855 856sub determine_new_packagename 857{ 858 my ( $dir ) = @_; 859 860 my ($newcontent, $allcontent) = installer::systemactions::find_new_content_in_directory($dir, \@installer::globals::installsetcontent); 861 @installer::globals::installsetcontent = (); 862 foreach my $element ( @{$allcontent} ) { push(@installer::globals::installsetcontent, $element); } 863 864 my $newentriesnumber = $#{$newcontent} + 1; 865 if ( $newentriesnumber > 1 ) 866 { 867 my $newpackages = ""; 868 foreach my $onepackage ( @{$newcontent} ) { $newpackages = $newpackages . " " . $onepackage; } 869 installer::exiter::exit_program("ERROR: More than one new package in directory $dir ($newpackages)", "determine_new_packagename (packagepool)"); 870 } 871 elsif ( $newentriesnumber < 1 ) 872 { 873 installer::exiter::exit_program("ERROR: No new package in directory $dir", "determine_new_packagename (packagepool)"); 874 } 875 my $newpackage = ${$newcontent}[0]; 876 877 return $newpackage; 878} 879 880#################################################### 881# Including content into the package pool 882#################################################### 883 884sub put_content_into_pool 885{ 886 my ($packagename, $installdir, $subdir, $filesinpackage, $epmfilecontent) = @_; 887 888 my $infoline = ""; 889 890 my $fullinstalldir = $installdir . $installer::globals::separator . $subdir; 891 my $fullrealpackagename = determine_new_packagename($fullinstalldir); 892 my $realpackagename = $fullrealpackagename; 893 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$realpackagename); 894 895 installer::logger::include_header_into_logfile("Adding content into the package pool: $realpackagename (PackageName: $packagename)"); 896 897 # Calculating content for pcf file, if not already done in "package_is_up_to_date" 898 if ( ! $installer::globals::newpcfcontentcalculated ) 899 { 900 $installer::globals::newpcfcontent = calculate_current_content($filesinpackage, $packagename); 901 $installer::globals::newpcfcontentcalculated = 1; 902 } 903 904 # Determining md5sum and FileSize for the new package and saving in pcf file 905 my $md5sum = installer::xpdinstaller::get_md5_value($fullrealpackagename); 906 my $filesize = installer::xpdinstaller::get_size_value($fullrealpackagename); 907 my $fullpackagename = installer::xpdinstaller::get_fullpkgname_value($fullrealpackagename); 908 my $pkgversion = installer::xpdinstaller::get_pkgversion_value($fullrealpackagename); 909 910 # Put package content file (pcf) into pool 911 my $pcffilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf"; 912 create_pcfcontent_file($realpackagename, $md5sum, $filesize, $fullpackagename, $pkgversion, $epmfilecontent, $pcffilename); 913 914 # Creating xpd info 915 $installer::globals::xpdpackageinfo{'FileSize'} = $filesize; 916 $installer::globals::xpdpackageinfo{'FullPackageName'} = $fullpackagename; 917 $installer::globals::xpdpackageinfo{'md5sum'} = $md5sum; 918 $installer::globals::xpdpackageinfo{'RealPackageName'} = $realpackagename; 919 $installer::globals::xpdpackageinfo{'PkgVersion'} = $pkgversion; 920 921 # Put package into pool 922 $infoline = "Pool: Adding package \"$packagename\" into pool.\n"; 923 $installer::logger::Lang->print($infoline); 924 925 # Copying with unique name, containing PID. Only renaming if everything was fine. 926 my $realdestination = ""; 927 my $uniquedestination = ""; 928 if ( -f $fullrealpackagename ) 929 { 930 $realdestination = $installer::globals::poolpath . $installer::globals::separator . $realpackagename; 931 $uniquedestination = $realdestination . "." . $installer::globals::sessionid; 932 installer::systemactions::copy_one_file($fullrealpackagename, $uniquedestination); 933 } 934 935 # Copying Solaris packages (as tar files) 936 if ( -d $fullrealpackagename ) 937 { 938 my $tarfilename = $packagename . ".tar"; 939 my $fulltarfilename = $fullinstalldir . $installer::globals::separator . $tarfilename; 940 my $size = installer::worker::tar_package($fullinstalldir, $packagename, $tarfilename, $installer::globals::getuidpath); 941 if (( ! -f $fulltarfilename ) || ( ! ( $size > 0 ))) { installer::exiter::exit_program("ERROR: Missing file: $fulltarfilename", "put_content_into_pool"); } 942 $realdestination = $installer::globals::poolpath . $installer::globals::separator . $tarfilename; 943 $uniquedestination = $realdestination . "." . $installer::globals::sessionid; 944 installer::systemactions::copy_one_file($fulltarfilename, $uniquedestination); 945 unlink $fulltarfilename; 946 } 947 948 # Before the new package is renamed in the pool, it has to be checked, if this process still has the lock for this package. 949 # Check, if lock file still exists and if this process is the owner. Otherwise a pool error occured. 950 if ( ! -f $installer::globals::poollockfilename ) 951 { 952 unlink $uniquedestination; # removing file from pool 953 log_pool_info(0); 954 installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" was removed by another process (F)!", "put_content_into_pool"); 955 } 956 957 if ( ! process_is_owner($installer::globals::poollockfilename) ) 958 { 959 unlink $uniquedestination; # removing file from pool 960 log_pool_info(1); 961 installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" belongs to another process (F)!", "put_content_into_pool"); 962 } 963 964 # Renaming the file in the pool (atomic step) 965 rename($uniquedestination, $realdestination); 966 967 $infoline = "Pool: Renamed file: \"$uniquedestination\" to \"$realdestination\".\n"; 968 $installer::logger::Lang->print($infoline); 969 970 # Before the lock file in the pool can be removed, it has to be checked, if this process is still the owner of this lock file. 971 # Check, if lock file still exists and if this process is the owner. Otherwise a pool error occured. 972 if ( ! -f $installer::globals::poollockfilename ) 973 { 974 log_pool_info(0); 975 installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" was removed by another process (G)!", "put_content_into_pool"); 976 } 977 978 if ( ! process_is_owner($installer::globals::poollockfilename) ) 979 { 980 log_pool_info(1); 981 installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" belongs to another process (G)!", "put_content_into_pool"); 982 } 983 984 # Removing lock file, so that other processes can use this package now 985 unlink $installer::globals::poollockfilename; 986 $installer::globals::processhaspoollockfile = 0; 987 $infoline = "Pool: Removing file: $installer::globals::poollockfilename\n"; 988 $installer::logger::Lang->print($infoline); 989} 990 991################################################################### 992# Copying a package from the pool into the installation set 993################################################################### 994 995sub copy_package_from_pool 996{ 997 my ($installdir, $subdir, $packagename) = @_; 998 999 my $infoline = "Pool: Using package \"$packagename\" from pool.\n"; 1000 $installer::logger::Lang->print($infoline); 1001 my $sourcefile = $installer::globals::poolpath . $installer::globals::separator . $packagename; 1002 if ( $installer::globals::issolarisbuild ) { $sourcefile = $sourcefile . ".tar"; } 1003 if ( ! -f $sourcefile ) { installer::exiter::exit_program("ERROR: Missing package in package pool: \"$sourcefile\"", "copy_package_from_pool"); } 1004 my $destination = $installdir . $installer::globals::separator . $subdir; 1005 if ( ! -d $destination ) { installer::systemactions::create_directory($destination); } 1006 my $destinationfile = $destination . $installer::globals::separator . $packagename; 1007 if ( $installer::globals::issolarisbuild ) { $destinationfile = $destinationfile . ".tar"; } 1008 if ( -f $sourcefile ) { installer::systemactions::copy_one_file($sourcefile, $destinationfile); } 1009 # Unpacking for Solaris 1010 if ( $installer::globals::issolarisbuild ) 1011 { 1012 my $tarfilename = $packagename . ".tar"; 1013 installer::worker::untar_package($destination, $tarfilename, $installer::globals::getuidpath); 1014 unlink $destinationfile; 1015 $destinationfile =~ s/.tar\s*$//; 1016 } 1017 1018 # Keeping the content of @installer::globals::installsetcontent up to date (with full pathes): 1019 push(@installer::globals::installsetcontent, $destinationfile); 1020 1021 return $destinationfile; 1022} 1023 1024################################################################### 1025# Counting keys in hash 1026################################################################### 1027 1028sub get_count 1029{ 1030 my ( $hashref ) = @_; 1031 1032 my $counter = 0; 1033 foreach my $onekey ( keys %{$hashref} ) { $counter++; } 1034 return $counter; 1035} 1036 1037################################################################### 1038# Logging some pool information 1039################################################################### 1040 1041sub log_pool_statistics 1042{ 1043 my $infoline = ""; 1044 1045 installer::logger::include_header_into_logfile("Pool statistics:"); 1046 1047 # Info collected in global hashes 1048 # %installer::globals::createpackages 1049 # %installer::globals::poolpackages 1050 1051 my $pool_packages = get_count(\%installer::globals::poolpackages); 1052 my $created_packages = get_count(\%installer::globals::createpackages); 1053 1054 $infoline = "Number of packages from pool: $pool_packages\n"; 1055 $installer::logger::Lang->print($infoline); 1056 1057 foreach my $packagename ( sort keys(%installer::globals::poolpackages) ) 1058 { 1059 $infoline = "\t$packagename\n"; 1060 $installer::logger::Lang->print($infoline); 1061 } 1062 1063 $installer::logger::Lang->print("\n"); 1064 $installer::logger::Lang->print("Number of packages that were created: %s\n", $created_packages); 1065 1066 foreach my $packagename ( sort keys(%installer::globals::createpackages) ) 1067 { 1068 $infoline = "\t$packagename\n"; 1069 $installer::logger::Lang->print($infoline); 1070 my $reason = $installer::globals::createpackages{$packagename}; 1071 1072 foreach my $line (@reason) 1073 { 1074 $installer::logger::Lang->print($line); 1075 } 1076 } 1077} 1078 10791; 1080