diff options
Diffstat (limited to 'solenv/bin/modules/installer/packagepool.pm')
-rw-r--r-- | solenv/bin/modules/installer/packagepool.pm | 1048 |
1 files changed, 1048 insertions, 0 deletions
diff --git a/solenv/bin/modules/installer/packagepool.pm b/solenv/bin/modules/installer/packagepool.pm new file mode 100644 index 000000000000..d4032b7db17e --- /dev/null +++ b/solenv/bin/modules/installer/packagepool.pm @@ -0,0 +1,1048 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +package installer::packagepool; + +use Digest::MD5; +use installer::exiter; +use installer::globals; +use installer::logger; +use installer::pathanalyzer; +use installer::worker; + +###################################################### +# Checking the md5sum of a file +###################################################### + +sub get_md5sum +{ + my ($filename) = @_; + + open(FILE, "<$filename") or die "ERROR: Can't open $filename for creating file hash"; + binmode(FILE); + my $digest = Digest::MD5->new->addfile(*FILE)->hexdigest; + close(FILE); + + return $digest; +} + +#################################################### +# Setting a unique sessionid to identify this +# packaging process. +#################################################### + +sub set_sessionid +{ + my $pid = $$; # process id + my $timer = time(); # time + $installer::globals::sessionid = $pid . $timer; + $installer::globals::sessionidset = 1; + my $infoline = "\nPool: Setting session id: $installer::globals::sessionid.\n"; + push( @installer::globals::logfileinfo, $infoline); +} + +#################################################### +# Setting and creating pool path. +#################################################### + +sub set_pool_path +{ + $installer::globals::unpackpath =~ s/\Q$installer::globals::separator\E\s*$//; # removing ending slashes and backslashes + $installer::globals::poolpath = $installer::globals::unpackpath . $installer::globals::separator . "pool_" . $installer::globals::packageformat; + installer::systemactions::create_directory($installer::globals::poolpath); + $installer::globals::poolpathset = 1; +} + +#################################################### +# Comparing the content of two epm files. +#################################################### + +sub compare_epm_content +{ + my ($oldcontent, $newcontent) = @_; + + my $identical = 1; + my $diffinfo = ""; + + # Removing empty lines and files from $newcontent + + my @newlocalcontent = (); + for ( my $i = 0; $i <= $#{$newcontent}; $i++ ) + { + if ( ${$newcontent}[$i] =~ /^\s*$/ ) { next; } # Removing empty lines from $newcontent. Empty lines are also not included into pcf file, from where $oldcontent was read. + if ( ${$newcontent}[$i] =~ /^\s*f\s+/ ) { next; } # Ignoring files, they can contain temporary pathes + if (( ${$newcontent}[$i] =~ /^\s*%readme\s+/ ) || ( ${$newcontent}[$i] =~ /^\s*%license\s+/ )) { next; } # ignoring license and readme (language specific!) + my $oneline = ${$newcontent}[$i]; + $oneline =~ s/\s*$//; # Removing line ends. Also not included in old epm file, that is read from pcf file. + push(@newlocalcontent, $oneline); + } + + my $oldmember = $#{$oldcontent} + 1; + my $newmember = $#newlocalcontent + 1; + + # comparing the count + if ( $oldmember != $newmember ) + { + $identical = 0; + installer::logger::print_message("\n...... changed length of EPM file\n"); + $diffinfo = "Pool: EPM, different line count: old epm file: $oldmember, new epm file: $newmember\n"; + push(@installer::globals::epmdifflist, $diffinfo); + } + + # comparing the content line for line, so the order must not change + + if ( $identical ) + { + for ( my $i = 0; $i <= $#{$oldcontent}; $i++ ) + { + if ( ${$oldcontent}[$i] ne $newlocalcontent[$i] ) + { + $identical = 0; + my $line = $i + 1; + installer::logger::print_message("\n...... different content in EPM file\n"); + $diffinfo = "Pool: EPM, line $line changed from \"${$oldcontent}[$i]\" to \"$newlocalcontent[$i]\".\n"; + push(@installer::globals::epmdifflist, $diffinfo); + last; + } + } + } + + return $identical; +} + +#################################################### +# Comparing the content of two pcf files. +#################################################### + +sub compare_package_content +{ + my ($oldcontent, $newcontent) = @_; + + my $identical = 1; + my $infoline = ""; + + my $oldmember = scalar keys %{$oldcontent}; + my $newmember = scalar keys %{$newcontent}; + + # comparing the count + + if ( $oldmember != $newmember ) + { + # Logging the difference + $identical = 0; + installer::logger::print_message("\n...... different number of files in packages. New number: $newmember, old number: $oldmember\n"); + $infoline = "Different number of files in packages. New number: $newmember, old number: $oldmember\n"; + push(@installer::globals::pcfdiffcomment, $infoline); + } + + # comparing the keys + + if ( $identical ) + { + my $first = 1; + my $start = "\n"; + foreach my $dest ( keys %{$newcontent} ) + { + if ( ! exists($oldcontent->{$dest}) ) + { + $identical = 0; + installer::logger::print_message("$start...... file only in one package (A): $dest\n"); + $infoline = "File only in existing pool package: $dest\n"; + push(@installer::globals::pcfdiffcomment, $infoline); + if ( $first ) { $start = ""; } + $first = 0; + } + } + + # collecting all differences + if ( ! $identical ) + { + foreach my $dest ( keys %{$oldcontent} ) + { + if ( ! exists($newcontent->{$dest}) ) + { + $identical = 0; + installer::logger::print_message("$start...... file only in one package (B): $dest\n"); + $infoline = "File only in new package: $dest\n"; + push(@installer::globals::pcfdiffcomment, $infoline); + if ( $first ) { $start = ""; } + $first = 0; + } + } + } + } + + # comparing the checksum + + if ( $identical ) + { + my $first = 1; + + foreach my $dest ( keys %{$newcontent} ) + { + if ( $newcontent->{$dest}->{'md5sum'} ne $oldcontent->{$dest}->{'md5sum'} ) + { + $identical = 0; + if ( $first == 1 ) + { + installer::logger::print_message("\n"); + $first = 0; + } + $installer::globals::pcfdifflist{$dest} = 1; + installer::logger::print_message("...... different file: $dest\n"); + # last; + } + + if ( $installer::globals::iswindowsbuild ) + { + if ( $newcontent->{$dest}->{'uniquename'} ne $oldcontent->{$dest}->{'uniquename'} ) + { + $identical = 0; + $installer::globals::pcfdifflist{$dest} = 1; + installer::logger::print_message("\n...... different file: $dest"); + # last; + } + } + } + } + + return $identical; +} + +#################################################### +# Calculating content of pcf file. +#################################################### + +sub calculate_current_content +{ + my ($filesarray, $packagename) = @_; + + installer::logger::include_timestamp_into_logfile("\nCalculating content for package content file ($packagename), start"); + + my %globalcontent = (); + + for ( my $i = 0; $i <= $#{$filesarray}; $i++ ) + { + my %onefilehash = (); + + my $onefile = ${$filesarray}[$i]; + if ( ! $onefile->{'sourcepath'} ) { installer::exiter::exit_program("ERROR: No sourcepath found for file $onefile->{'gid'}", "calculate_current_content"); } + my $source = $onefile->{'sourcepath'}; + if ( $onefile->{'zipfilesource'} ) { $source = $onefile->{'zipfilesource'}; } + if ( ! -f $source ) { installer::exiter::exit_program("ERROR: Sourcefile not found: $source ($onefile->{'gid'})", "calculate_current_content"); } + + # For Windows the unique name inside the cabinet file also has to be saved + my $uniquename = ""; + if ( $installer::globals::iswindowsbuild ) { $uniquename = $onefile->{'uniquename'};} + + my $destination = $onefile->{'destination'}; + my $checksum = get_md5sum($source); + + $onefilehash{'md5sum'} = $checksum; + $onefilehash{'uniquename'} = $uniquename; + + if ( exists($globalcontent{$destination}) ) { installer::exiter::exit_program("ERROR: Destination not unique: $destination ($onefile->{'gid'})", "calculate_current_content"); } + $globalcontent{$destination} = \%onefilehash; + } + + installer::logger::include_timestamp_into_logfile("\nCalculating content for package content file ($packagename), start"); + + return \%globalcontent; +} + +#################################################### +# Writing pcf file. +#################################################### + +sub create_pcfcontent_file +{ + my ($realpackagename, $md5sum, $filesize, $fullpackagename, $pkgversion, $epmfilecontent, $pcffilename) = @_; + + my @content = (); + my $oneline = "PackageName: $realpackagename\n"; + push(@content, $oneline); + + $oneline = "md5sum: $md5sum\n"; + push(@content, $oneline); + + $oneline = "FileSize: $filesize\n"; + push(@content, $oneline); + + $oneline = "FullPackageName: $fullpackagename\n"; + push(@content, $oneline); + + $oneline = "PkgVersion: $pkgversion\n"; + push(@content, $oneline); + + foreach my $dest (keys %{$installer::globals::newpcfcontent} ) + { + $oneline = "Files:\t$dest\t$installer::globals::newpcfcontent->{$dest}->{'md5sum'}\t$installer::globals::newpcfcontent->{$dest}->{'uniquename'}\n"; + push(@content, $oneline); + } + + for ( my $i = 0; $i <= $#{$epmfilecontent}; $i++ ) + { + if ( ${$epmfilecontent}[$i] =~ /^\s*$/ ) { next; } # avoiding empty lines + if ( ${$epmfilecontent}[$i] =~ /^\s*f\s+/ ) { next; } # ignoring files, because they can contain temporary pathes + if (( ${$epmfilecontent}[$i] =~ /^\s*%readme\s+/ ) || ( ${$epmfilecontent}[$i] =~ /^\s*%license\s+/ )) { next; } # ignoring license and readme (language specific!) + $oneline = "EPM:\t${$epmfilecontent}[$i]"; + push(@content, $oneline); + } + + installer::files::save_file($pcffilename, \@content); +} + +####################################################### +# Reading the content of the package content file. +####################################################### + +sub read_pcf_content +{ + my ($pcffilename) = @_; + + my %allcontent = (); + my @epmfile = (); + my $realpackagename = ""; + + my $content = installer::files::read_file($pcffilename); + + for ( my $i = 0; $i <= $#{$content}; $i++ ) + { + my $line = ${$content}[$i]; + + if ( $line =~ /^\s*PackageName\:\s*(.*?)\s*$/ ) + { + $realpackagename = $1; + $installer::globals::xpdpackageinfo{'RealPackageName'} = $realpackagename; + next; + } + + if ( $line =~ /^\s*FullPackageName\:\s*(.*?)\s*$/ ) + { + $installer::globals::xpdpackageinfo{'FullPackageName'} = $1; + next; + } + + if ( $line =~ /^\s*FileSize\:\s*(.*?)\s*$/ ) + { + $installer::globals::xpdpackageinfo{'FileSize'} = $1; + next; + } + + if ( $line =~ /^\s*PkgVersion\:\s*(.*?)\s*$/ ) + { + $installer::globals::xpdpackageinfo{'PkgVersion'} = $1; + next; + } + + if ( $line =~ /^\s*md5sum\:\s*(.*?)\s*$/ ) + { + $installer::globals::xpdpackageinfo{'md5sum'} = $1; + next; + } + + if ( $line =~ /^\s*Files:\t(.+?)\t(.+?)\t(.*?)\s*$/ ) + { + my $destination = $1; + my $checksum = $2; + my $uniquename = $3; + + my %onefilehash = (); + $onefilehash{'md5sum'} = $checksum; + $onefilehash{'uniquename'} = $uniquename; + + $allcontent{$destination} = \%onefilehash; + next; + } + + if ( $line =~ /^\s*EPM:\t(.*?)\s*$/ ) # A line can be empty in epm file + { + my $epmcontent = $1; + push(@epmfile, $epmcontent); + next; + } + } + + if ( $realpackagename eq "" ) { installer::exiter::exit_program("ERROR: Real package name not found in pcf file: \"$pcffilename\"", "read_pcf_content"); } + + return ($realpackagename, \%allcontent, \@epmfile); +} + +#################################################### +# Checking, if a specific package can be +# created at the moment. +#################################################### + +sub check_package_availability +{ + my ($packagename) = @_; + + my $package_is_available = 1; + + my $checkfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.check"; + my $lockfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.lock"; + + if (( -f $checkfilename ) || ( -f $lockfilename )) { $package_is_available = 0; } + + return $package_is_available; +} + +#################################################### +# Check, if the existence of the check or lock +# file requires an exit of packaging process. +#################################################### + +sub check_pool_exit +{ + my ( $lockfilename, $timecounter ) = @_; + + # How old is this lock file? + my $timeage = installer::logger::get_file_age($lockfilename); + + # if ( $timeage > 1800 ) # file is older than half an hour + if ( $timeage > 3600 ) # file is older than an hour + { + my $timestring = installer::logger::convert_timestring($timeage); + my $infoline = "\nPool: Attention: \"$lockfilename\" is too old ($timestring). Removing file!\n"; + installer::logger::print_message( "... $infoline" ); + push( @installer::globals::logfileinfo, $infoline); + unlink $lockfilename; + # installer::exiter::exit_program("ERROR: Waiting too long for removal of lock file \"$lockfilename\"", "check_pool_exit (packagepool)"); + } + else + { + my $filecontent = installer::files::read_file($lockfilename); + my $waittime = $timecounter * 10; + $waittime = installer::logger::convert_timestring($waittime); + my $infoline = "\nPool: Warning: \"$lockfilename\" blocks this process for $waittime. Lock content: \"${$filecontent}[0]\"\n"; + installer::logger::print_message( "... $infoline" ); + push( @installer::globals::logfileinfo, $infoline); + } +} + +############################################################################ +# This function logs some information, that can be used to find +# pool problems. +############################################################################ + +sub log_pool_info +{ + my ( $file_exists ) = @_; + + my $infoline = ""; + + # Content saved in + # $installer::globals::savelockfilecontent = installer::files::read_file($filename); + # $installer::globals::savelockfilename = $filename; + + if ( $file_exists ) + { + $infoline = "\nPool Problem: Lock file \"$installer::globals::savelockfilename\" belongs to another process. This process has session id: $installer::globals::sessionid .\n"; + push( @installer::globals::logfileinfo, $infoline); + $infoline = "Content of Lock file:\n"; + push( @installer::globals::logfileinfo, $infoline); + foreach my $line ( @{$installer::globals::savelockfilecontent} ) { push( @installer::globals::logfileinfo, $line); } + } + else + { + $infoline = "\nPool Problem: Lock file \"$installer::globals::savelockfilename\" does not exist anymore (this process has session id: $installer::globals::sessionid) .\n"; + push( @installer::globals::logfileinfo, $infoline); + } +} + +############################################################################ +# Checking, if this process is the owner of the lock file in the pool. +# This can be determined by the Process ID, that is written at the +# beginning of the first line into the lock file. +############################################################################ + +sub process_is_owner +{ + my ( $filename ) = @_; + + my $process_is_owner = 0; + + $installer::globals::savelockfilecontent = installer::files::read_file($filename); + $installer::globals::savelockfilename = $filename; + + if ( ${$installer::globals::savelockfilecontent}[0] =~ /^\s*\Q$installer::globals::sessionid\E\s+/ ) { $process_is_owner = 1; } + + return $process_is_owner; +} + +#################################################### +# Removing a package from installation set, if +# there were pooling problems. +#################################################### + +sub remove_package_from_installset +{ + my ($newpackagepath) = @_; + + my $infoline = "Pool problem: Removing package \"$newpackagepath\" from installation set!\n"; + push(@installer::globals::logfileinfo, $infoline); + + if ( -f $newpackagepath ) { unlink $newpackagepath; } + if ( -d $newpackagepath ) { installer::systemactions::remove_complete_directory($newpackagepath, 1); } + + # Keeping the content of @installer::globals::installsetcontent up to date. Removing the last package. + pop(@installer::globals::installsetcontent); +} + +#################################################### +# Check, if the package is in the pool and if +# there are no changes in the package. +#################################################### + +sub package_is_up_to_date +{ + my ($allvariables, $onepackage, $packagename, $newepmcontent, $filesinpackage, $installdir, $subdir, $languagestringref) = @_; + + installer::logger::print_message_without_newline( "... checking pool package $packagename ..." ); + + installer::logger::include_header_into_logfile("Checking package in pool: $packagename"); + + if ( ! $installer::globals::poolpathset ) { installer::packagepool::set_pool_path(); } + if ( ! $installer::globals::sessionidset ) { installer::packagepool::set_sessionid(); } + + my $infoline = ""; + # Resetting some variables for this package + my $package_is_up_to_date = 0; + my $realpackagename = ""; + my $oldepmcontent = ""; + my $waited_for_check = 0; + my $waited_for_lock = 0; + $installer::globals::newpcfcontentcalculated = 0; + %installer::globals::pcfdifflist = (); + @installer::globals::pcfdiffcomment = (); + @installer::globals::epmdifflist = (); + + # Reading the package content file, if this file exists (extension *.pcf) + my $filename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf"; + my $checkfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.check"; + my $lockfilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf.lock"; + # Saving name in global variable, so that this file can be removed somewhere else (at the end of "put_content_into_pool"). + $installer::globals::poolcheckfilename = $checkfilename; + $installer::globals::poollockfilename = $lockfilename; + + my @checkfilecontent = ("$installer::globals::sessionid $installer::globals::product $$languagestringref $checkfilename"); # $$ is the process id + my @lockfilecontent = ("$installer::globals::sessionid $installer::globals::product $$languagestringref $lockfilename"); # $$ is the process id + + # Waiting, step 1 + # Checking, if another process checks this package at the moment + my $timecounter = 0; + while ( -f $checkfilename ) + { + $timecounter++; + + # including an exit to enable creation of other packages + if (( $timecounter == 1 ) && ( ! exists($installer::globals::poolshiftedpackages{$packagename}) )) + { + $package_is_up_to_date = 3; # repeat this package later + return $package_is_up_to_date; + } + + $infoline = "Pool: $checkfilename exists. WAITING 10 seconds ($timecounter).\n"; + if ( $timecounter == 1 ) { installer::logger::print_message( "\n" ); } + installer::logger::print_message( "... $infoline" ); + push( @installer::globals::logfileinfo, $infoline); + # if ( $timecounter % 50 == 0 ) { check_pool_exit($checkfilename, $timecounter); } + if ( $timecounter % 100 == 0 ) { check_pool_exit($checkfilename, $timecounter); } + sleep 10; # process sleeps 10 seconds + $waited_for_check = 1; + } + + # Creating file, showing that this package is checked at the moment by this process. No other process can reach this. + installer::files::save_file($checkfilename, \@checkfilecontent); # Creating the Lock, to check this package. This blocks all other processes. + $installer::globals::processhaspoolcheckfile = 1; + + # Check, if the Lock file creation was really successful + if ( ! -f $checkfilename ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" could not be created successfully or was removed by another process (A)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(0); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + if ( ! process_is_owner($checkfilename) ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (A)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(1); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + $infoline = "Pool: Created file: $checkfilename\n"; + push( @installer::globals::logfileinfo, $infoline); + if ( $waited_for_check ) { installer::logger::print_message( "... $infoline" ); } + + # Waiting, step 2 + # Checking, if another process creates this package at the moment + $timecounter = 0; + while ( -f $lockfilename ) + { + $timecounter++; + $infoline = "Pool: $lockfilename exists. WAITING 10 seconds ($timecounter).\n"; + if ( $timecounter == 1 ) { installer::logger::print_message( "\n" ); } + installer::logger::print_message( "... $infoline" ); + push( @installer::globals::logfileinfo, $infoline); + # if ( $timecounter % 50 == 0 ) { check_pool_exit($lockfilename, $timecounter); } + if ( $timecounter % 100 == 0 ) { check_pool_exit($lockfilename, $timecounter); } + sleep 10; # process sleeps 10 seconds + $waited_for_lock = 1; + } + + # No lock file exists, therefore no process creates this package at the moment. Check can be done now. + if ( $waited_for_lock ) { installer::logger::print_message( "... Pool: Proceeding, $lockfilename was removed.\n" ); } + + my $package_already_exists = 0; + + if ( -f $filename ) + { + # Calculating content for pcf file + $installer::globals::newpcfcontent = calculate_current_content($filesinpackage, $packagename); + $installer::globals::newpcfcontentcalculated = 1; + + # reading the existing pcf file + ($realpackagename, $oldpcfcontent, $oldepmcontent) = read_pcf_content($filename); + + # First check: Package has to exist in pool (directories on Solaris) + my $fullpackage = $installer::globals::poolpath . $installer::globals::separator . $realpackagename; + if ( $installer::globals::issolarisbuild ) { $fullpackage = $fullpackage . ".tar"; } + if ( -f $fullpackage ) + { + $package_already_exists = 1; + # Second check: Only files + my $content_is_identical = compare_package_content($oldpcfcontent, $installer::globals::newpcfcontent); + + # Third check for Unix: Changes in the epm file? + if (( $content_is_identical ) && ( ! $installer::globals::iswindowsbuild )) + { + $content_is_identical = compare_epm_content($oldepmcontent, $newepmcontent); + } + + if ( $content_is_identical ) { $package_is_up_to_date = 1; } + } + } + + if ( $package_is_up_to_date ) + { + $infoline = "Pool: $packagename: No new content, using existing package\n"; + push( @installer::globals::logfileinfo, $infoline); + installer::logger::print_message( "... using package from pool\n" ); + } + else + { + if ( $package_already_exists ) + { + $infoline = "Pool: $packagename: Contains new content, creating new package. Differences:\n"; + push( @installer::globals::logfileinfo, $infoline); + foreach my $dest ( sort keys %installer::globals::pcfdifflist ) { push( @installer::globals::logfileinfo, "$dest\n"); } + foreach my $dest ( @installer::globals::pcfdiffcomment ) { push( @installer::globals::logfileinfo, "$dest"); } + foreach my $dest ( @installer::globals::epmdifflist ) { push( @installer::globals::logfileinfo, "$dest"); } + } + else + { + $infoline = "Pool: $packagename: Does not exist in pool.\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + installer::logger::print_message( "... packaging required\n" ); + %installer::globals::xpdpackageinfo = (); # reset the filled hash, because the package cannot be used. + + # Creating lock mechanism, so that other processes do not create this package, too. + installer::files::save_file($lockfilename, \@lockfilecontent); # Creating the Lock, to create this package (Lock for check still exists). + $installer::globals::processhaspoollockfile = 1; + + # Check if creation of Lock file was really successful + + if ( ! -f $lockfilename ) + { + $infoline = "Pool problem: Pool lock file \"$lockfilename\" could not be created successfully or was removed by another process (D)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(0); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + if ( ! process_is_owner($lockfilename) ) + { + $infoline = "Pool problem: Pool lock file \"$lockfilename\" belongs to another process (D)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(1); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + $infoline = "Pool: Created file: $lockfilename\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + my $newpackagepath = ""; + + if ( $package_is_up_to_date ) + { + # 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.. + # Check, if lock file still exists and if this process is the owner. + + if ( ! -f $checkfilename ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" was removed by another process (B)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(0); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + if ( ! process_is_owner($checkfilename) ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (B)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(1); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + # Copying the package from the pool into the installation set + $newpackagepath = copy_package_from_pool($installdir, $subdir, $realpackagename); + } + + # 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. + # Check, if lock file still exists and if this process is the owner. + if ( ! -f $checkfilename ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" was removed by another process (C)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(0); + + # removing new package from installation set + if ( $newpackagepath ne "" ) { remove_package_from_installset($newpackagepath); } # A file was copied and a problem occured with pooling + + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + if ( ! process_is_owner($checkfilename) ) + { + $infoline = "Pool problem: Pool lock file \"$checkfilename\" belongs to another process (C)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(1); + + # removing new package from installation set + if ( $newpackagepath ne "" ) { remove_package_from_installset($newpackagepath); } # A file was copied and a problem occured with pooling + + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + # Removing the check file, releasing this package for the next process. + # The Lock to create this package still exists, if required. + unlink $checkfilename; + $installer::globals::processhaspoolcheckfile = 0; + $infoline = "Pool: Removing file: $checkfilename\n"; + push( @installer::globals::logfileinfo, $infoline); + + # Last chance before packaging starts, to check, if this process is really still owner + # of the packaging lock file. If not, this packaging process can be repeated. + if ( $installer::globals::processhaspoollockfile ) + { + if ( ! -f $lockfilename ) + { + $infoline = "Pool problem: Pool lock file \"$lockfilename\" was removed by another process (E)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(0); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + + if ( ! process_is_owner($lockfilename) ) + { + $infoline = "Pool problem: Pool lock file \"$lockfilename\" belongs to another process (E)!\n"; + push( @installer::globals::logfileinfo, $infoline); + log_pool_info(1); + $package_is_up_to_date = 4; # repeat this package + return $package_is_up_to_date; + } + } + + # Collecting log information + if ( $package_is_up_to_date == 1 ) { $installer::globals::poolpackages{$packagename} = 1; } + if ( $package_is_up_to_date == 0 ) + { + my @packreasons = (); + if ( $package_already_exists ) + { + $infoline = "\t\tPool: $packagename: Contains new content, creating new package. Differences:\n"; + push( @packreasons, $infoline); + foreach my $dest ( sort keys %installer::globals::pcfdifflist ) { push( @packreasons, "\t\t$dest\n"); } + foreach my $dest ( @installer::globals::pcfdiffcomment ) { push( @packreasons, "\t\t$dest"); } + foreach my $dest ( @installer::globals::epmdifflist ) { push( @packreasons, "\t\t$dest"); } + } + else + { + $infoline = "\t\tPool: $packagename: Does not exist in pool.\n"; + push( @packreasons, $infoline); + } + + $installer::globals::createpackages{$packagename} = \@packreasons; + } + + return $package_is_up_to_date; +} + +################################################### +# Determine, which package was created newly +################################################### + +sub determine_new_packagename +{ + my ( $dir ) = @_; + + my ($newcontent, $allcontent) = installer::systemactions::find_new_content_in_directory($dir, \@installer::globals::installsetcontent); + @installer::globals::installsetcontent = (); + foreach my $element ( @{$allcontent} ) { push(@installer::globals::installsetcontent, $element); } + + my $newentriesnumber = $#{$newcontent} + 1; + if ( $newentriesnumber > 1 ) + { + my $newpackages = ""; + foreach my $onepackage ( @{$newcontent} ) { $newpackages = $newpackages . " " . $onepackage; } + installer::exiter::exit_program("ERROR: More than one new package in directory $dir ($newpackages)", "determine_new_packagename (packagepool)"); + } + elsif ( $newentriesnumber < 1 ) + { + installer::exiter::exit_program("ERROR: No new package in directory $dir", "determine_new_packagename (packagepool)"); + } + my $newpackage = ${$newcontent}[0]; + + return $newpackage; +} + +#################################################### +# Including content into the package pool +#################################################### + +sub put_content_into_pool +{ + my ($packagename, $installdir, $subdir, $filesinpackage, $epmfilecontent) = @_; + + my $infoline = ""; + + my $fullinstalldir = $installdir . $installer::globals::separator . $subdir; + my $fullrealpackagename = determine_new_packagename($fullinstalldir); + my $realpackagename = $fullrealpackagename; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$realpackagename); + + installer::logger::include_header_into_logfile("Adding content into the package pool: $realpackagename (PackageName: $packagename)"); + + # Calculating content for pcf file, if not already done in "package_is_up_to_date" + if ( ! $installer::globals::newpcfcontentcalculated ) + { + $installer::globals::newpcfcontent = calculate_current_content($filesinpackage, $packagename); + $installer::globals::newpcfcontentcalculated = 1; + } + + # Determining md5sum and FileSize for the new package and saving in pcf file + my $md5sum = installer::xpdinstaller::get_md5_value($fullrealpackagename); + my $filesize = installer::xpdinstaller::get_size_value($fullrealpackagename); + my $fullpackagename = installer::xpdinstaller::get_fullpkgname_value($fullrealpackagename); + my $pkgversion = installer::xpdinstaller::get_pkgversion_value($fullrealpackagename); + + # Put package content file (pcf) into pool + my $pcffilename = $installer::globals::poolpath . $installer::globals::separator . $packagename . ".pcf"; + create_pcfcontent_file($realpackagename, $md5sum, $filesize, $fullpackagename, $pkgversion, $epmfilecontent, $pcffilename); + + # Creating xpd info + $installer::globals::xpdpackageinfo{'FileSize'} = $filesize; + $installer::globals::xpdpackageinfo{'FullPackageName'} = $fullpackagename; + $installer::globals::xpdpackageinfo{'md5sum'} = $md5sum; + $installer::globals::xpdpackageinfo{'RealPackageName'} = $realpackagename; + $installer::globals::xpdpackageinfo{'PkgVersion'} = $pkgversion; + + # Put package into pool + $infoline = "Pool: Adding package \"$packagename\" into pool.\n"; + push( @installer::globals::logfileinfo, $infoline); + + # Copying with unique name, containing PID. Only renaming if everything was fine. + my $realdestination = ""; + my $uniquedestination = ""; + if ( -f $fullrealpackagename ) + { + $realdestination = $installer::globals::poolpath . $installer::globals::separator . $realpackagename; + $uniquedestination = $realdestination . "." . $installer::globals::sessionid; + installer::systemactions::copy_one_file($fullrealpackagename, $uniquedestination); + } + + # Copying Solaris packages (as tar files) + if ( -d $fullrealpackagename ) + { + my $tarfilename = $packagename . ".tar"; + my $fulltarfilename = $fullinstalldir . $installer::globals::separator . $tarfilename; + my $size = installer::worker::tar_package($fullinstalldir, $packagename, $tarfilename, $installer::globals::getuidpath); + if (( ! -f $fulltarfilename ) || ( ! ( $size > 0 ))) { installer::exiter::exit_program("ERROR: Missing file: $fulltarfilename", "put_content_into_pool"); } + $realdestination = $installer::globals::poolpath . $installer::globals::separator . $tarfilename; + $uniquedestination = $realdestination . "." . $installer::globals::sessionid; + installer::systemactions::copy_one_file($fulltarfilename, $uniquedestination); + unlink $fulltarfilename; + } + + # Before the new package is renamed in the pool, it has to be checked, if this process still has the lock for this package. + # Check, if lock file still exists and if this process is the owner. Otherwise a pool error occured. + if ( ! -f $installer::globals::poollockfilename ) + { + unlink $uniquedestination; # removing file from pool + log_pool_info(0); + installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" was removed by another process (F)!", "put_content_into_pool"); + } + + if ( ! process_is_owner($installer::globals::poollockfilename) ) + { + unlink $uniquedestination; # removing file from pool + log_pool_info(1); + installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" belongs to another process (F)!", "put_content_into_pool"); + } + + # Renaming the file in the pool (atomic step) + rename($uniquedestination, $realdestination); + + $infoline = "Pool: Renamed file: \"$uniquedestination\" to \"$realdestination\".\n"; + push( @installer::globals::logfileinfo, $infoline); + + # 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. + # Check, if lock file still exists and if this process is the owner. Otherwise a pool error occured. + if ( ! -f $installer::globals::poollockfilename ) + { + log_pool_info(0); + installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" was removed by another process (G)!", "put_content_into_pool"); + } + + if ( ! process_is_owner($installer::globals::poollockfilename) ) + { + log_pool_info(1); + installer::exiter::exit_program("ERROR: Pool lock file \"$installer::globals::poollockfilename\" belongs to another process (G)!", "put_content_into_pool"); + } + + # Removing lock file, so that other processes can use this package now + unlink $installer::globals::poollockfilename; + $installer::globals::processhaspoollockfile = 0; + $infoline = "Pool: Removing file: $installer::globals::poollockfilename\n"; + push( @installer::globals::logfileinfo, $infoline); +} + +################################################################### +# Copying a package from the pool into the installation set +################################################################### + +sub copy_package_from_pool +{ + my ($installdir, $subdir, $packagename) = @_; + + my $infoline = "Pool: Using package \"$packagename\" from pool.\n"; + push( @installer::globals::logfileinfo, $infoline); + my $sourcefile = $installer::globals::poolpath . $installer::globals::separator . $packagename; + if ( $installer::globals::issolarisbuild ) { $sourcefile = $sourcefile . ".tar"; } + if ( ! -f $sourcefile ) { installer::exiter::exit_program("ERROR: Missing package in package pool: \"$sourcefile\"", "copy_package_from_pool"); } + my $destination = $installdir . $installer::globals::separator . $subdir; + if ( ! -d $destination ) { installer::systemactions::create_directory($destination); } + my $destinationfile = $destination . $installer::globals::separator . $packagename; + if ( $installer::globals::issolarisbuild ) { $destinationfile = $destinationfile . ".tar"; } + if ( -f $sourcefile ) { installer::systemactions::copy_one_file($sourcefile, $destinationfile); } + # Unpacking for Solaris + if ( $installer::globals::issolarisbuild ) + { + my $tarfilename = $packagename . ".tar"; + installer::worker::untar_package($destination, $tarfilename, $installer::globals::getuidpath); + unlink $destinationfile; + $destinationfile =~ s/.tar\s*$//; + } + + # Keeping the content of @installer::globals::installsetcontent up to date (with full pathes): + push(@installer::globals::installsetcontent, $destinationfile); + + return $destinationfile; +} + +################################################################### +# Counting keys in hash +################################################################### + +sub get_count +{ + my ( $hashref ) = @_; + + my $counter = 0; + foreach my $onekey ( keys %{$hashref} ) { $counter++; } + return $counter; +} + +################################################################### +# Logging some pool information +################################################################### + +sub log_pool_statistics +{ + my $infoline = ""; + + installer::logger::include_header_into_logfile("Pool statistics:"); + + # Info collected in global hashes + # %installer::globals::createpackages + # %installer::globals::poolpackages + + my $pool_packages = get_count(\%installer::globals::poolpackages); + my $created_packages = get_count(\%installer::globals::createpackages); + + $infoline = "Number of packages from pool: $pool_packages\n"; + push( @installer::globals::logfileinfo, $infoline); + + foreach my $packagename ( sort keys(%installer::globals::poolpackages) ) + { + $infoline = "\t$packagename\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + $infoline = "\nNumber of packages that were created: $created_packages\n"; + push( @installer::globals::logfileinfo, $infoline); + + foreach my $packagename ( sort keys(%installer::globals::createpackages) ) + { + $infoline = "\t$packagename\n"; + push( @installer::globals::logfileinfo, $infoline); + my $reason = $installer::globals::createpackages{$packagename}; + + for ( my $i = 0; $i <= $#{$reason}; $i++ ) + { + $infoline = "${$reason}[$i]"; + push( @installer::globals::logfileinfo, $infoline); + } + } +} + +1; |