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