diff options
Diffstat (limited to 'solenv/bin/modules/installer/worker.pm')
-rw-r--r-- | solenv/bin/modules/installer/worker.pm | 3436 |
1 files changed, 3436 insertions, 0 deletions
diff --git a/solenv/bin/modules/installer/worker.pm b/solenv/bin/modules/installer/worker.pm new file mode 100644 index 000000000000..564a8cb71da7 --- /dev/null +++ b/solenv/bin/modules/installer/worker.pm @@ -0,0 +1,3436 @@ +#************************************************************************* +# +# 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::worker; + +use Cwd; +use File::Copy; +use File::stat; +use File::Temp qw(tmpnam); +use installer::control; +use installer::converter; +use installer::existence; +use installer::exiter; +use installer::files; +use installer::globals; +use installer::logger; +use installer::mail; +use installer::pathanalyzer; +use installer::scpzipfiles; +use installer::scriptitems; +use installer::sorter; +use installer::systemactions; +use installer::windows::language; + +##################################################################### +# Unpacking all files ending with tar.gz in a specified directory +##################################################################### + +sub unpack_all_targzfiles_in_directory +{ + my ( $directory ) = @_; + + installer::logger::include_header_into_logfile("Unpacking tar.gz files:"); + + installer::logger::print_message( "... unpacking tar.gz files ... \n" ); + + my $localdirectory = $directory . $installer::globals::separator . "packages"; + my $alltargzfiles = installer::systemactions::find_file_with_file_extension("tar.gz", $localdirectory); + + for ( my $i = 0; $i <= $#{$alltargzfiles}; $i++ ) + { + my $onefile = $localdirectory . $installer::globals::separator . ${$alltargzfiles}[$i]; + + my $systemcall = "cd $localdirectory; cat ${$alltargzfiles}[$i] \| gunzip \| tar -xf -"; + $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + } +} + +######################################### +# Copying installation sets to ship +######################################### + +sub copy_install_sets_to_ship +{ + my ( $destdir, $shipinstalldir ) = @_; + + installer::logger::include_header_into_logfile("Copying installation set to ship:"); + + my $dirname = $destdir; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname); + $dirname = $dirname . "_inprogress"; + my $localshipinstalldir = $shipinstalldir . $installer::globals::separator . $dirname; + if ( ! -d $localshipinstalldir ) { installer::systemactions::create_directory_structure($localshipinstalldir); } + + # copy installation set to /ship ($localshipinstalldir) + installer::logger::print_message( "... copy installation set from " . $destdir . " to " . $localshipinstalldir . "\n" ); + installer::systemactions::copy_complete_directory($destdir, $localshipinstalldir); + + if (( ! $installer::globals::iswindowsbuild ) && ( $installer::globals::addjavainstaller )) + { + # Setting Unix rights for Java starter ("setup") + my $localcall = "chmod 775 $localshipinstalldir/setup \>\/dev\/null 2\>\&1"; + system($localcall); + } + + # unpacking the tar.gz file for Solaris + if ( $installer::globals::issolarisbuild ) { unpack_all_targzfiles_in_directory($localshipinstalldir); } + + $localshipinstalldir = installer::systemactions::rename_string_in_directory($localshipinstalldir, "_inprogress", ""); + + return $localshipinstalldir; +} + +######################################### +# Copying installation sets to ship +######################################### + +sub link_install_sets_to_ship +{ + my ( $destdir, $shipinstalldir ) = @_; + + installer::logger::include_header_into_logfile("Linking installation set to ship:"); + + my $infoline = "... destination directory: $shipinstalldir ...\n"; + installer::logger::print_message( $infoline ); + push( @installer::globals::logfileinfo, $infoline); + + if ( ! -d $shipinstalldir) + { + $infoline = "Creating directory: $shipinstalldir\n"; + push( @installer::globals::logfileinfo, $infoline); + installer::systemactions::create_directory_structure($shipinstalldir); + $infoline = "Created directory: $shipinstalldir\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + my $dirname = $destdir; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname); + + my $localshipinstalldir = $shipinstalldir . $installer::globals::separator . $dirname; + + # link installation set to /ship ($localshipinstalldir) + installer::logger::print_message( "... linking installation set from " . $destdir . " to " . $localshipinstalldir . "\n" ); + + my $systemcall = "ln -s $destdir $localshipinstalldir"; + + $returnvalue = system($systemcall); + + $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not create link \"$localshipinstalldir\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Created link \"$localshipinstalldir\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + return $localshipinstalldir; +} + +######################################### +# Create checksum file +######################################### + +sub make_checksum_file +{ + my ( $filesref, $includepatharrayref ) = @_; + + my @checksum = (); + + my $checksumfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$installer::globals::checksumfile, $includepatharrayref, 1); + if ( $$checksumfileref eq "" ) { installer::exiter::exit_program("ERROR: Could not find file $installer::globals::checksumfile !", "make_checksum_file"); } + +# # very slow on Windows +# for ( my $i = 0; $i <= $#{$filesref}; $i++ ) +# { +# my $onefile = ${$filesref}[$i]; +# my $systemcall = "$$checksumfileref $onefile->{'sourcepath'} |"; +# open (CHECK, "$systemcall"); +# my $localchecksum = <CHECK>; +# close (CHECK); +# push(@checksum, $localchecksum); +# } + + my $systemcall = "$$checksumfileref"; + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $onefile = ${$filesref}[$i]; + $systemcall = $systemcall . " " . $onefile->{'sourcepath'}; # very very long systemcall + + if ((( $i > 0 ) && ( $i%100 == 0 )) || ( $i == $#{$filesref} )) # limiting to 100 files + { + $systemcall = $systemcall . " \|"; + + my @localchecksum = (); + open (CHECK, "$systemcall"); + @localchecksum = <CHECK>; + close (CHECK); + + for ( my $j = 0; $j <= $#localchecksum; $j++ ) { push(@checksum, $localchecksum[$j]); } + + $systemcall = "$$checksumfileref"; # reset the system call + } + } + + return \@checksum; +} + +######################################### +# Saving the checksum file +######################################### + +sub save_checksum_file +{ + my ($current_install_number, $installchecksumdir, $checksumfile) = @_; + + my $numberedchecksumfilename = $installer::globals::checksumfilename; + $numberedchecksumfilename =~ s/\./_$current_install_number\./; # checksum.txt -> checksum_01.txt + installer::files::save_file($installchecksumdir . $installer::globals::separator . $numberedchecksumfilename, $checksumfile); +} + +################################################# +# Writing some global information into +# the list of files without flag PATCH +################################################# + +sub write_nopatchlist_header +{ + my ( $content ) = @_; + + my @header = (); + my $infoline = "This is a list of files, that are defined in scp-projects without\n"; + push(@header, $infoline); + $infoline = "flag \"PATCH\". Important: This does not mean in any case, that \n"; + push(@header, $infoline); + $infoline = "this files are included into or excluded from a patch. \n\n"; + push(@header, $infoline); + $infoline = "Exception Linux: A patch rpm is a complete rpm. This means that all \n"; + push(@header, $infoline); + $infoline = "files are included into a patch rpm, if only one file of the rpm has the \n"; + push(@header, $infoline); + $infoline = "style \"PATCH\". \n\n"; + push(@header, $infoline); + + for ( my $i = 0; $i <= $#header; $i++ ) { push(@{$content},$header[$i]); } +} + +################################################# +# Creating the content of the list of files +# without flag PATCH. +# All files are saved in +# @{$installer::globals::nopatchfilecollector} +################################################# + +sub create_nopatchlist +{ + my @content =(); + + write_nopatchlist_header(\@content); + + for ( my $i = 0; $i <= $#{$installer::globals::nopatchfilecollector}; $i++ ) + { + my $onefile = ${$installer::globals::nopatchfilecollector}[$i]; + my $oneline = $onefile->{'destination'}; + if ( $onefile->{'zipfilename'} ) { $oneline = $oneline . " (" . $onefile->{'zipfilename'} . ")"; } + $oneline = $oneline . "\n"; + push(@content, $oneline); + } + + return \@content; +} + +######################################### +# Saving the patchlist file +######################################### + +sub save_patchlist_file +{ + my ($installlogdir, $patchlistfilename) = @_; + + my $installpatchlistdir = installer::systemactions::create_directory_next_to_directory($installlogdir, "patchlist"); + $patchlistfilename =~ s/log\_/patchfiles\_/; + $patchlistfilename =~ s/\.log/\.txt/; + installer::files::save_file($installpatchlistdir . $installer::globals::separator . $patchlistfilename, \@installer::globals::patchfilecollector); + installer::logger::print_message( "... creating patchlist file $patchlistfilename \n" ); + + if (( $installer::globals::patch ) && ( ! $installer::globals::creating_windows_installer_patch )) # only for non-Windows patches + { + $patchlistfilename =~ s/patchfiles\_/nopatchfiles\_/; + my $nopatchlist = create_nopatchlist(); + installer::files::save_file($installpatchlistdir . $installer::globals::separator . $patchlistfilename, $nopatchlist); + installer::logger::print_message( "... creating patch exclusion file $patchlistfilename \n" ); + } + +} + +############################################################### +# Removing all directories of a special language +# in the directory $basedir +############################################################### + +sub remove_old_installation_sets +{ + my ($basedir) = @_; + + installer::logger::print_message( "... removing old installation directories ...\n" ); + + my $removedir = $basedir; + + if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); } + + # looking for non successful old installation sets + + $removedir = $basedir . "_witherror"; + if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); } + + $removedir = $basedir . "_inprogress"; + if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); } + + # finally the $basedir can be created empty + + if ( $installer::globals::localinstalldirset ) { installer::systemactions::create_directory_structure($basedir); } + + installer::systemactions::create_directory($basedir); +} + +############################################################### +# Removing all non successful installation sets on ship +############################################################### + +sub remove_old_ship_installation_sets +{ + my ($fulldir, $counter) = @_; + + installer::logger::print_message( "... removing old installation directories ...\n" ); + + my $basedir = $fulldir; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$basedir); + + # collecting all directories next to the new installation directory + my $alldirs = installer::systemactions::get_all_directories($basedir); + + if ( $fulldir =~ /^\s*(.*?inprogress\-)(\d+)(.*?)\s*$/ ) + { + my $pre_inprogress = $1; # $pre still contains "inprogress" + my $number = $2; + my $post = $3; + my $pre_witherror = $pre_inprogress; + $pre_witherror =~ s/inprogress/witherror/; + + for ( my $i = 0; $i <= $#{$alldirs}; $i++ ) + { + if ( ${$alldirs}[$i] eq $fulldir ) { next; } # do not delete the newly created directory + + if ( ${$alldirs}[$i] =~ /^\s*\Q$pre_inprogress\E\d+\Q$post\E\s*$/ ) # removing old "inprogress" directories + { + installer::systemactions::remove_complete_directory(${$alldirs}[$i], 1); + } + + if ( ${$alldirs}[$i] =~ /^\s*\Q$pre_witherror\E\d+\Q$post\E\s*$/ ) # removing old "witherror" directories + { + installer::systemactions::remove_complete_directory(${$alldirs}[$i], 1); + } + } + } +} + +############################################################### +# Creating the installation directory structure +############################################################### + +sub create_installation_directory +{ + my ($shipinstalldir, $languagestringref, $current_install_number_ref) = @_; + + my $installdir = ""; + + my $languageref = $languagestringref; + + if ( $installer::globals::updatepack ) + { + $installdir = $shipinstalldir; + installer::systemactions::create_directory_structure($installdir); + $$current_install_number_ref = installer::systemactions::determine_maximum_number($installdir, $languageref); + $installdir = installer::systemactions::rename_string_in_directory($installdir, "number", $$current_install_number_ref); + remove_old_ship_installation_sets($installdir); + } + else + { + $installdir = installer::systemactions::create_directories("install", $languageref); + installer::logger::print_message( "... creating installation set in $installdir ...\n" ); + remove_old_installation_sets($installdir); + my $inprogressinstalldir = $installdir . "_inprogress"; + installer::systemactions::rename_directory($installdir, $inprogressinstalldir); + $installdir = $inprogressinstalldir; + } + + $installer::globals::saveinstalldir = $installdir; # saving directory globally, in case of exiting + + return $installdir; +} + +############################################################### +# Analyzing and creating the log file +############################################################### + +sub analyze_and_save_logfile +{ + my ($loggingdir, $installdir, $installlogdir, $allsettingsarrayref, $languagestringref, $current_install_number) = @_; + + my $is_success = 1; + my $finalinstalldir = ""; + + installer::logger::print_message( "... checking log file " . $loggingdir . $installer::globals::logfilename . "\n" ); + + my $contains_error = installer::control::check_logfile(\@installer::globals::logfileinfo); + + # Dependent from the success, the installation directory can be renamed and mails can be send. + + if ( $contains_error ) + { + my $errordir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", "_witherror"); + if ( $installer::globals::updatepack ) { installer::mail::send_fail_mail($allsettingsarrayref, $languagestringref, $errordir); } + # Error output to STDERR + for ( my $j = 0; $j <= $#installer::globals::errorlogfileinfo; $j++ ) + { + my $line = $installer::globals::errorlogfileinfo[$j]; + $line =~ s/\s*$//g; + installer::logger::print_error( $line ); + } + $is_success = 0; + + $finalinstalldir = $errordir; + } + else + { + my $destdir = ""; + + if ( $installer::globals::updatepack ) + { + if ( $installdir =~ /_download_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_download_inprogress", "_download"); } + elsif ( $installdir =~ /_jds_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_jds_inprogress", "_jds"); } + elsif ( $installdir =~ /_msp_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_msp_inprogress", "_msp"); } + else + { + if ( $installdir =~ /_packed/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", ""); } + else { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", "_packed"); } + } + installer::mail::send_success_mail($allsettingsarrayref, $languagestringref, $destdir); + } + else + { + $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", ""); + } + + $finalinstalldir = $destdir; + } + + # Saving the logfile in the log file directory and additionally in a log directory in the install directory + + my $numberedlogfilename = $installer::globals::logfilename; + if ( $installer::globals::updatepack ) { $numberedlogfilename =~ s /log_/log_$current_install_number\_/; } + installer::logger::print_message( "... creating log file $numberedlogfilename \n" ); + installer::files::save_file($loggingdir . $numberedlogfilename, \@installer::globals::logfileinfo); + installer::files::save_file($installlogdir . $installer::globals::separator . $numberedlogfilename, \@installer::globals::logfileinfo); + + # Saving the checksumfile in a checksum directory in the install directory + # installer::worker::save_checksum_file($current_install_number, $installchecksumdir, $checksumfile); + + # Saving the list of patchfiles in a patchlist directory in the install directory + if (( $installer::globals::patch ) || ( $installer::globals::creating_windows_installer_patch )) { installer::worker::save_patchlist_file($installlogdir, $numberedlogfilename); } + + if ( $installer::globals::creating_windows_installer_patch ) { $installer::globals::creating_windows_installer_patch = 0; } + + # Exiting the packaging process, if an error occured. + # This is important, to get an error code "-1", if an error was found in the log file, + # that did not break the packaging process + + if ( ! $is_success) { installer::exiter::exit_program("ERROR: Found an error in the logfile. Packaging failed.", "analyze_and_save_logfile"); } + + return ($is_success, $finalinstalldir); +} + +############################################################### +# Analyzing and creating the log file +############################################################### + +sub save_logfile_after_linking +{ + my ($loggingdir, $installlogdir, $current_install_number) = @_; + + # Saving the logfile in the log file directory and additionally in a log directory in the install directory + my $numberedlogfilename = $installer::globals::logfilename; + if ( $installer::globals::updatepack ) { $numberedlogfilename =~ s /log_/log_$current_install_number\_/; } + installer::logger::print_message( "... creating log file $numberedlogfilename \n" ); + installer::files::save_file($loggingdir . $numberedlogfilename, \@installer::globals::logfileinfo); + installer::files::save_file($installlogdir . $installer::globals::separator . $numberedlogfilename, \@installer::globals::logfileinfo); +} + +############################################################### +# Removing all directories that are saved in the +# global directory @installer::globals::removedirs +############################################################### + +sub clean_output_tree +{ + installer::logger::print_message( "... cleaning the output tree ...\n" ); + + for ( my $i = 0; $i <= $#installer::globals::removedirs; $i++ ) + { + if ( -d $installer::globals::removedirs[$i] ) + { + installer::logger::print_message( "... removing directory $installer::globals::removedirs[$i] ...\n" ); + installer::systemactions::remove_complete_directory($installer::globals::removedirs[$i], 1); + } + } + + # Last try to remove the ship test directory + + if ( $installer::globals::shiptestdirectory ) + { + if ( -d $installer::globals::shiptestdirectory ) + { + my $infoline = "Last try to remove $installer::globals::shiptestdirectory . \n"; + push(@installer::globals::logfileinfo, $infoline); + my $systemcall = "rmdir $installer::globals::shiptestdirectory"; + my $returnvalue = system($systemcall); + } + } +} + +############################################################### +# Removing all directories that are saved in the +# global directory @installer::globals::jdsremovedirs +############################################################### + +sub clean_jds_temp_dirs +{ + installer::logger::print_message( "... cleaning jds directories ...\n" ); + + for ( my $i = 0; $i <= $#installer::globals::jdsremovedirs; $i++ ) + { + if ( -d $installer::globals::jdsremovedirs[$i] ) + { + installer::logger::print_message( "... removing directory $installer::globals::jdsremovedirs[$i] ...\n" ); + installer::systemactions::remove_complete_directory($installer::globals::jdsremovedirs[$i], 1); + } + } +} + +########################################################### +# Copying a reference array +########################################################### + +sub copy_array_from_references +{ + my ( $arrayref ) = @_; + + my @newarray = (); + + for ( my $i = 0; $i <= $#{$arrayref}; $i++ ) + { + push(@newarray, ${$arrayref}[$i]); + } + + return \@newarray; +} + +########################################################### +# Copying a reference hash +########################################################### + +sub copy_hash_from_references +{ + my ($hashref) = @_; + + my %newhash = (); + my $key; + + foreach $key (keys %{$hashref}) + { + $newhash{$key} = $hashref->{$key}; + } + + return \%newhash; +} + +########################################################### +# Setting one language in the language independent +# array of include pathes with $(LANG) +########################################################### + +sub get_language_specific_include_pathes +{ + my ( $patharrayref, $onelanguage ) = @_; + + my @patharray = (); + + for ( my $i = 0; $i <= $#{$patharrayref}; $i++ ) + { + my $line = ${$patharrayref}[$i]; + $line =~ s/\$\(LANG\)/$onelanguage/g; + push(@patharray ,$line); + } + + return \@patharray; +} + +############################################################## +# Returning the first item with a defined flag +############################################################## + +sub return_first_item_with_special_flag +{ + my ($itemsref, $flag) = @_; + + my $firstitem = ""; + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} }; + + if ( $styles =~ /\b$flag\b/ ) + { + $firstitem = $oneitem; + last; + } + } + + return $firstitem; +} + +############################################################## +# Collecting all items with a defined flag +############################################################## + +sub collect_all_items_with_special_flag +{ + my ($itemsref, $flag) = @_; + + my @allitems = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} }; + + if ( $styles =~ /\b$flag\b/ ) + { + push( @allitems, $oneitem ); + } + } + + return \@allitems; +} + +############################################################## +# Collecting all files without patch flag in +# $installer::globals::nopatchfilecollector +############################################################## + +sub collect_all_files_without_patch_flag +{ + my ($filesref) = @_; + + my $newfiles = collect_all_items_without_special_flag($filesref, "PATCH"); + + for ( my $i = 0; $i <= $#{$newfiles}; $i++ ) { push(@{$installer::globals::nopatchfilecollector}, ${$newfiles}[$i]); } +} + +############################################################## +# Collecting all items without a defined flag +############################################################## + +sub collect_all_items_without_special_flag +{ + my ($itemsref, $flag) = @_; + + my @allitems = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} }; + + if ( !( $styles =~ /\b$flag\b/ )) + { + push( @allitems, $oneitem ); + } + } + + return \@allitems; +} + +############################################################## +# Removing all items with a defined flag from collector +############################################################## + +sub remove_all_items_with_special_flag +{ + my ($itemsref, $flag) = @_; + + my @allitems = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} }; + if ( $styles =~ /\b$flag\b/ ) + { + my $infoline = "Attention: Removing from collector: $oneitem->{'Name'} !\n"; + push( @installer::globals::logfileinfo, $infoline); + if ( $flag eq "BINARYTABLE_ONLY" ) { push(@installer::globals::binarytableonlyfiles, $oneitem); } + next; + } + push( @allitems, $oneitem ); + } + + return \@allitems; +} + +########################################################### +# Mechanism for simple installation without packing +########################################################### + +sub install_simple ($$$$$$) +{ + my ($packagename, $languagestring, $directoriesarray, $filesarray, $linksarray, $unixlinksarray) = @_; + + # locate GNU cp on the system + my $gnucp = 'cp'; + if ( $ENV{'GNUCOPY'} ) { $gnucp = $ENV{'GNUCOPY'}; } + my $copyopts = '-af'; + $copyopts = '-PpRf' unless ( $ENV{'GNUCOPY'} ); # if not gnucopy, assume POSIX copy + + installer::logger::print_message( "... installing module $packagename ...\n" ); + + my $destdir = $installer::globals::destdir; + my @lines = (); + + installer::logger::print_message( "DestDir: $destdir \n" ); + installer::logger::print_message( "Rootpath: $installer::globals::rootpath \n" ); + + `mkdir -p $destdir` if $destdir ne ""; + `mkdir -p $destdir$installer::globals::rootpath`; + + # Create Directories + for ( my $i = 0; $i <= $#{$directoriesarray}; $i++ ) + { + my $onedir = ${$directoriesarray}[$i]; + my $dir = ""; + + if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; } + + if ((!($dir =~ /\bPREDEFINED_/ )) || ( $dir =~ /\bPREDEFINED_PROGDIR\b/ )) + { + # printf "mkdir $destdir$onedir->{'HostName'}\n"; + mkdir $destdir . $onedir->{'HostName'}; + push @lines, "%dir " . $onedir->{'HostName'} . "\n"; + } + } + + for ( my $i = 0; $i <= $#{$filesarray}; $i++ ) + { + my $onefile = ${$filesarray}[$i]; + my $unixrights = $onefile->{'UnixRights'}; + my $destination = $onefile->{'destination'}; + my $sourcepath = $onefile->{'sourcepath'}; + + # This is necessary to install SDK that includes files with $ in its name + # Otherwise, the following shell commands does not work and the file list + # is not correct + $destination =~ s/\$\$/\$/; + $sourcepath =~ s/\$\$/\$/; + + push @lines, "$destination\n"; + # printf "cp $sourcepath $destdir$destination\n"; + copy ("$sourcepath", "$destdir$destination") || die "Can't copy file: $sourcepath -> $destdir$destination $!"; + my $sourcestat = stat($sourcepath); + utime ($sourcestat->atime, $sourcestat->mtime, "$destdir$destination"); + chmod (oct($unixrights), "$destdir$destination") || die "Can't change permissions: $!"; + push @lines, "$destination\n"; + } + + for ( my $i = 0; $i <= $#{$linksarray}; $i++ ) + { + my $onelink = ${$linksarray}[$i]; + my $destination = $onelink->{'destination'}; + my $destinationfile = $onelink->{'destinationfile'}; + + # print "link $destinationfile -> $destdir$destination\n"; + symlink ("$destinationfile", "$destdir$destination") || die "Can't create symlink: $!"; + push @lines, "$destination\n"; + } + + for ( my $i = 0; $i <= $#{$unixlinksarray}; $i++ ) + { + my $onelink = ${$unixlinksarray}[$i]; + my $target = $onelink->{'Target'}; + my $destination = $onelink->{'destination'}; + + # print "Unix link $target -> $destdir$destination\n"; + `ln -sf '$target' '$destdir$destination'`; + push @lines, "$destination\n"; + } + + if ( $destdir ne "" ) + { + my $filelist; + my $fname = $installer::globals::destdir . "/$packagename"; + if ($installer::globals::languagepack) { $fname .= ".$languagestring"; } + open ($filelist, ">$fname") || die "Can't open $fname: $!"; + print $filelist @lines; + close ($filelist); + } + +} + +########################################################### +# Adding shellnew files into files collector for +# user installation +########################################################### + +sub add_shellnewfile_into_filesarray +{ + my ($filesref, $onefile, $inffile) = @_; + + my %shellnewfile = (); + my $shellnewfileref = \%shellnewfile; + + installer::converter::copy_item_object($inffile, $shellnewfileref); + + $shellnewfileref->{'Name'} = $onefile->{'Name'}; + $shellnewfileref->{'sourcepath'} = $onefile->{'sourcepath'}; + $shellnewfileref->{'gid'} = $onefile->{'gid'} . "_Userinstall"; + + # the destination has to be adapted + my $destination = $inffile->{'destination'}; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination); + $destination = $destination . $onefile->{'Name'}; + $shellnewfileref->{'destination'} = $destination; + + # add language specific inffile into filesarray + push(@{$filesref}, $shellnewfileref); +} + +########################################################### +# Replacing one placehoder in template file +########################################################### + +sub replace_in_template_file +{ + my ($templatefile, $placeholder, $newstring) = @_; + + for ( my $i = 0; $i <= $#{$templatefile}; $i++ ) + { + ${$templatefile}[$i] =~ s/\Q$placeholder\E/$newstring/g; + } +} + +########################################################### +# Replacing one placehoder with an array in template file +########################################################### + +sub replace_array_in_template_file +{ + my ($templatefile, $placeholder, $arrayref) = @_; + + for ( my $i = 0; $i <= $#{$templatefile}; $i++ ) + { + if ( ${$templatefile}[$i] =~ /\Q$placeholder\E/ ) + { + my @return = splice(@{$templatefile}, $i, 1, @{$arrayref}); + } + } +} + +########################################################### +# Collecting all modules from registry items +########################################################### + +sub collect_all_modules +{ + my ($registryitemsref) = @_; + + my @allmodules = (); + + for ( my $i = 0; $i <= $#{$registryitemsref}; $i++ ) + { + $registryitem = ${$registryitemsref}[$i]; + my $module = $registryitem->{'ModuleID'}; + + if ( ! installer::existence::exists_in_array($module, \@allmodules) ) + { + push(@allmodules, $module); + } + } + + return \@allmodules; +} + +########################################################### +# Changing the content of the inf file +########################################################### + +sub write_content_into_inf_file +{ + my ($templatefile, $filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $onelanguage, $inffile, $firstlanguage, $allvariableshashref) = @_; + + # First part: Shellnew files + # SHELLNEWFILESPLACEHOLDER + + my $rootmodule = 0; + # inf files can be assigned to "gid_Module_Root_Files_2" + if ( $inffile->{'modules'} =~ /Module_Root/i ) { $rootmodule = 1; } + + if ( $rootmodule ) + { + my $shellnewstring = ""; + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $onefile = ${$filesref}[$i]; + my $directory = $onefile->{'Dir'}; + + if ( $directory =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ ) + { + $shellnewstring = $shellnewstring . $onefile->{'Name'} . "\n"; + if (( $firstlanguage ) && ( ! $installer::globals::shellnewfilesadded )) { add_shellnewfile_into_filesarray($filesref, $onefile, $inffile); } + } + } + + $shellnewstring =~ s/\s*$//; + replace_in_template_file($templatefile, "SHELLNEWFILESPLACEHOLDER", $shellnewstring); + + $installer::globals::shellnewfilesadded = 1; + } + + # Second part: Start menu entries + + # The OfficeMenuFolder is defined as: $productname . " " . $productversion; + + my $productname = $allvariableshashref->{'PRODUCTNAME'}; + my $productversion = $allvariableshashref->{'PRODUCTVERSION'}; + my $productkey = $productname . " " . $productversion; + + replace_in_template_file($templatefile, "OFFICEFOLDERPLACEHOLDER", $productkey); + + # Setting name target and infotip for all applications + + for ( my $i = 0; $i <= $#{$folderitemsref}; $i++ ) + { + my $folderitem = ${$folderitemsref}[$i]; + + my $styles = ""; + if ( $folderitem->{'Styles'} ) { $styles = $folderitem->{'Styles'}; } + if ( $styles =~ /\bNON_ADVERTISED\b/ ) { next; } # no entry for non-advertised shortcuts + + if (( ! $folderitem->{'ismultilingual'} ) || (( $folderitem->{'ismultilingual'} ) && ( $folderitem->{'specificlanguage'} eq $onelanguage ))) + { + my $gid = $folderitem->{'gid'}; + my $app = $gid; + $app =~ s/gid_Folderitem_//; + $app = uc($app); + + my $name = $folderitem->{'Name'}; + my $placeholder = "PLACEHOLDER_FOLDERITEM_NAME_" . $app; + replace_in_template_file($templatefile, $placeholder, $name); + + my $tooltip = $folderitem->{'Tooltip'}; + $placeholder = "PLACEHOLDER_FOLDERITEM_TOOLTIP_" . $app; + replace_in_template_file($templatefile, $placeholder, $tooltip); + + my $executablegid = $folderitem->{'FileID'}; + my $exefile = installer::existence::get_specified_file($filesref, $executablegid); + my $exefilename = $exefile->{'Name'}; + $placeholder = "PLACEHOLDER_FOLDERITEM_TARGET_" . $app; + replace_in_template_file($templatefile, $placeholder, $exefilename); + } + } + + # Third part: Windows registry entries + + # collecting all modules + + my $allmodules = collect_all_modules($registryitemsref); + + my @registryitems = (); + my $allsectionsstring = ""; + + for ( my $j = 0; $j <= $#{$allmodules}; $j++ ) + { + my $moduleid = ${$allmodules}[$j]; + + my $inffilemodule = $inffile->{'modules'}; + # inf files can be assigned to "gid_Module_Root_Files_2", but RegistryItems to "gid_Module_Root" + if ( $inffilemodule =~ /Module_Root/i ) { $inffilemodule = $installer::globals::rootmodulegid; } + + if ( ! ( $moduleid eq $inffilemodule )) { next; } + + my $shortmodulename = $moduleid; + $shortmodulename =~ s/gid_Module_//; + my $sectionname = "InstRegKeys." . $shortmodulename; + $allsectionsstring = $allsectionsstring . $sectionname . ","; + my $sectionheader = "\[" . $sectionname . "\]" . "\n"; + push(@registryitems, $sectionheader); + + for ( my $i = 0; $i <= $#{$registryitemsref}; $i++ ) + { + my $registryitem = ${$registryitemsref}[$i]; + + if ( ! ( $registryitem->{'ModuleID'} eq $moduleid )) { next; } + + if (( ! $registryitem->{'ismultilingual'} ) || (( $registryitem->{'ismultilingual'} ) && ( $registryitem->{'specificlanguage'} eq $onelanguage ))) + { + # Syntax: HKCR,".bau",,,"soffice.StarConfigFile.6" + + my $regroot = ""; + my $parentid = ""; + if ( $registryitem->{'ParentID'} ) { $parentid = $registryitem->{'ParentID'}; } + if ( $parentid eq "PREDEFINED_HKEY_CLASSES_ROOT" ) { $regroot = "HKCR"; } + if ( $parentid eq "PREDEFINED_HKEY_LOCAL_MACHINE" ) { $regroot = "HKCU"; } + + my $subkey = ""; + if ( $registryitem->{'Subkey'} ) { $subkey = $registryitem->{'Subkey'}; } + if ( $subkey ne "" ) { $subkey = "\"" . $subkey . "\""; } + + my $valueentryname = ""; + if ( $registryitem->{'Name'} ) { $valueentryname = $registryitem->{'Name'}; } + if ( $valueentryname ne "" ) { $valueentryname = "\"" . $valueentryname . "\""; } + + my $flag = ""; + + my $value = ""; + if ( $registryitem->{'Value'} ) { $value = $registryitem->{'Value'}; } + if ( $value =~ /\<progpath\>/ ) { $value =~ s/\\\"/\"\"/g; } # Quoting for INF is done by double "" + $value =~ s/\\\"/\"/g; # no more masquerading of '"' + $value =~ s/\<progpath\>/\%INSTALLLOCATION\%/g; + if ( $value ne "" ) { $value = "\"" . $value . "\""; } + + my $oneline = $regroot . "," . $subkey . "," . $valueentryname . "," . $flag . "," . $value . "\n"; + + push(@registryitems, $oneline); + } + } + + push(@registryitems, "\n"); # empty line after each section + } + + # replacing the $allsectionsstring + $allsectionsstring =~ s/\,\s*$//; + replace_in_template_file($templatefile, "ALLREGISTRYSECTIONSPLACEHOLDER", $allsectionsstring); + + # replacing the placeholder for all registry keys + replace_array_in_template_file($templatefile, "REGISTRYKEYSPLACEHOLDER", \@registryitems); + +} + +########################################################### +# Creating inf files for local user system integration +########################################################### + +sub create_inf_file +{ + my ($filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $languagesarrayref, $languagestringref, $allvariableshashref) = @_; + + # collecting all files with flag INFFILE + + my $inf_files = collect_all_items_with_special_flag($filesref ,"INFFILE"); + + if ( $#{$inf_files} > -1 ) + { + # create new language specific inffile + installer::logger::include_header_into_logfile("Creating inf files:"); + + my $infdirname = "inffiles"; + my $infdir = installer::systemactions::create_directories($infdirname, $languagestringref); + + my $infoline = "Number of inf files: $#{$inf_files} + 1 \n"; + push( @installer::globals::logfileinfo, $infoline); + + # there are inffiles for all modules + + for ( my $i = 0; $i <= $#{$inf_files}; $i++ ) + { + my $inffile = ${$inf_files}[$i]; + my $inf_file_name = $inffile->{'Name'}; + + my $templatefilename = $inffile->{'sourcepath'}; + + if ( ! -f $templatefilename ) { installer::exiter::exit_program("ERROR: Could not find file $templatefilename !", "create_inf_file"); } + + # iterating over all languages + + for ( my $j = 0; $j <= $#{$languagesarrayref}; $j++ ) # iterating over all languages + { + my $firstlanguage = 0; + if ( $j == 0 ) { $firstlanguage = 1; } + + my $onelanguage = ${$languagesarrayref}[$j]; + + $infoline = "Templatefile: $inf_file_name, Language: $onelanguage \n"; + push( @installer::globals::logfileinfo, $infoline); + + my $templatefile = installer::files::read_file($templatefilename); + + my $linesbefore = $#{$templatefile}; + + write_content_into_inf_file($templatefile, $filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $onelanguage, $inffile, $firstlanguage, $allvariableshashref); + + $infoline = "Lines change: From $linesbefore to $#{$templatefile}.\n"; + push( @installer::globals::logfileinfo, $infoline); + + # rename language specific inffile + my $language_inf_file_name = $inf_file_name; + my $windowslanguage = installer::windows::language::get_windows_language($onelanguage); + $language_inf_file_name =~ s/\.inf/_$windowslanguage\.inf/; + + my $sourcepath = $infdir . $installer::globals::separator . $language_inf_file_name; + installer::files::save_file($sourcepath, $templatefile); + + $infoline = "Saving file: $sourcepath\n"; + push( @installer::globals::logfileinfo, $infoline); + + # creating new file object + + my %languageinffile = (); + my $languageinifileref = \%languageinffile; + + if ( $j < $#{$languagesarrayref} ) { installer::converter::copy_item_object($inffile, $languageinifileref); } + else { $languageinifileref = $inffile; } + + $languageinifileref->{'Name'} = $language_inf_file_name; + $languageinifileref->{'sourcepath'} = $sourcepath; + # destination and gid also have to be adapted + $languageinifileref->{'gid'} = $languageinifileref->{'gid'} . "_" . $onelanguage; + my $destination = $languageinifileref->{'destination'}; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination); + $destination = $destination . $language_inf_file_name; + $languageinifileref->{'destination'} = $destination; + + # add language specific inffile into filesarray + if ( $j < $#{$languagesarrayref} ) { push(@{$filesref}, $languageinifileref); } + } + } + } +} + +########################################################### +# Selecting patch items +########################################################### + +sub select_patch_items +{ + my ( $itemsref, $itemname ) = @_; + + installer::logger::include_header_into_logfile("Selecting items for patches. Item: $itemname"); + + my @itemsarray = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + + my $name = $oneitem->{'Name'}; + if (( $name =~ /\bLICENSE/ ) || ( $name =~ /\bREADME/ )) + { + push(@itemsarray, $oneitem); + next; + } + + # Items with style "PATCH" have to be included into the patch + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; } + if ( $styles =~ /\bPATCH\b/ ) { push(@itemsarray, $oneitem); } + } + + return \@itemsarray; +} + +########################################################### +# Selecting patch items +########################################################### + +sub select_patch_items_without_name +{ + my ( $itemsref, $itemname ) = @_; + + installer::logger::include_header_into_logfile("Selecting RegistryItems for patches"); + + my @itemsarray = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + + # Items with style "PATCH" have to be included into the patch + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; } + if ( $styles =~ /\bPATCH\b/ ) { push(@itemsarray, $oneitem); } + } + + return \@itemsarray; +} + +########################################################### +# Selecting patch items +########################################################### + +sub select_langpack_items +{ + my ( $itemsref, $itemname ) = @_; + + installer::logger::include_header_into_logfile("Selecting RegistryItems for Language Packs"); + + my @itemsarray = (); + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $oneitem = ${$itemsref}[$i]; + + # Items with style "LANGUAGEPACK" have to be included into the patch + my $styles = ""; + if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; } + if (( $styles =~ /\bLANGUAGEPACK\b/ ) || ( $styles =~ /\bFORCELANGUAGEPACK\b/ )) { push(@itemsarray, $oneitem); } + } + + return \@itemsarray; +} + +########################################################### +# Searching if LICENSE and README, which are not removed +# in select_patch_items are really needed for the patch. +# If not, they are removed now. +########################################################### + +sub analyze_patch_files +{ + my ( $filesref ) = @_; + + installer::logger::include_header_into_logfile("Analyzing patch files"); + + my @filesarray = (); + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $onefile = ${$filesref}[$i]; + my $styles = ""; + if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } + if ( !( $styles =~ /\bPATCH\b/) ) { next; } # removing all files without flag PATCH (LICENSE, README, ...) + + if ( $installer::globals::iswindowsbuild ) + { + # all files of the Windows patch belong to the root module + $onefile->{'modules'} = $installer::globals::rootmodulegid; + } + + push(@filesarray, $onefile); + } + + return \@filesarray; +} + +########################################################### +# Sorting an array +########################################################### + +sub sort_array +{ + my ( $arrayref ) = @_; + + for ( my $i = 0; $i <= $#{$arrayref}; $i++ ) + { + my $under = ${$arrayref}[$i]; + + for ( my $j = $i + 1; $j <= $#{$arrayref}; $j++ ) + { + my $over = ${$arrayref}[$j]; + + if ( $under gt $over) + { + ${$arrayref}[$i] = $over; + ${$arrayref}[$j] = $under; + $under = $over; + } + } + } +} + +########################################################### +# Renaming linux files with flag LINUXLINK +########################################################### + +sub prepare_linuxlinkfiles +{ + my ( $filesref ) = @_; + + @installer::globals::linuxlinks = (); # empty this array, because it could be already used + @installer::globals::linuxpatchfiles = (); # empty this array, because it could be already used + @installer::globals::allfilessav = (); # empty this array, because it could be already used. Required for forced links + + my @filesarray = (); + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $onefile = ${$filesref}[$i]; + my %linkfilehash = (); + my $linkfile = \%linkfilehash; + installer::converter::copy_item_object($onefile, $linkfile); + + my $ispatchfile = 0; + my $styles = ""; + if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } + if ( $styles =~ /\bPATCH\b/ ) { $ispatchfile = 1; } + + # Collecting all files for the mechanism with forced links + # Saving a copy + my %copyfilehash = (); + my $copyfile = \%copyfilehash; + installer::converter::copy_item_object($onefile, $copyfile); + push( @installer::globals::allfilessav, $copyfile); + + my $original_destination = $onefile->{'destination'}; + # $onefile->{'destination'} is used in the epm list file. This value can be changed now! + + if ( $ispatchfile ) { $onefile->{'destination'} = $onefile->{'destination'} . "\.$installer::globals::linuxlibrarypatchlevel"; } + else { $onefile->{'destination'} = $onefile->{'destination'} . "\.$installer::globals::linuxlibrarybaselevel"; } + + my $infoline = "LINUXLINK: Changing file destination from $original_destination to $onefile->{'destination'} !\n"; + push( @installer::globals::logfileinfo, $infoline); + + # all files without PATCH flag are included into the RPM + if ( ! $ispatchfile ) { push( @filesarray, $onefile); } + else { push( @installer::globals::linuxpatchfiles, $onefile); } + + # Preparing the collector for the links + # Setting the new file name as destination of the link + my $linkdestination = $linkfile->{'Name'}; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination); + if ( $ispatchfile ) { $linkfile->{'destinationfile'} = $linkdestination . "\.$installer::globals::linuxlibrarypatchlevel"; } + else { $linkfile->{'destinationfile'} = $linkdestination . "\.$installer::globals::linuxlibrarybaselevel"; } + push( @installer::globals::linuxlinks, $linkfile ); + + $infoline = "LINUXLINK: Created link: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + return \@filesarray; +} + +########################################################### +# Adding links into "u-RPMs", that have the flag +# FORCE_INTO_UPDATE_PACKAGE +# This is only relevant for Linux +########################################################### + +sub prepare_forced_linuxlinkfiles +{ + my ( $linksref ) = @_; + + my @linksarray = (); + + for ( my $i = 0; $i <= $#{$linksref}; $i++ ) + { + my $onelink = ${$linksref}[$i]; + + my $isforcedlink = 0; + my $styles = ""; + if ( $onelink->{'Styles'} ) { $styles = $onelink->{'Styles'}; } + if ( $styles =~ /\bFORCE_INTO_UPDATE_PACKAGE\b/ ) { $isforcedlink = 1; } + + if ( $isforcedlink ) + { + my $fileid = ""; + + if ( $onelink->{'ShortcutID'} ) + { + $fileid = $onelink->{'ShortcutID'}; + + my $searchedlinkfile = find_file_by_id($linksref, $fileid); + + # making a copy! + my %linkfilehash = (); + my $linkfile = \%linkfilehash; + installer::converter::copy_item_object($searchedlinkfile, $linkfile); + + $linkfile->{'Name'} = $onelink->{'Name'}; + $linkfile->{'destinationfile'} = $linkfile->{'destination'}; + my $linkdestination = $linkfile->{'destinationfile'}; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination); + $linkfile->{'destinationfile'} = $linkdestination; + + my $localdestination = $linkfile->{'destination'}; + # Getting the path + installer::pathanalyzer::get_path_from_fullqualifiedname(\$localdestination); + $localdestination =~ s/\Q$installer::globals::separator\E\s*$//; + $linkfile->{'destination'} = $localdestination . $installer::globals::separator . $onelink->{'Name'}; + + $infoline = "Forced link into update file: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n"; + push( @installer::globals::logfileinfo, $infoline); + + # The file, defined by the link, has to be included into the + # link array @installer::globals::linuxlinks + push( @installer::globals::linuxlinks, $linkfile ); + } + + if ( $onelink->{'FileID'} ) + { + $fileid = $onelink->{'FileID'}; + + my $searchedlinkfile = find_file_by_id(\@installer::globals::allfilessav, $fileid); + + # making a copy! + my %linkfilehash = (); + my $linkfile = \%linkfilehash; + installer::converter::copy_item_object($searchedlinkfile, $linkfile); + + $linkfile->{'Name'} = $onelink->{'Name'}; + $linkfile->{'destinationfile'} = $linkfile->{'destination'}; + my $linkdestination = $linkfile->{'destinationfile'}; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination); + $linkfile->{'destinationfile'} = $linkdestination; + + my $localdestination = $linkfile->{'destination'}; + # Getting the path + installer::pathanalyzer::get_path_from_fullqualifiedname(\$localdestination); + $localdestination =~ s/\Q$installer::globals::separator\E\s*$//; + $linkfile->{'destination'} = $localdestination . $installer::globals::separator . $onelink->{'Name'}; + + $infoline = "Forced link into update file: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n"; + push( @installer::globals::logfileinfo, $infoline); + + # The file, defined by the link, has to be included into the + # link array @installer::globals::linuxlinks + push( @installer::globals::linuxlinks, $linkfile ); + } + + if ( $fileid eq "" ) { installer::exiter::exit_program("ERROR: No FileID assigned to forced link $onelink->{'gid'} !", "prepare_forced_linuxlinkfiles"); } + + } + else + { + # Links with flag FORCE_INTO_UPDATE_PACKAGE are forced into "u"-RPM. All other + # links are included into the non-"u"-package. + push( @linksarray, $onelink ); + } + } + + return \@linksarray; +} + +########################################################### +# reorganizing the patchfile content, +# sorting for directory to decrease the file size +########################################################### + +sub reorg_patchfile +{ + my ($patchfiles, $patchfiledirectories) = @_; + + my @patchfilesarray = (); + my $line = ""; + my $directory = ""; + + # iterating over all directories, writing content into new patchfiles list + + for ( my $i = 0; $i <= $#{$patchfiledirectories}; $i++ ) + { + $directory = ${$patchfiledirectories}[$i]; + $line = "[" . $directory . "]" . "\n"; + push(@patchfilesarray, $line); + + for ( my $j = 0; $j <= $#{$patchfiles}; $j++ ) + { + # "\tXXXXX\t" . $olddestination . "\n"; + if ( ${$patchfiles}[$j] =~ /^\s*(.*?)\s*\tXXXXX\t\Q$directory\E\s*$/ ) + { + $line = $1 . "\n"; + push(@patchfilesarray, $line); + } + } + } + + return \@patchfilesarray; +} + +########################################################### +# One special file has to be the last in patchfile.txt. +# Controlling this file, guarantees, that all files were +# patch correctly. Using version.ini makes it easy to +# control this by looking into the about box +# -> shifting one section to the end +########################################################### + +sub shift_section_to_end +{ + my ($patchfilelist) = @_; + + my @patchfile = (); + my @lastsection = (); + my $lastsection = "program"; + my $notlastsection = "Basis\\program"; + my $record = 0; + + for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ ) + { + my $line = ${$patchfilelist}[$i]; + + if (( $record ) && ( $line =~ /^\s*\[/ )) { $record = 0; } + + if (( $line =~ /^\s*\[\Q$lastsection\E\\\]\s*$/ ) && ( ! ( $line =~ /\Q$notlastsection\E\\\]\s*$/ ))) { $record = 1; } + + if ( $record ) { push(@lastsection, $line); } + else { push(@patchfile, $line); } + } + + if ( $#lastsection > -1 ) + { + for ( my $i = 0; $i <= $#lastsection; $i++ ) + { + push(@patchfile, $lastsection[$i]); + } + } + + return \@patchfile; +} + +########################################################### +# One special file has to be the last in patchfile.txt. +# Controlling this file, guarantees, that all files were +# patch correctly. Using version.ini makes it easy to +# control this by looking into the about box +# -> shifting one file of the last section to the end +########################################################### + +sub shift_file_to_end +{ + my ($patchfilelist) = @_; + + my @patchfile = (); + my $lastfilename = "version.ini"; + my $lastfileline = ""; + my $foundfile = 0; + + # Only searching this file in the last section + my $lastsectionname = ""; + + for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ ) + { + my $line = ${$patchfilelist}[$i]; + if ( $line =~ /^\s*\[(.*?)\]\s*$/ ) { $lastsectionname = $1; } + } + + my $record = 0; + for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ ) + { + my $line = ${$patchfilelist}[$i]; + + if ( $line =~ /^\s*\[\Q$lastsectionname\E\]\s*$/ ) { $record = 1; } + + if (( $line =~ /^\s*\"\Q$lastfilename\E\"\=/ ) && ( $record )) + { + $lastfileline = $line; + $foundfile = 1; + $record = 0; + next; + } + + push(@patchfile, $line); + } + + if ( $foundfile ) { push(@patchfile, $lastfileline); } + + return \@patchfile; +} + +########################################################### +# Putting hash content into array and sorting it +########################################################### + +sub sort_hash +{ + my ( $hashref ) = @_; + + my $item = ""; + my @sortedarray = (); + + foreach $item (keys %{$hashref}) { push(@sortedarray, $item); } + installer::sorter::sorting_array_of_strings(\@sortedarray); + + return \@sortedarray; +} + +########################################################### +# Renaming Windows files in Patch and creating file +# patchfiles.txt +########################################################### + +sub prepare_windows_patchfiles +{ + my ( $filesref, $languagestringref, $allvariableshashref ) = @_; + + my @patchfiles = (); + my %patchfiledirectories = (); + my $patchfilename = "patchlist.txt"; + my $patchfilename2 = "patchmsi.dll"; + + if ( ! $allvariableshashref->{'WINDOWSPATCHLEVEL'} ) { installer::exiter::exit_program("ERROR: No Windows patch level defined in list file (WINDOWSPATCHLEVEL) !", "prepare_windows_patchfiles"); } + # my $windowspatchlevel = $allvariableshashref->{'WINDOWSPATCHLEVEL'}; + my $windowspatchlevel = $installer::globals::buildid; + + # the environment variable CWS_WORK_STAMP is set only in CWS + if ( $ENV{'CWS_WORK_STAMP'} ) { $windowspatchlevel = $ENV{'CWS_WORK_STAMP'} . $windowspatchlevel; } + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $onefile = ${$filesref}[$i]; + + my $filename = $onefile->{'Name'}; + if (( $filename eq $patchfilename ) || ( $filename eq $patchfilename2 )) { next; } + + my $styles = ""; + if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } + if ( $styles =~ /\bDONTRENAMEINPATCH\b/ ) { next; } + + # special handling for files with flag DONTSHOW. This files get the extension ".dontshow" to be filtered by dialogs. + my $localwindowspatchlevel = $windowspatchlevel; + if ( $styles =~ /\bDONTSHOW\b/ ) { $localwindowspatchlevel = $localwindowspatchlevel . "\.dontshow"; } + + my $olddestination = $onefile->{'destination'}; + my $newdestination = $olddestination . "." . $localwindowspatchlevel; + my $localfilename = $olddestination; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$localfilename); # file name part + my $line = "\"" . $localfilename . "\"" . "=" . "\"" . "\." . $localwindowspatchlevel . "\""; + $onefile->{'destination'} = $newdestination; + + my $newfilename = $onefile->{'Name'} . "." . $localwindowspatchlevel; + $onefile->{'Name'} = $newfilename; + + # adding section information (section is the directory) + my $origolddestination = $olddestination; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$olddestination); # directory part + if ( ! $olddestination ) { $olddestination = "_root"; } + if ( ! exists($patchfiledirectories{$olddestination}) ) { $patchfiledirectories{$olddestination} = 1; } + $line = $line . "\tXXXXX\t" . $olddestination . "\n"; + + push(@patchfiles, $line); + + # also collecting all files from patch in @installer::globals::patchfilecollector + my $patchfileline = $origolddestination . "\n"; + push(@installer::globals::patchfilecollector, $patchfileline); + } + + my $winpatchdirname = "winpatch"; + my $winpatchdir = installer::systemactions::create_directories($winpatchdirname, $languagestringref); + + my $patchlistfile = installer::existence::get_specified_file_by_name($filesref, $patchfilename); + + # reorganizing the patchfile content, sorting for directory to decrease the file size + my $sorteddirectorylist = sort_hash(\%patchfiledirectories); + my $patchfilelist = reorg_patchfile(\@patchfiles, $sorteddirectorylist); + + # shifting version.ini to the end of the list, to guarantee, that all files are patched + # if the correct version is shown in the about box + $patchfilelist = shift_section_to_end($patchfilelist); + $patchfilelist = shift_file_to_end($patchfilelist); + + # saving the file + $patchfilename = $winpatchdir . $installer::globals::separator . $patchfilename; + installer::files::save_file($patchfilename, $patchfilelist); + + my $infoline = "\nCreated list of patch files: $patchfilename\n"; + push( @installer::globals::logfileinfo, $infoline); + + # and assigning the new source + $patchlistfile->{'sourcepath'} = $patchfilename; + + # and finally checking the file size + if ( -f $patchfilename ) # test of existence + { + my $filesize = ( -s $patchfilename ); + $infoline = "Size of patch file list: $filesize\n\n"; + push( @installer::globals::logfileinfo, $infoline); + installer::logger::print_message( "... size of patch list file: $filesize Byte ... \n" ); + + # Win 98: Maximum size of ini file is 65 kB + # if ( $filesize > 64000 ) { installer::exiter::exit_program("ERROR: Maximum size of patch file list is 65 kB (Win98), now reached: $filesize Byte !", "prepare_windows_patchfiles"); } + } + +} + +########################################################### +# Replacing %-variables with the content +# of $allvariableshashref +########################################################### + +sub replace_variables_in_string +{ + my ( $string, $variableshashref ) = @_; + + if ( $string =~ /^.*\%\w+.*$/ ) + { + my $key; + + foreach $key (keys %{$variableshashref}) + { + my $value = $variableshashref->{$key}; + $key = "\%" . $key; + $string =~ s/\Q$key\E/$value/g; + } + } + + return $string; +} + +########################################################### +# Replacing %-variables with the content +# of $allvariableshashref +########################################################### + +sub replace_dollar_variables_in_string +{ + my ( $string, $variableshashref ) = @_; + + if ( $string =~ /^.*\$\{\w+\}.*$/ ) + { + my $key; + + foreach $key (keys %{$variableshashref}) + { + my $value = $variableshashref->{$key}; + $key = "\$\{" . $key . "\}"; + $string =~ s/\Q$key\E/$value/g; + } + } + + return $string; +} + +########################################################### +# The list file contains the list of packages/RPMs that +# have to be copied. +########################################################### + +sub get_all_files_from_filelist +{ + my ( $listfile, $section ) = @_; + + my @allpackages = (); + + for ( my $i = 0; $i <= $#{$listfile}; $i++ ) + { + my $line = ${$listfile}[$i]; + if ( $line =~ /^\s*\#/ ) { next; } # this is a comment line + if ( $line =~ /^\s*$/ ) { next; } # empty line + $line =~ s/^\s*//; + $line =~ s/\s*$//; + push(@allpackages, $line); + } + + return \@allpackages; +} + +########################################################### +# Getting one section from a file. Section begins with +# [xyz] and ends with file end or next [abc]. +########################################################### + +sub get_section_from_file +{ + my ($file, $sectionname) = @_; + + my @section = (); + my $record = 0; + + for ( my $i = 0; $i <= $#{$file}; $i++ ) + { + my $line = ${$file}[$i]; + + if (( $record ) && ( $line =~ /^\s*\[/ )) + { + $record = 0; + last; + } + + if ( $line =~ /^\s*\[\Q$sectionname\E\]\s*$/ ) { $record = 1; } + + if ( $line =~ /^\s*\[/ ) { next; } # this is a section line + if ( $line =~ /^\s*\#/ ) { next; } # this is a comment line + if ( $line =~ /^\s*$/ ) { next; } # empty line + $line =~ s/^\s*//; + $line =~ s/\s*$//; + if ( $record ) { push(@section, $line); } + } + + return \@section; + +} + +####################################################### +# Substituting one variable in the xml file +####################################################### + +sub replace_one_dollar_variable +{ + my ($file, $variable, $searchstring) = @_; + + for ( my $i = 0; $i <= $#{$file}; $i++ ) + { + ${$file}[$i] =~ s/\$\{$searchstring\}/$variable/g; + } +} + +####################################################### +# Substituting the variables in the xml file +####################################################### + +sub substitute_dollar_variables +{ + my ($file, $variableshashref) = @_; + + my $key; + + foreach $key (keys %{$variableshashref}) + { + my $value = $variableshashref->{$key}; + replace_one_dollar_variable($file, $value, $key); + } +} + +############################################################################# +# Collecting all packages or rpms located in the installation directory +############################################################################# + +sub get_all_packages_in_installdir +{ + my ($directory) = @_; + + my $infoline = ""; + + my @allpackages = (); + my $allpackages = \@allpackages; + + if ( $installer::globals::islinuxrpmbuild ) + { + $allpackages = installer::systemactions::find_file_with_file_extension("rpm", $directory); + } + + if ( $installer::globals::issolarisbuild ) + { + $allpackages = installer::systemactions::get_all_directories($directory); + } + + return $allpackages; +} + +############################################################### +# The list of exclude packages can contain the +# beginning of the package name, not the complete name. +############################################################### + +sub is_matching +{ + my ($onepackage, $allexcludepackages ) = @_; + + my $matches = 0; + + for ( my $i = 0; $i <= $#{$allexcludepackages}; $i++ ) + { + my $oneexcludepackage = ${$allexcludepackages}[$i]; + + if ( $onepackage =~ /^\s*$oneexcludepackage/ ) + { + $matches = 1; + last; + } + } + + return $matches; +} + +############################################################### +# Copying all Solaris packages or RPMs from installation set +############################################################### + +sub copy_all_packages +{ + my ($allexcludepackages, $sourcedir, $destdir) = @_; + + my $infoline = ""; + + $sourcedir =~ s/\/\s*$//; + $destdir =~ s/\/\s*$//; + + # $allexcludepackages is a list of RPMs and packages, that shall NOT be included into jds product + my $allpackages = get_all_packages_in_installdir($sourcedir); + + for ( my $i = 0; $i <= $#{$allpackages}; $i++ ) + { + my $onepackage = ${$allpackages}[$i]; + + my $packagename = $onepackage; + + if ( $installer::globals::issolarispkgbuild ) # on Solaris $onepackage contains the complete path + { + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$packagename); + } + + if ( ! installer::existence::exists_in_array($packagename, $allexcludepackages)) + { + if ( ! is_matching($packagename, $allexcludepackages ) ) + { + + if ( $installer::globals::islinuxrpmbuild ) + { + my $sourcepackage = $sourcedir . $installer::globals::separator . $packagename; + my $destfile = $destdir . $installer::globals::separator . $packagename; + if ( ! -f $sourcepackage ) { installer::exiter::exit_program("ERROR: Could not find RPM $sourcepackage!", "copy_all_packages"); } + installer::systemactions::hardlink_one_file($sourcepackage, $destfile); + } + + if ( $installer::globals::issolarispkgbuild ) + { + my $destinationdir = $destdir . $installer::globals::separator . $packagename; + if ( ! -d $onepackage ) { installer::exiter::exit_program("ERROR: Could not find Solaris package $onepackage!", "copy_all_packages"); } + # installer::systemactions::hardlink_complete_directory($onepackage, $destinationdir); + # installer::systemactions::copy_complete_directory($onepackage, $destinationdir); + + my $systemcall = "cp -p -R $onepackage $destinationdir"; + make_systemcall($systemcall); + } + } + else + { + $infoline = "Excluding package (matching): $onepackage\n"; + push( @installer::globals::logfileinfo, $infoline); + } + } + else + { + $infoline = "Excluding package (precise name): $onepackage\n"; + push( @installer::globals::logfileinfo, $infoline); + } + } +} + +###################################################### +# Making systemcall +###################################################### + +sub make_systemcall +{ + my ($systemcall) = @_; + + my $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } +} + +########################################################### +# Copying all Solaris packages or RPMs from solver +########################################################### + +sub copy_additional_packages +{ + my ($allcopypackages, $destdir, $includepatharrayref) = @_; + + my $infoline = "Copy additional packages into installation set.\n"; + push( @installer::globals::logfileinfo, $infoline); + + $destdir =~ s/\/\s*$//; + + for ( my $i = 0; $i <= $#{$allcopypackages}; $i++ ) + { + my $onepackage = ${$allcopypackages}[$i]; + $infoline = "Copy package: $onepackage\n"; + push( @installer::globals::logfileinfo, $infoline); + + # this package must be delivered into the solver + + my $packagesourceref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$onepackage, $includepatharrayref, 0); + if ($$packagesourceref eq "") { installer::exiter::exit_program("ERROR: Could not find jds file $onepackage!", "copy_additional_packages"); } + + if ( $onepackage =~ /\.tar\.gz\s*$/ ) + { + my $systemcall = "cd $destdir; cat $$packagesourceref | gunzip | tar -xf -"; + make_systemcall($systemcall); + } + else + { + my $destfile = $destdir . $installer::globals::separator . $onepackage; + installer::systemactions::copy_one_file($$packagesourceref, $destfile); + } + } +} + +########################################################### +# Creating jds installation sets +########################################################### + +sub create_jds_sets +{ + my ($installationdir, $allvariableshashref, $languagestringref, $languagesarrayref, $includepatharrayref) = @_; + + installer::logger::print_message( "\n******************************************\n" ); + installer::logger::print_message( "... creating jds installation set ...\n" ); + installer::logger::print_message( "******************************************\n" ); + + installer::logger::include_header_into_logfile("Creating jds installation sets:"); + + my $firstdir = $installationdir; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$firstdir); + + my $lastdir = $installationdir; + installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$lastdir); + + if ( $lastdir =~ /\./ ) { $lastdir =~ s/\./_jds_inprogress\./ } + else { $lastdir = $lastdir . "_jds_inprogress"; } + + # removing existing directory "_native_packed_inprogress" and "_native_packed_witherror" and "_native_packed" + + my $jdsdir = $firstdir . $lastdir; + if ( -d $jdsdir ) { installer::systemactions::remove_complete_directory($jdsdir); } + + my $olddir = $jdsdir; + $olddir =~ s/_inprogress/_witherror/; + if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); } + + $olddir = $jdsdir; + $olddir =~ s/_inprogress//; + if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); } + + # creating the new directory + + installer::systemactions::create_directory($jdsdir); + + $installer::globals::saveinstalldir = $jdsdir; + + # find and read jds files list + my $filelistname = $installer::globals::jdsexcludefilename; + + my $filelistnameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filelistname, "", 0); + if ($$filelistnameref eq "") { installer::exiter::exit_program("ERROR: Could not find jds list file $filelistname!", "create_jds_sets"); } + + my $listfile = installer::files::read_file($$filelistnameref); + + my $infoline = "Found jds list file: $$filelistnameref\n"; + push( @installer::globals::logfileinfo, $infoline); + + # substituting the variables + substitute_dollar_variables($listfile, $allvariableshashref); + + # determining the packages/RPMs to copy + my $allexcludepackages = get_section_from_file($listfile, "excludefiles"); + my $allcopypackages = get_section_from_file($listfile, "copyfiles"); + + # determining the source directory + my $alldirs = installer::systemactions::get_all_directories($installationdir); + my $sourcedir = ${$alldirs}[0]; # there is only one directory + + if ( $installer::globals::issolarisbuild ) { $sourcedir = $installer::globals::saved_packages_path; } + + # copy all packages/RPMs + copy_all_packages($allexcludepackages, $sourcedir, $jdsdir); + copy_additional_packages($allcopypackages, $jdsdir, $includepatharrayref); + + return $jdsdir; +} + +############################################################################# +# Checking, whether this installation set contains the correct languages +############################################################################# + +sub check_jds_language +{ + my ($allvariableshashref, $languagestringref) = @_; + + my $infoline = ""; + + # languagesarrayref and $allvariableshashref->{'JDSLANG'} + + if ( ! $allvariableshashref->{'JDSLANG'} ) { installer::exiter::exit_program("ERROR: For building JDS installation sets \"JDSLANG\" must be defined!", "check_jds_language"); } + my $languagestring = $allvariableshashref->{'JDSLANG'}; + + my $sortedarray1 = installer::converter::convert_stringlist_into_array(\$languagestring, ","); + + installer::sorter::sorting_array_of_strings($sortedarray1); + + my $sortedarray2 = installer::converter::convert_stringlist_into_array($languagestringref, "_"); + installer::sorter::sorting_array_of_strings($sortedarray2); + + my $string1 = installer::converter::convert_array_to_comma_separated_string($sortedarray1); + my $string2 = installer::converter::convert_array_to_comma_separated_string($sortedarray2); + + my $arrays_are_equal = compare_arrays($sortedarray1, $sortedarray2); + + return $arrays_are_equal; +} + +################################################################################### +# Comparing two arrays. The arrays are equal, if the complete content is equal. +################################################################################### + +sub compare_arrays +{ + my ($array1, $array2) = @_; + + my $arrays_are_equal = 1; + + # checking the size + + if ( ! ( $#{$array1} == $#{$array2} )) { $arrays_are_equal = 0; } # different size + + if ( $arrays_are_equal ) # only make further investigations if size is equal + { + for ( my $i = 0; $i <= $#{$array1}; $i++ ) + { + # ingnoring whitespaces at end and beginning + ${$array1}[$i] =~ s/^\s*//; + ${$array2}[$i] =~ s/^\s*//; + ${$array1}[$i] =~ s/\s*$//; + ${$array2}[$i] =~ s/\s*$//; + + if ( ! ( ${$array1}[$i] eq ${$array2}[$i] )) + { + $arrays_are_equal = 0; + last; + } + } + } + + return $arrays_are_equal; +} + +################################################################# +# Copying the files defined as ScpActions into the +# installation set. +################################################################# + +sub put_scpactions_into_installset +{ + my ($installdir) = @_; + + installer::logger::include_header_into_logfile("Start: Copying scp action files into installation set"); + + for ( my $i = 0; $i <= $#installer::globals::allscpactions; $i++ ) + { + my $onescpaction = $installer::globals::allscpactions[$i]; + + my $subdir = ""; + if ( $onescpaction->{'Subdir'} ) { $subdir = $onescpaction->{'Subdir'}; } + + if ( $onescpaction->{'Name'} eq "loader.exe" ) { next; } # do not copy this ScpAction loader + + my $destdir = $installdir; + $destdir =~ s/\Q$installer::globals::separator\E\s*$//; + if ( $subdir ) { $destdir = $destdir . $installer::globals::separator . $subdir; } + + my $sourcefile = $onescpaction->{'sourcepath'}; + my $destfile = $destdir . $installer::globals::separator . $onescpaction->{'DestinationName'}; + + my $styles = ""; + if ( $onescpaction->{'Styles'} ) { $styles = $onescpaction->{'Styles'}; } + if (( $styles =~ /\bFILE_CAN_MISS\b/ ) && ( $sourcefile eq "" )) { next; } + + if (( $subdir =~ /\// ) || ( $subdir =~ /\\/ )) + { + installer::systemactions::create_directory_structure($destdir); + } + else + { + installer::systemactions::create_directory($destdir); + } + + installer::systemactions::copy_one_file($sourcefile, $destfile); + + if ( $onescpaction->{'UnixRights'} ) + { + my $localcall = "chmod $onescpaction->{'UnixRights'} $destfile \>\/dev\/null 2\>\&1"; + system($localcall); + } + + } + + installer::logger::include_header_into_logfile("End: Copying scp action files into installation set"); + +} + +################################################################# +# Collecting scp actions for all languages +################################################################# + +sub collect_scpactions +{ + my ($allscpactions) = @_; + + for ( my $i = 0; $i <= $#{$allscpactions}; $i++ ) + { + push(@installer::globals::allscpactions, ${$allscpactions}[$i]); + } +} + +################################################################# +# Setting the platform name for download +################################################################# + +sub get_platform_name +{ + my $platformname = ""; + + if (( $installer::globals::islinuxintelrpmbuild ) || ( $installer::globals::islinuxinteldebbuild )) + { + $platformname = "LinuxIntel"; + } + elsif (( $installer::globals::islinuxppcrpmbuild ) || ( $installer::globals::islinuxppcdebbuild )) + { + $platformname = "LinuxPowerPC"; + } + elsif (( $installer::globals::islinuxx86_64rpmbuild ) || ( $installer::globals::islinuxx86_64debbuild )) + { + $platformname = "LinuxX86-64"; + } + elsif ( $installer::globals::issolarissparcbuild ) + { + $platformname = "SolarisSparc"; + } + elsif ( $installer::globals::issolarisx86build ) + { + $platformname = "Solarisx86"; + } + elsif ( $installer::globals::iswindowsbuild ) + { + $platformname = "Win32Intel"; + } + elsif ( $installer::globals::compiler =~ /^unxmacxi/ ) + { + $platformname = "MacOSXIntel"; + } + elsif ( $installer::globals::compiler =~ /^unxmacxp/ ) + { + $platformname = "MacOSXPowerPC"; + } + else + { + # $platformname = $installer::globals::packageformat; + $platformname = $installer::globals::compiler; + } + + return $platformname; +} + +########################################################### +# Adding additional variables into the variableshashref, +# that are defined in include files in the solver. The +# names of the include files are stored in +# ADD_INCLUDE_FILES (comma separated list). +########################################################### + +sub add_variables_from_inc_to_hashref +{ + my ($allvariables, $includepatharrayref) = @_; + + my $infoline = ""; + my $includefilelist = ""; + if ( $allvariables->{'ADD_INCLUDE_FILES'} ) { $includefilelist = $allvariables->{'ADD_INCLUDE_FILES'}; } + + my $includefiles = installer::converter::convert_stringlist_into_array_without_linebreak_and_quotes(\$includefilelist, ","); + + for ( my $i = 0; $i <= $#{$includefiles}; $i++ ) + { + my $includefilename = ${$includefiles}[$i]; + $includefilename =~ s/^\s*//; + $includefilename =~ s/\s*$//; + $includefilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$includefilename, $includepatharrayref, 1); + if ( $$includefilenameref eq "" ) { installer::exiter::exit_program("Include file $includefilename not found!\nADD_INCLUDE_FILES = $allvariables->{'ADD_INCLUDE_FILES'}", "add_variables_from_inc_to_hashref"); } + + $infoline = "Including inc file: $$includefilenameref \n"; + push( @installer::globals::globallogfileinfo, $infoline); + + my $includefile = installer::files::read_file($$includefilenameref); + + for ( my $j = 0; $j <= $#{$includefile}; $j++ ) + { + # Analyzing all "key=value" lines + my $oneline = ${$includefile}[$j]; + + if ( $oneline =~ /^\s*(\S+)\s*\=\s*(.*?)\s*$/ ) # no white space allowed in key + { + my $key = $1; + my $value = $2; + $allvariables->{$key} = $value; + $infoline = "Setting of variable: $key = $value\n"; + push( @installer::globals::globallogfileinfo, $infoline); + } + } + } + + # Allowing different Java versions for Windows and Unix. Instead of "JAVAVERSION" + # the property "WINDOWSJAVAVERSION" has to be used, if it is set. + + if ( $installer::globals::iswindowsbuild ) + { + if (( exists($allvariables->{'WINDOWSJAVAVERSION'})) && ( $allvariables->{'WINDOWSJAVAVERSION'} ne "" )) + { + $allvariables->{'JAVAVERSION'} = $allvariables->{'WINDOWSJAVAVERSION'}; + $infoline = "Changing value of property \"JAVAVERSION\" to $allvariables->{'JAVAVERSION'} (property \"WINDOWSJAVAVERSION\").\n"; + push( @installer::globals::globallogfileinfo, $infoline); + } + } +} + +############################################## +# Collecting all files from include pathes +############################################## + +sub collect_all_files_from_includepathes +{ + my ($patharrayref) = @_; + + installer::logger::globallog("Reading all directories: Start"); + installer::logger::print_message( "... reading include pathes ...\n" ); + # empty the global + + @installer::globals::allincludepathes =(); + my $infoline; + + for ( my $i = 0; $i <= $#{$patharrayref}; $i++ ) + { + $includepath = ${$patharrayref}[$i]; + installer::remover::remove_leading_and_ending_whitespaces(\$includepath); + + if ( ! -d $includepath ) + { + $infoline = "$includepath does not exist. (Can be removed from include path list?)\n"; + push( @installer::globals::globallogfileinfo, $infoline); + next; + } + + my @sourcefiles = (); + my $pathstring = ""; + # installer::systemactions::read_complete_directory($includepath, $pathstring, \@sourcefiles); + installer::systemactions::read_full_directory($includepath, $pathstring, \@sourcefiles); + + if ( ! ( $#sourcefiles > -1 )) + { + $infoline = "$includepath is empty. (Can be removed from include path list?)\n"; + push( @installer::globals::globallogfileinfo, $infoline); + } + else + { + my $number = $#sourcefiles + 1; + $infoline = "Directory $includepath contains $number files (including subdirs)\n"; + push( @installer::globals::globallogfileinfo, $infoline); + + my %allfileshash = (); + $allfileshash{'includepath'} = $includepath; + + for ( my $j = 0; $j <= $#sourcefiles; $j++ ) + { + $allfileshash{$sourcefiles[$j]} = 1; + } + + push(@installer::globals::allincludepathes, \%allfileshash); + } + } + + $installer::globals::include_pathes_read = 1; + + installer::logger::globallog("Reading all directories: End"); + push( @installer::globals::globallogfileinfo, "\n"); +} + +############################################## +# Searching for a file with the gid +############################################## + +sub find_file_by_id +{ + my ( $filesref, $gid ) = @_; + + my $foundfile = 0; + my $onefile; + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + $onefile = ${$filesref}[$i]; + my $filegid = $onefile->{'gid'}; + + if ( $filegid eq $gid ) + { + $foundfile = 1; + last; + } + } + + # It does not need to exist. For example products that do not contain the libraries. + # if (! $foundfile ) { installer::exiter::exit_program("ERROR: No unique file name found for $filename !", "get_selfreg_file"); } + + if (! $foundfile ) { $onefile = ""; } + + return $onefile; +} + +############################################## +# Searching for an item with the gid +############################################## + +sub find_item_by_gid +{ + my ( $itemsref, $gid ) = @_; + + my $founditem = 0; + my $oneitem = ""; + + for ( my $i = 0; $i <= $#{$itemsref}; $i++ ) + { + my $localitem = ${$itemsref}[$i]; + my $itemgid = $localitem->{'gid'}; + + if ( $itemgid eq $gid ) + { + $oneitem = $localitem; + $founditem = 1; + last; + } + } + + return $oneitem; +} + +######################################################### +# Calling sum +######################################################### + +sub call_sum +{ + my ($filename) = @_; + + $sumfile = "/usr/bin/sum"; + + if ( ! -f $sumfile ) { installer::exiter::exit_program("ERROR: No file /usr/bin/sum", "call_sum"); } + + my $systemcall = "$sumfile $filename |"; + + my $sumoutput = ""; + + open (SUM, "$systemcall"); + $sumoutput = <SUM>; + close (SUM); + + my $returnvalue = $?; # $? contains the return value of the systemcall + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + return $sumoutput; +} + +######################################################### +# Calling wc +# wc -c pkginfo | cut -f6 -d' ' +######################################################### + +sub call_wc +{ + my ($filename) = @_; + + $wcfile = "/usr/bin/wc"; + + if ( ! -f $wcfile ) { installer::exiter::exit_program("ERROR: No file /usr/bin/wc", "call_wc"); } + + my $systemcall = "$wcfile -c $filename |"; + + my $wcoutput = ""; + + open (WC, "$systemcall"); + $wcoutput = <WC>; + close (WC); + + my $returnvalue = $?; # $? contains the return value of the systemcall + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + return $wcoutput; +} + +############################################## +# Setting architecture ARCH=i86pc +# instead of ARCH=i386. +############################################## + +sub set_old_architecture_string +{ + my ($pkginfofile) = @_; + + for ( my $i = 0; $i <= $#{$pkginfofile}; $i++ ) + { + if ( ${$pkginfofile}[$i] =~ /^\s*ARCH=i386\s*$/ ) + { + ${$pkginfofile}[$i] =~ s/i386/i86pc/; + last; + } + } +} + +############################################## +# For the new copied package, it is necessary +# that a value for the key SUNW_REQUIRES +# is set. Otherwise this copied package +# with ARCH=i86pc would be useless. +############################################## + +sub check_requires_setting +{ + my ($pkginfofile) = @_; + + my $found = 0; + my $patchid = ""; + + for ( my $i = 0; $i <= $#{$pkginfofile}; $i++ ) + { + if ( ${$pkginfofile}[$i] =~ /^\s*SUNW_REQUIRES=(\S*?)\s*$/ ) + { + $patchid = $1; + $found = 1; + last; + } + } + + if (( ! $found ) || ( $patchid eq "" )) { installer::exiter::exit_program("ERROR: No patch id defined for SUNW_REQUIRES in patch pkginfo file!", "check_requires_setting"); } +} + +############################################## +# Setting checksum and wordcount for changed +# pkginfo file into pkgmap. +############################################## + +sub set_pkginfo_line +{ + my ($pkgmapfile, $pkginfofilename) = @_; + + # 1 i pkginfo 442 34577 1166716297 + # -> + # 1 i pkginfo 443 34737 1166716297 + # + # wc -c pkginfo | cut -f6 -d' ' -> 442 (variable) + # sum pkginfo | cut -f1 -d' ' -> 34577 (variable) + # grep 'pkginfo' pkgmap | cut -f6 -d' ' -> 1166716297 (fix) + + my $checksum = call_sum($pkginfofilename); + if ( $checksum =~ /^\s*(\d+)\s+.*$/ ) { $checksum = $1; } + + my $wordcount = call_wc($pkginfofilename); + if ( $wordcount =~ /^\s*(\d+)\s+.*$/ ) { $wordcount = $1; } + + for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ ) + { + if ( ${$pkgmapfile}[$i] =~ /(^.*\bpkginfo\b\s+)(\d+)(\s+)(\d+)(\s+)(\d+)(\s*$)/ ) + { + my $newline = $1 . $wordcount . $3 . $checksum . $5 . $6 . $7; + ${$pkgmapfile}[$i] = $newline; + last; + } + } +} + +############################################## +# Setting time stamp of copied files to avoid +# errors from pkgchk. +############################################## + +sub set_time_stamp +{ + my ($olddir, $newdir, $copyfiles) = @_; + + for ( my $i = 0; $i <= $#{$copyfiles}; $i++ ) + { + my $sourcefile = $olddir . $installer::globals::separator . ${$copyfiles}[$i]; + my $destfile = $newdir . $installer::globals::separator . ${$copyfiles}[$i]; + + my $systemcall = "touch -r $sourcefile $destfile"; + + my $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: \"$systemcall\" failed!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: \"$systemcall\" !\n"; + push( @installer::globals::logfileinfo, $infoline); + } + } +} + +############################################################ +# Generating pathes for cygwin (first version) +# This function has problems with cygwin, if $tmpfilename +# contains many thousand files (OpenOffice SDK). +############################################################ + +sub generate_cygwin_pathes_old +{ + my ($filesref) = @_; + + my ($tmpfilehandle, $tmpfilename) = tmpnam(); + open SOURCEPATHLIST, ">$tmpfilename" or die "oops...\n"; + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + print SOURCEPATHLIST "${$filesref}[$i]->{'sourcepath'}\n"; + } + close SOURCEPATHLIST; + my @cyg_sourcepathlist = qx{cygpath -w -f "$tmpfilename"}; + chomp @cyg_sourcepathlist; + unlink "$tmpfilename" or die "oops\n"; + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + ${$filesref}[$i]->{'cyg_sourcepath'} = $cyg_sourcepathlist[$i]; + } + +} + +################################################# +# Generating pathes for cygwin (second version) +# This function generates smaller files for +################################################# + +sub generate_cygwin_pathes +{ + my ($filesref) = @_; + + installer::logger::include_timestamp_into_logfile("Starting generating cygwin pathes"); + + my $infoline = "Generating cygwin pathes (generate_cygwin_pathes)\n"; + push( @installer::globals::logfileinfo, $infoline); + + my $max = 5000; # number of pathes in one file + + my @pathcollector = (); + my $startnumber = 0; + my $counter = 0; + + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + my $line = ${$filesref}[$i]->{'sourcepath'} . "\n"; + push(@pathcollector, $line); + $counter++; + + if (( $i == $#{$filesref} ) || ((( $counter % $max ) == 0 ) && ( $i > 0 ))) + { + my $tmpfilename = "cygwinhelper_" . $i . ".txt"; + my $temppath = $installer::globals::temppath; + $temppath =~ s/\Q$installer::globals::separator\E\s*$//; + $tmpfilename = $temppath . $installer::globals::separator . $tmpfilename; + $infoline = "Creating temporary file for cygwin conversion: $tmpfilename (contains $counter pathes)\n"; + push( @installer::globals::logfileinfo, $infoline); + if ( -f $tmpfilename ) { unlink $tmpfilename; } + + installer::files::save_file($tmpfilename, \@pathcollector); + + my $success = 0; + my @cyg_sourcepathlist = qx{cygpath -w -f "$tmpfilename"}; + chomp @cyg_sourcepathlist; + + # Validating the array, it has to contain the correct number of values + my $new_pathes = $#cyg_sourcepathlist + 1; + if ( $new_pathes == $counter ) { $success = 1; } + + if ($success) + { + $infoline = "Success: Successfully converted to cygwin pathes!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "ERROR: Failed to convert to cygwin pathes!\n"; + push( @installer::globals::logfileinfo, $infoline); + installer::exiter::exit_program("ERROR: Failed to convert to cygwin pathes!", "generate_cygwin_pathes"); + } + + for ( my $j = 0; $j <= $#cyg_sourcepathlist; $j++ ) + { + my $number = $startnumber + $j; + ${$filesref}[$number]->{'cyg_sourcepath'} = $cyg_sourcepathlist[$j]; + } + + if ( -f $tmpfilename ) { unlink $tmpfilename; } + + @pathcollector = (); + $startnumber = $startnumber + $max; + $counter = 0; + } + } + + # Checking existence fo cyg_sourcepath for every file + for ( my $i = 0; $i <= $#{$filesref}; $i++ ) + { + if (( ! exists(${$filesref}[$i]->{'cyg_sourcepath'}) ) || ( ${$filesref}[$i]->{'cyg_sourcepath'} eq "" )) + { + $infoline = "ERROR: No cygwin sourcepath defined for file ${$filesref}[$i]->{'sourcepath'}\n"; + push( @installer::globals::logfileinfo, $infoline); + installer::exiter::exit_program("ERROR: No cygwin sourcepath defined for file ${$filesref}[$i]->{'sourcepath'}!", "generate_cygwin_pathes"); + } + } + + installer::logger::include_timestamp_into_logfile("Ending generating cygwin pathes"); +} + +############################################## +# Include only files from install directory +# in pkgmap file. +############################################## + +sub filter_pkgmapfile +{ + my ($pkgmapfile) = @_; + + my @pkgmap = (); + + my $line = ": 1 10\n"; + push(@pkgmap, $line); + + for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ ) + { + $line = ${$pkgmapfile}[$i]; + if ( $line =~ /^\s*1\si\s/ ) { push(@pkgmap, $line); } + } + + return \@pkgmap; +} + +############################################## +# Creating double packages for Solaris x86. +# One package with ARCH=i386 and one with +# ARCH=i86pc. +############################################## + +sub fix_solaris_x86_patch +{ + my ($packagename, $subdir) = @_; + + # changing into directory of packages, important for soft linking + my $startdir = cwd(); + chdir($subdir); + + # $packagename is: "SUNWstaroffice-core01" + # Current working directory is: "<path>/install/en-US_inprogress" + + # create new folder in "packages": $packagename . ".i" + my $newpackagename = $packagename . "\.i"; + my $newdir = $newpackagename; + installer::systemactions::create_directory($newdir); + + # collecting all directories in the package + my $olddir = $packagename; + my $allsubdirs = installer::systemactions::get_all_directories_without_path($olddir); + + # link all directories from $packagename to $packagename . ".i" + for ( my $i = 0; $i <= $#{$allsubdirs}; $i++ ) + { + my $sourcedir = $olddir . $installer::globals::separator . ${$allsubdirs}[$i]; + my $destdir = $newdir . $installer::globals::separator . ${$allsubdirs}[$i]; + my $directory_depth = 2; # important for soft links, two directories already exist + installer::systemactions::softlink_complete_directory($sourcedir, $destdir, $directory_depth); + } + + # copy "pkginfo" and "pkgmap" from $packagename to $packagename . ".i" + my @allcopyfiles = ("pkginfo", "pkgmap"); + for ( my $i = 0; $i <= $#allcopyfiles; $i++ ) + { + my $sourcefile = $olddir . $installer::globals::separator . $allcopyfiles[$i]; + my $destfile = $newdir . $installer::globals::separator . $allcopyfiles[$i]; + installer::systemactions::copy_one_file($sourcefile, $destfile); + } + + # change in pkginfo in $packagename . ".i" the value for ARCH from i386 to i86pc + my $pkginfofilename = "pkginfo"; + $pkginfofilename = $newdir . $installer::globals::separator . $pkginfofilename; + + my $pkginfofile = installer::files::read_file($pkginfofilename); + set_old_architecture_string($pkginfofile); + installer::files::save_file($pkginfofilename, $pkginfofile); + + # adapt the values in pkgmap for pkginfo file, because this file was edited + my $pkgmapfilename = "pkgmap"; + $pkgmapfilename = $newdir . $installer::globals::separator . $pkgmapfilename; + + my $pkgmapfile = installer::files::read_file($pkgmapfilename); + set_pkginfo_line($pkgmapfile, $pkginfofilename); + installer::files::save_file($pkgmapfilename, $pkgmapfile); + + # changing back to startdir + chdir($startdir); +} + +################################################### +# Creating double core01 package for Solaris x86. +# One package with ARCH=i386 and one with +# ARCH=i86pc. This is necessary, to inform the +# user about the missing "small patch", if +# packages with ARCH=i86pc are installed. +################################################### + +sub fix2_solaris_x86_patch +{ + my ($packagename, $subdir) = @_; + + if ( $packagename =~ /-core01\s*$/ ) # only this one package needs to be duplicated + { + my $startdir = cwd(); + chdir($subdir); + + # $packagename is: "SUNWstaroffice-core01" + # Current working directory is: "<path>/install/en-US_inprogress" + + # create new package in "packages": $packagename . ".i" + my $olddir = $packagename; + my $newpackagename = $packagename . "\.i"; + my $newdir = $newpackagename; + + installer::systemactions::create_directory($newdir); + + my $oldinstalldir = $olddir . $installer::globals::separator . "install"; + my $newinstalldir = $newdir . $installer::globals::separator . "install"; + + installer::systemactions::copy_complete_directory($oldinstalldir, $newinstalldir); + + # setting time stamp of all copied files to avoid errors from pkgchk + my $allinstallfiles = installer::systemactions::get_all_files_from_one_directory_without_path($newinstalldir); + set_time_stamp($oldinstalldir, $newinstalldir, $allinstallfiles); + + # copy "pkginfo" and "pkgmap" from $packagename to $packagename . ".i" + my @allcopyfiles = ("pkginfo", "pkgmap"); + for ( my $i = 0; $i <= $#allcopyfiles; $i++ ) + { + my $sourcefile = $olddir . $installer::globals::separator . $allcopyfiles[$i]; + my $destfile = $newdir . $installer::globals::separator . $allcopyfiles[$i]; + installer::systemactions::copy_one_file($sourcefile, $destfile); + } + + # change in pkginfo in $packagename . ".i" the value for ARCH from i386 to i86pc + my $pkginfofilename = "pkginfo"; + $pkginfofilename = $newdir . $installer::globals::separator . $pkginfofilename; + + my $pkginfofile = installer::files::read_file($pkginfofilename); + set_old_architecture_string($pkginfofile); + check_requires_setting($pkginfofile); + installer::files::save_file($pkginfofilename, $pkginfofile); + + # adapt the values in pkgmap for pkginfo file, because this file was edited + my $pkgmapfilename = "pkgmap"; + $pkgmapfilename = $newdir . $installer::globals::separator . $pkgmapfilename; + + my $pkgmapfile = installer::files::read_file($pkgmapfilename); + set_pkginfo_line($pkgmapfile, $pkginfofilename); + $pkgmapfile = filter_pkgmapfile($pkgmapfile); + installer::files::save_file($pkgmapfilename, $pkgmapfile); + + # setting time stamp of all copied files to avoid errors from pkgchk + set_time_stamp($olddir, $newdir, \@allcopyfiles); + + # changing back to startdir + chdir($startdir); + } +} + +################################################ +# Files with flag HIDDEN get a dot at the +# beginning of the file name. This cannot be +# defined in scp2 project, because tooling +# cannot handle files with beginning dot +# correctly. +################################################ + +sub resolving_hidden_flag +{ + my ($filesarrayref, $variableshashref, $item, $languagestringref) = @_; + + my $diritem = lc($item); + my $infoline = ""; + + my $hiddendirbase = installer::systemactions::create_directories("hidden_$diritem", $languagestringref); + + installer::logger::include_header_into_logfile("$item with flag HIDDEN:"); + + for ( my $i = 0; $i <= $#{$filesarrayref}; $i++ ) + { + my $onefile = ${$filesarrayref}[$i]; + my $styles = ""; + + if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } + + if ( $styles =~ /\bHIDDEN\b/ ) + { + # Language specific subdirectory + + my $onelanguage = $onefile->{'specificlanguage'}; + + if ($onelanguage eq "") + { + $onelanguage = "00"; # files without language into directory "00" + } + + my $hiddendir = $hiddendirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; + installer::systemactions::create_directory($hiddendir); # creating language specific directories + + # copy files and edit them with the variables defined in the zip.lst + + my $onefilename = $onefile->{'Name'}; + my $newfilename = "\." . $onefilename; + my $sourcefile = $onefile->{'sourcepath'}; + my $destfile = $hiddendir . $newfilename; + + my $copysuccess = installer::systemactions::copy_one_file($sourcefile, $destfile); + + if ( $copysuccess ) + { + # $onefile->{'Name'} = $newfilename; + $onefile->{'sourcepath'} = $destfile; + $destination = $onefile->{'destination'}; + installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination); + if ( $destination eq "" ) { $onefile->{'destination'} = $newfilename; } + else { $onefile->{'destination'} = $destination . $installer::globals::separator . $newfilename; } + + $infoline = "Success: Using file with flag HIDDEN from \"$onefile->{'sourcepath'}\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Error: Failed to copy HIDDEN file from \"$sourcefile\" to \"$destfile\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + } + } + + $infoline = "\n"; + push( @installer::globals::logfileinfo, $infoline); +} + +################################################ +# Controlling that all keys in hash A are +# also key in hash B. +################################################ + +sub key_in_a_is_also_key_in_b +{ + my ( $hashref_a, $hashref_b) = @_; + + my $returnvalue = 1; + + my $key; + foreach $key ( keys %{$hashref_a} ) + { + if ( ! exists($hashref_b->{$key}) ) + { + print "*****\n"; + foreach $keyb ( keys %{$hashref_b} ) { print "$keyb : $hashref_b->{$keyb}\n"; } + print "*****\n"; + $returnvalue = 0; + } + } + + return $returnvalue; +} + +###################################################### +# Getting the first entry from a list of languages +###################################################### + +sub get_first_from_list +{ + my ( $list ) = @_; + + my $first = $list; + + if ( $list =~ /^\s*(.+?),(.+)\s*$/) # "?" for minimal matching + { + $first = $1; + } + + return $first; +} + +################################################ +# Setting all spellchecker languages +################################################ + +sub set_spellcheckerlanguages +{ + my ( $productlanguagesarrayref, $allvariables ) = @_; + + my %productlanguages = (); + for ( my $i = 0; $i <= $#{$productlanguagesarrayref}; $i++ ) { $productlanguages{${$productlanguagesarrayref}[$i]} = 1; } + + my $spellcheckfilename = $allvariables->{'SPELLCHECKERFILE'}; + + my $spellcheckfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$spellcheckfilename, "", 1); + + if ($$spellcheckfileref eq "") { installer::exiter::exit_program("ERROR: Could not find $spellcheckfilename!", "set_spellcheckerlanguages"); } + + my $infoline = "Using spellchecker file: $$spellcheckfileref \n"; + push( @installer::globals::globallogfileinfo, $infoline); + + my $spellcheckfile = installer::files::read_file($$spellcheckfileref); + my %spellcheckhash = (); + + for ( my $j = 0; $j <= $#{$spellcheckfile}; $j++ ) + { + # Analyzing all "key=value" lines + my $oneline = ${$spellcheckfile}[$j]; + + if ( $oneline =~ /^\s*(\S+)\s*\=\s*\"(.*?)\"\s*$/ ) # no white space allowed in key + { + my $onelang = $1; + my $languagelist = $2; + + # Special handling for language packs. Only include the first language of the language list. + # If no spellchecker shall be included, the keyword "EMPTY" can be used. + + if ( $installer::globals::languagepack ) + { + my $first = get_first_from_list($languagelist); + + if ( $first eq "EMPTY" ) # no spellchecker into language pack + { + $languagelist = ""; + } + else + { + $languagelist = $first; + } + } + else # no language pack, so EMPTY is not required + { + $languagelist =~ s/^\s*EMPTY\s*,//; # removing the entry EMPTY + } + + $spellcheckhash{$onelang} = $languagelist; + } + } + + # Collecting all required languages in %installer::globals::spellcheckerlanguagehash + + foreach my $lang (keys %productlanguages) + { + my $languagelist = ""; + if ( exists($spellcheckhash{$lang}) ) { $languagelist = $spellcheckhash{$lang}; } + else { $languagelist = $spellcheckhash{'en-US'}; } # defaulting to English + + my $langlisthash = installer::converter::convert_stringlist_into_hash(\$languagelist, ","); + foreach my $onelang ( keys %{$langlisthash} ) { $installer::globals::spellcheckerlanguagehash{$onelang} = 1; } + } + + $installer::globals::analyze_spellcheckerlanguage = 1; + + # Logging + + my $langstring = ""; + foreach my $lang (sort keys %installer::globals::spellcheckerlanguagehash) { $langstring = $langstring . "," . $lang } + $langstring =~ s/^\s*,//; + + $infoline = "Collected spellchecker languages for spellchecker: $langstring \n"; + push( @installer::globals::globallogfileinfo, $infoline); +} + +################################################ +# Including a license text into setup script +################################################ + +sub put_license_into_setup +{ + my ($installdir, $includepatharrayref) = @_; + + # find and read english license file + my $licenselanguage = "en-US"; # always english ! + # my $licensefilename = "LICENSE_" . $licenselanguage; + my $licensefilename = "license_" . $licenselanguage . ".txt"; + my $licenseincludepatharrayref = get_language_specific_include_pathes($includepatharrayref, $licenselanguage); + + my $licenseref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$licensefilename, $licenseincludepatharrayref, 0); + if ($$licenseref eq "") { installer::exiter::exit_program("ERROR: Could not find License file $licensefilename!", "put_license_into_setup"); } + my $licensefile = installer::files::read_file($$licenseref); + + # Read setup + my $setupfilename = $installdir . $installer::globals::separator . "setup"; + my $setupfile = installer::files::read_file($setupfilename); + + # Replacement + my $infoline = "Adding licensefile into setup script\n"; + push( @installer::globals::logfileinfo, $infoline); + + my $includestring = ""; + for ( my $i = 0; $i <= $#{$licensefile}; $i++ ) { $includestring = $includestring . ${$licensefile}[$i]; } + for ( my $i = 0; $i <= $#{$setupfile}; $i++ ) { ${$setupfile}[$i] =~ s/LICENSEFILEPLACEHOLDER/$includestring/; } + + # Write setup + installer::files::save_file($setupfilename, $setupfile); +} + +################################################ +# Setting global path to getuid.so library +################################################ + +sub set_getuid_path +{ + my ($includepatharrayref) = @_; + + my $getuidlibraryname = "getuid.so"; + my $getuidlibraryref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$getuidlibraryname, $includepatharrayref, 0); + if ($$getuidlibraryref eq "") { installer::exiter::exit_program("ERROR: Could not find $getuidlibraryname!", "set_getuid_path"); } + + $installer::globals::getuidpath = $$getuidlibraryref; + $installer::globals::getuidpathset = 1; +} + +######################################################### +# Create a tar file from the binary package +######################################################### + +sub tar_package +{ + my ( $installdir, $packagename, $tarfilename, $getuidlibrary) = @_; + + my $ldpreloadstring = ""; + if ( $getuidlibrary ne "" ) { $ldpreloadstring = "LD_PRELOAD=" . $getuidlibrary; } + + my $systemcall = "cd $installdir; $ldpreloadstring tar -cf - $packagename > $tarfilename"; + # my $systemcall = "cd $installdir; $ldpreloadstring tar -cf - * > $tarfilename"; + + my $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + my $localcall = "chmod 775 $tarfilename \>\/dev\/null 2\>\&1"; + $returnvalue = system($localcall); + + my $fulltarfile = $installdir . $installer::globals::separator . $tarfilename; + my $filesize = ( -s $fulltarfile ); + + return $filesize; +} + +######################################################### +# Create a tar file from the binary package +######################################################### + +sub untar_package +{ + my ( $installdir, $tarfilename, $getuidlibrary) = @_; + + my $ldpreloadstring = ""; + if ( $getuidlibrary ne "" ) { $ldpreloadstring = "LD_PRELOAD=" . $getuidlibrary; } + + my $systemcall = "cd $installdir; $ldpreloadstring tar -xf $tarfilename"; + + my $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: Executed \"$systemcall\" successfully!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + + my $localcall = "chmod 775 $tarfilename \>\/dev\/null 2\>\&1"; + $returnvalue = system($localcall); +} + +######################################################### +# Shuffle an array (Fisher Yates shuffle) +######################################################### + +sub shuffle_array +{ + my ( $arrayref ) = @_; + + # my $counter = 0; + # my $infoline = "Old package order: \n"; + # push( @installer::globals::logfileinfo, $infoline); + # foreach my $onepackage ( @{$arrayref} ) + # { + # $counter++; + # $infoline = "$counter: $onepackage->{'module'}\n"; + # push( @installer::globals::logfileinfo, $infoline); + # } + + my $i = @$arrayref; + while (--$i) + { + my $j = int rand ($i+1); + @$arrayref[$i,$j] = @$arrayref[$j,$i]; + } + + # $counter = 0; + # $infoline = "New package order: \n"; + # push( @installer::globals::logfileinfo, $infoline); + # foreach my $onepackage ( @{$arrayref} ) + # { + # $counter++; + # $infoline = "$counter: $onepackage->{'module'}\n"; + # push( @installer::globals::logfileinfo, $infoline); + # } +} + +################################################ +# Defining the English license text to add +# it into Solaris packages. +################################################ + +sub set_english_license +{ + my $additional_license_name = $installer::globals::englishsolarislicensename; # always the English file + my $licensefileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$additional_license_name, "" , 0); + if ( $$licensefileref eq "" ) { installer::exiter::exit_program("ERROR: Could not find license file $additional_license_name!", "set_english_license"); } + $installer::globals::englishlicenseset = 1; + $installer::globals::englishlicense = installer::files::read_file($$licensefileref); + installer::scpzipfiles::replace_all_ziplistvariables_in_file($installer::globals::englishlicense, $variableshashref); +} + +############################################## +# Setting time stamp of copied files to avoid +# errors from pkgchk. +############################################## + +sub set_time_stamp_for_file +{ + my ($sourcefile, $destfile) = @_; + + my $systemcall = "touch -r $sourcefile $destfile"; + + my $returnvalue = system($systemcall); + + my $infoline = "Systemcall: $systemcall\n"; + push( @installer::globals::logfileinfo, $infoline); + + if ($returnvalue) + { + $infoline = "ERROR: \"$systemcall\" failed!\n"; + push( @installer::globals::logfileinfo, $infoline); + } + else + { + $infoline = "Success: \"$systemcall\" !\n"; + push( @installer::globals::logfileinfo, $infoline); + } +} + +############################################## +# Setting checksum and wordcount for changed +# pkginfo file into pkgmap. +############################################## + +sub change_onefile_in_pkgmap +{ + my ($pkgmapfile, $fullfilename, $shortfilename) = @_; + + # 1 i pkginfo 442 34577 1166716297 + # -> + # 1 i pkginfo 443 34737 1166716297 + # + # wc -c pkginfo | cut -f6 -d' ' -> 442 (variable) + # sum pkginfo | cut -f1 -d' ' -> 34577 (variable) + # grep 'pkginfo' pkgmap | cut -f6 -d' ' -> 1166716297 (fix) + + my $checksum = call_sum($fullfilename); + if ( $checksum =~ /^\s*(\d+)\s+.*$/ ) { $checksum = $1; } + + my $wordcount = call_wc($fullfilename); + if ( $wordcount =~ /^\s*(\d+)\s+.*$/ ) { $wordcount = $1; } + + for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ ) + { + if ( ${$pkgmapfile}[$i] =~ /(^.*\b\Q$shortfilename\E\b\s+)(\d+)(\s+)(\d+)(\s+)(\d+)(\s*$)/ ) + { + my $newline = $1 . $wordcount . $3 . $checksum . $5 . $6 . $7; + ${$pkgmapfile}[$i] = $newline; + last; + } + } +} + +################################################ +# Adding the content of the English license +# file into the system integration packages. +################################################ + +sub add_license_into_systemintegrationpackages +{ + my ($destdir, $packages) = @_; + + for ( my $i = 0; $i <= $#{$packages}; $i++ ) + { + my $copyrightfilename = ${$packages}[$i] . $installer::globals::separator . "install" . $installer::globals::separator . "copyright"; + if ( ! -f $copyrightfilename ) { installer::exiter::exit_program("ERROR: Could not find license file in system integration package: $copyrightfilename!", "add_license_into_systemintegrationpackages"); } + my $copyrightfile = installer::files::read_file($copyrightfilename); + + # Saving time stamp of old copyrightfile + my $savcopyrightfilename = $copyrightfilename . ".sav"; + installer::systemactions::copy_one_file($copyrightfilename, $savcopyrightfilename); + set_time_stamp_for_file($copyrightfilename, $savcopyrightfilename); # now $savcopyrightfile has the time stamp of $copyrightfile + + # Adding license content to copyright file + push(@{$copyrightfile}, "\n"); + for ( my $i = 0; $i <= $#{$installer::globals::englishlicense}; $i++ ) { push(@{$copyrightfile}, ${$installer::globals::englishlicense}[$i]); } + installer::files::save_file($copyrightfilename, $copyrightfile); + + # Setting the old time stamp saved with $savcopyrightfilename + set_time_stamp_for_file($savcopyrightfilename, $copyrightfilename); # now $copyrightfile has the time stamp of $savcopyrightfile + unlink($savcopyrightfilename); + + # Changing content of copyright file in pkgmap + my $pkgmapfilename = ${$packages}[$i] . $installer::globals::separator . "pkgmap"; + if ( ! -f $pkgmapfilename ) { installer::exiter::exit_program("ERROR: Could not find pkgmap in system integration package: $pkgmapfilename!", "add_license_into_systemintegrationpackages"); } + my $pkgmap = installer::files::read_file($pkgmapfilename); + change_onefile_in_pkgmap($pkgmap, $copyrightfilename, "copyright"); + installer::files::save_file($pkgmapfilename, $pkgmap); + } +} + +######################################################### +# Collecting all pkgmap files from an installation set +######################################################### + +sub collectpackagemaps +{ + my ( $installdir, $languagestringref, $allvariables ) = @_; + + installer::logger::include_header_into_logfile("Collecing all packagemaps (pkgmap):"); + + my $pkgmapdir = installer::systemactions::create_directories("pkgmap", $languagestringref); + my $subdirname = $allvariables->{'UNIXPRODUCTNAME'} . "_pkgmaps"; + my $pkgmapsubdir = $pkgmapdir . $installer::globals::separator . $subdirname; + if ( -d $pkgmapsubdir ) { installer::systemactions::remove_complete_directory($pkgmapsubdir); } + if ( ! -d $pkgmapsubdir ) { installer::systemactions::create_directory($pkgmapsubdir); } + + $installdir =~ s/\/\s*$//; + # Collecting all packages in $installdir and its sub package ("packages") + my $searchdir = $installdir . $installer::globals::separator . $installer::globals::epmoutpath; + + my $allpackages = installer::systemactions::get_all_directories_without_path($searchdir); + + for ( my $i = 0; $i <= $#{$allpackages}; $i++ ) + { + my $pkgmapfile = $searchdir . $installer::globals::separator . ${$allpackages}[$i] . $installer::globals::separator . "pkgmap"; + my $destfilename = $pkgmapsubdir . $installer::globals::separator . ${$allpackages}[$i] . "_pkgmap"; + installer::systemactions::copy_one_file($pkgmapfile, $destfilename); + } + + # Create a tar gz file with all package maps + my $tarfilename = $subdirname . ".tar"; + my $targzname = $tarfilename . ".gz"; + # my $systemcall = "cd $pkgmapdir; tar -cf - $subdirname > $tarfilename"; + $systemcall = "cd $pkgmapdir; tar -cf - $subdirname | gzip > $targzname"; + make_systemcall($systemcall); + installer::systemactions::remove_complete_directory($pkgmapsubdir, 1); +} + +1; |