xref: /AOO41X/main/solenv/bin/modules/installer/worker.pm (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22
23
24package installer::worker;
25
26use Cwd;
27use File::Copy;
28use File::stat;
29use File::Temp qw(tmpnam);
30use installer::control;
31use installer::converter;
32use installer::existence;
33use installer::exiter;
34use installer::files;
35use installer::globals;
36use installer::logger;
37use installer::mail;
38use installer::pathanalyzer;
39use installer::scpzipfiles;
40use installer::scriptitems;
41use installer::sorter;
42use installer::systemactions;
43use installer::windows::language;
44
45#####################################################################
46# Unpacking all files ending with tar.gz in a specified directory
47#####################################################################
48
49sub unpack_all_targzfiles_in_directory
50{
51    my ( $directory ) = @_;
52
53    installer::logger::include_header_into_logfile("Unpacking tar.gz files:");
54
55    installer::logger::print_message( "... unpacking tar.gz files ... \n" );
56
57    my $localdirectory = $directory . $installer::globals::separator . "packages";
58    my $alltargzfiles = installer::systemactions::find_file_with_file_extension("tar.gz", $localdirectory);
59
60    for ( my $i = 0; $i <= $#{$alltargzfiles}; $i++ )
61    {
62        my $onefile = $localdirectory . $installer::globals::separator . ${$alltargzfiles}[$i];
63
64        my $systemcall = "cd $localdirectory; cat ${$alltargzfiles}[$i] \| gunzip \| tar -xf -";
65        $returnvalue = system($systemcall);
66
67        my $infoline = "Systemcall: $systemcall\n";
68        push( @installer::globals::logfileinfo, $infoline);
69
70        if ($returnvalue)
71        {
72            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
73            push( @installer::globals::logfileinfo, $infoline);
74        }
75        else
76        {
77            $infoline = "Success: Executed \"$systemcall\" successfully!\n";
78            push( @installer::globals::logfileinfo, $infoline);
79        }
80    }
81}
82
83#########################################
84# Copying installation sets to ship
85#########################################
86
87sub copy_install_sets_to_ship
88{
89    my ( $destdir, $shipinstalldir  ) = @_;
90
91    installer::logger::include_header_into_logfile("Copying installation set to ship:");
92
93    my $dirname = $destdir;
94    installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname);
95    $dirname = $dirname . "_inprogress";
96    my $localshipinstalldir = $shipinstalldir . $installer::globals::separator . $dirname;
97    if ( ! -d $localshipinstalldir ) { installer::systemactions::create_directory_structure($localshipinstalldir); }
98
99    # copy installation set to /ship ($localshipinstalldir)
100    installer::logger::print_message( "... copy installation set from " . $destdir . " to " . $localshipinstalldir . "\n" );
101    installer::systemactions::copy_complete_directory($destdir, $localshipinstalldir);
102
103    if (( ! $installer::globals::iswindowsbuild ) && ( $installer::globals::addjavainstaller ))
104    {
105        # Setting Unix rights for Java starter ("setup")
106        my $localcall = "chmod 775 $localshipinstalldir/setup \>\/dev\/null 2\>\&1";
107        system($localcall);
108    }
109
110    # unpacking the tar.gz file for Solaris
111    if ( $installer::globals::issolarisbuild ) { unpack_all_targzfiles_in_directory($localshipinstalldir); }
112
113    $localshipinstalldir = installer::systemactions::rename_string_in_directory($localshipinstalldir, "_inprogress", "");
114
115    return $localshipinstalldir;
116}
117
118#########################################
119# Copying installation sets to ship
120#########################################
121
122sub link_install_sets_to_ship
123{
124    my ( $destdir, $shipinstalldir  ) = @_;
125
126    installer::logger::include_header_into_logfile("Linking installation set to ship:");
127
128    my $infoline = "... destination directory: $shipinstalldir ...\n";
129    installer::logger::print_message( $infoline );
130    push( @installer::globals::logfileinfo, $infoline);
131
132    if ( ! -d $shipinstalldir)
133    {
134        $infoline = "Creating directory: $shipinstalldir\n";
135        push( @installer::globals::logfileinfo, $infoline);
136        installer::systemactions::create_directory_structure($shipinstalldir);
137        $infoline = "Created directory: $shipinstalldir\n";
138        push( @installer::globals::logfileinfo, $infoline);
139    }
140
141    my $dirname = $destdir;
142    installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname);
143
144    my $localshipinstalldir = $shipinstalldir . $installer::globals::separator . $dirname;
145
146    # link installation set to /ship ($localshipinstalldir)
147    installer::logger::print_message( "... linking installation set from " . $destdir . " to " . $localshipinstalldir . "\n" );
148
149    my $systemcall = "ln -s $destdir $localshipinstalldir";
150
151    $returnvalue = system($systemcall);
152
153    $infoline = "Systemcall: $systemcall\n";
154    push( @installer::globals::logfileinfo, $infoline);
155
156    if ($returnvalue)
157    {
158        $infoline = "ERROR: Could not create link \"$localshipinstalldir\"!\n";
159        push( @installer::globals::logfileinfo, $infoline);
160    }
161    else
162    {
163        $infoline = "Success: Created link \"$localshipinstalldir\"!\n";
164        push( @installer::globals::logfileinfo, $infoline);
165    }
166
167    return $localshipinstalldir;
168}
169
170#########################################
171# Create checksum file
172#########################################
173
174sub make_checksum_file
175{
176    my ( $filesref, $includepatharrayref ) = @_;
177
178    my @checksum = ();
179
180    my $checksumfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$installer::globals::checksumfile, $includepatharrayref, 1);
181    if ( $$checksumfileref eq "" ) { installer::exiter::exit_program("ERROR: Could not find file $installer::globals::checksumfile !", "make_checksum_file"); }
182
183#   # very slow on Windows
184#   for ( my $i = 0; $i <= $#{$filesref}; $i++ )
185#   {
186#       my $onefile = ${$filesref}[$i];
187#       my $systemcall = "$$checksumfileref $onefile->{'sourcepath'} |";
188#       open (CHECK, "$systemcall");
189#       my $localchecksum = <CHECK>;
190#       close (CHECK);
191#       push(@checksum, $localchecksum);
192#   }
193
194    my $systemcall = "$$checksumfileref";
195
196    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
197    {
198        my $onefile = ${$filesref}[$i];
199        $systemcall = $systemcall . " " . $onefile->{'sourcepath'};     # very very long systemcall
200
201        if ((( $i > 0 ) &&  ( $i%100 == 0 )) || ( $i == $#{$filesref} ))    # limiting to 100 files
202        {
203            $systemcall = $systemcall . " \|";
204
205            my @localchecksum = ();
206            open (CHECK, "$systemcall");
207            @localchecksum = <CHECK>;
208            close (CHECK);
209
210            for ( my $j = 0; $j <= $#localchecksum; $j++ ) { push(@checksum, $localchecksum[$j]); }
211
212            $systemcall = "$$checksumfileref";  # reset the system call
213        }
214    }
215
216    return \@checksum;
217}
218
219#########################################
220# Saving the checksum file
221#########################################
222
223sub save_checksum_file
224{
225    my ($current_install_number, $installchecksumdir, $checksumfile) = @_;
226
227    my $numberedchecksumfilename = $installer::globals::checksumfilename;
228    $numberedchecksumfilename =~ s/\./_$current_install_number\./;  # checksum.txt -> checksum_01.txt
229    installer::files::save_file($installchecksumdir . $installer::globals::separator . $numberedchecksumfilename, $checksumfile);
230}
231
232#################################################
233# Writing some global information into
234# the list of files without flag PATCH
235#################################################
236
237sub write_nopatchlist_header
238{
239    my ( $content ) = @_;
240
241    my @header = ();
242    my $infoline = "This is a list of files, that are defined in scp-projects without\n";
243    push(@header, $infoline);
244    $infoline = "flag \"PATCH\". Important: This does not mean in any case, that \n";
245    push(@header, $infoline);
246    $infoline = "this files are included into or excluded from a patch. \n\n";
247    push(@header, $infoline);
248    $infoline = "Exception Linux: A patch rpm is a complete rpm. This means that all \n";
249    push(@header, $infoline);
250    $infoline = "files are included into a patch rpm, if only one file of the rpm has the \n";
251    push(@header, $infoline);
252    $infoline = "style \"PATCH\". \n\n";
253    push(@header, $infoline);
254
255    for ( my $i = 0; $i <= $#header; $i++ ) { push(@{$content},$header[$i]); }
256}
257
258#################################################
259# Creating the content of the list of files
260# without flag PATCH.
261# All files are saved in
262# @{$installer::globals::nopatchfilecollector}
263#################################################
264
265sub create_nopatchlist
266{
267    my @content =();
268
269    write_nopatchlist_header(\@content);
270
271    for ( my $i = 0; $i <= $#{$installer::globals::nopatchfilecollector}; $i++ )
272    {
273        my $onefile = ${$installer::globals::nopatchfilecollector}[$i];
274        my $oneline = $onefile->{'destination'};
275        if ( $onefile->{'zipfilename'} ) { $oneline = $oneline . " (" . $onefile->{'zipfilename'} . ")"; }
276        $oneline = $oneline . "\n";
277        push(@content, $oneline);
278    }
279
280    return \@content;
281}
282
283#########################################
284# Saving the patchlist file
285#########################################
286
287sub save_patchlist_file
288{
289    my ($installlogdir, $patchlistfilename) = @_;
290
291    my $installpatchlistdir = installer::systemactions::create_directory_next_to_directory($installlogdir, "patchlist");
292    $patchlistfilename =~ s/log\_/patchfiles\_/;
293    $patchlistfilename =~ s/\.log/\.txt/;
294    installer::files::save_file($installpatchlistdir . $installer::globals::separator . $patchlistfilename, \@installer::globals::patchfilecollector);
295    installer::logger::print_message( "... creating patchlist file $patchlistfilename \n" );
296
297    if (( $installer::globals::patch ) && ( ! $installer::globals::creating_windows_installer_patch ))  # only for non-Windows patches
298    {
299        $patchlistfilename =~ s/patchfiles\_/nopatchfiles\_/;
300        my $nopatchlist = create_nopatchlist();
301        installer::files::save_file($installpatchlistdir . $installer::globals::separator . $patchlistfilename, $nopatchlist);
302        installer::logger::print_message( "... creating patch exclusion file $patchlistfilename \n" );
303    }
304
305}
306
307###############################################################
308# Removing all directories of a special language
309# in the directory $basedir
310###############################################################
311
312sub remove_old_installation_sets
313{
314    my ($basedir) = @_;
315
316    installer::logger::print_message( "... removing old installation directories ...\n" );
317
318    my $removedir = $basedir;
319
320    if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); }
321
322    # looking for non successful old installation sets
323
324    $removedir = $basedir . "_witherror";
325    if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); }
326
327    $removedir = $basedir . "_inprogress";
328    if ( -d $removedir ) { installer::systemactions::remove_complete_directory($removedir, 1); }
329
330    # finally the $basedir can be created empty
331
332    if ( $installer::globals::localinstalldirset ) { installer::systemactions::create_directory_structure($basedir); }
333
334    installer::systemactions::create_directory($basedir);
335}
336
337###############################################################
338# Removing all non successful installation sets on ship
339###############################################################
340
341sub remove_old_ship_installation_sets
342{
343    my ($fulldir, $counter) = @_;
344
345    installer::logger::print_message( "... removing old installation directories ...\n" );
346
347    my $basedir = $fulldir;
348    installer::pathanalyzer::get_path_from_fullqualifiedname(\$basedir);
349
350    # collecting all directories next to the new installation directory
351    my $alldirs = installer::systemactions::get_all_directories($basedir);
352
353    if ( $fulldir =~ /^\s*(.*?inprogress\-)(\d+)(.*?)\s*$/ )
354    {
355        my $pre_inprogress = $1;        # $pre still contains "inprogress"
356        my $number = $2;
357        my $post = $3;
358        my $pre_witherror = $pre_inprogress;
359        $pre_witherror =~ s/inprogress/witherror/;
360
361        for ( my $i = 0; $i <= $#{$alldirs}; $i++ )
362        {
363            if ( ${$alldirs}[$i] eq $fulldir ) { next; }    # do not delete the newly created directory
364
365            if ( ${$alldirs}[$i] =~ /^\s*\Q$pre_inprogress\E\d+\Q$post\E\s*$/ ) # removing old "inprogress" directories
366            {
367                installer::systemactions::remove_complete_directory(${$alldirs}[$i], 1);
368            }
369
370            if ( ${$alldirs}[$i] =~ /^\s*\Q$pre_witherror\E\d+\Q$post\E\s*$/ )  # removing old "witherror" directories
371            {
372                installer::systemactions::remove_complete_directory(${$alldirs}[$i], 1);
373            }
374        }
375    }
376}
377
378###############################################################
379# Creating the installation directory structure
380###############################################################
381
382sub create_installation_directory
383{
384    my ($shipinstalldir, $languagestringref, $current_install_number_ref) = @_;
385
386    my $installdir = "";
387
388    my $languageref = $languagestringref;
389
390    if ( $installer::globals::updatepack )
391    {
392        $installdir = $shipinstalldir;
393        installer::systemactions::create_directory_structure($installdir);
394        $$current_install_number_ref = installer::systemactions::determine_maximum_number($installdir, $languageref);
395        $installdir = installer::systemactions::rename_string_in_directory($installdir, "number", $$current_install_number_ref);
396        remove_old_ship_installation_sets($installdir);
397    }
398    else
399    {
400        $installdir = installer::systemactions::create_directories("install", $languageref);
401        installer::logger::print_message( "... creating installation set in $installdir ...\n" );
402        remove_old_installation_sets($installdir);
403        my $inprogressinstalldir = $installdir . "_inprogress";
404        installer::systemactions::rename_directory($installdir, $inprogressinstalldir);
405        $installdir = $inprogressinstalldir;
406    }
407
408    $installer::globals::saveinstalldir = $installdir;  # saving directory globally, in case of exiting
409
410    return $installdir;
411}
412
413###############################################################
414# Analyzing and creating the log file
415###############################################################
416
417sub analyze_and_save_logfile
418{
419    my ($loggingdir, $installdir, $installlogdir, $allsettingsarrayref, $languagestringref, $current_install_number) = @_;
420
421    my $is_success = 1;
422    my $finalinstalldir = "";
423
424    installer::logger::print_message( "... checking log file " . $loggingdir . $installer::globals::logfilename . "\n" );
425
426    my $contains_error = installer::control::check_logfile(\@installer::globals::logfileinfo);
427
428    # Dependent from the success, the installation directory can be renamed and mails can be send.
429
430    if ( $contains_error )
431    {
432        my $errordir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", "_witherror");
433        if ( $installer::globals::updatepack ) { installer::mail::send_fail_mail($allsettingsarrayref, $languagestringref, $errordir); }
434        # Error output to STDERR
435        for ( my $j = 0; $j <= $#installer::globals::errorlogfileinfo; $j++ )
436        {
437            my $line = $installer::globals::errorlogfileinfo[$j];
438            $line =~ s/\s*$//g;
439            installer::logger::print_error( $line );
440        }
441        $is_success = 0;
442
443        $finalinstalldir = $errordir;
444    }
445    else
446    {
447        my $destdir = "";
448
449        if ( $installer::globals::updatepack )
450        {
451            if ( $installdir =~ /_download_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_download_inprogress", "_download"); }
452            elsif ( $installdir =~ /_jds_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_jds_inprogress", "_jds"); }
453            elsif ( $installdir =~ /_msp_inprogress/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_msp_inprogress", "_msp"); }
454            else
455            {
456                if ( $installdir =~ /_packed/ ) { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", ""); }
457                else { $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", "_packed"); }
458            }
459            installer::mail::send_success_mail($allsettingsarrayref, $languagestringref, $destdir);
460        }
461        else
462        {
463            $destdir = installer::systemactions::rename_string_in_directory($installdir, "_inprogress", "");
464        }
465
466        $finalinstalldir = $destdir;
467    }
468
469    # Saving the logfile in the log file directory and additionally in a log directory in the install directory
470
471    my $numberedlogfilename = $installer::globals::logfilename;
472    if ( $installer::globals::updatepack ) { $numberedlogfilename =~ s /log_/log_$current_install_number\_/; }
473    installer::logger::print_message( "... creating log file $numberedlogfilename \n" );
474    installer::files::save_file($loggingdir . $numberedlogfilename, \@installer::globals::logfileinfo);
475    installer::files::save_file($installlogdir . $installer::globals::separator . $numberedlogfilename, \@installer::globals::logfileinfo);
476
477    # Saving the checksumfile in a checksum directory in the install directory
478    # installer::worker::save_checksum_file($current_install_number, $installchecksumdir, $checksumfile);
479
480    # Saving the list of patchfiles in a patchlist directory in the install directory
481    if (( $installer::globals::patch ) || ( $installer::globals::creating_windows_installer_patch )) { installer::worker::save_patchlist_file($installlogdir, $numberedlogfilename); }
482
483    if ( $installer::globals::creating_windows_installer_patch ) { $installer::globals::creating_windows_installer_patch = 0; }
484
485    # Exiting the packaging process, if an error occured.
486    # This is important, to get an error code "-1", if an error was found in the log file,
487    # that did not break the packaging process
488
489    if ( ! $is_success) { installer::exiter::exit_program("ERROR: Found an error in the logfile. Packaging failed.", "analyze_and_save_logfile"); }
490
491    return ($is_success, $finalinstalldir);
492}
493
494###############################################################
495# Analyzing and creating the log file
496###############################################################
497
498sub save_logfile_after_linking
499{
500    my ($loggingdir, $installlogdir, $current_install_number) = @_;
501
502    # Saving the logfile in the log file directory and additionally in a log directory in the install directory
503    my $numberedlogfilename = $installer::globals::logfilename;
504    if ( $installer::globals::updatepack ) { $numberedlogfilename =~ s /log_/log_$current_install_number\_/; }
505    installer::logger::print_message( "... creating log file $numberedlogfilename \n" );
506    installer::files::save_file($loggingdir . $numberedlogfilename, \@installer::globals::logfileinfo);
507    installer::files::save_file($installlogdir . $installer::globals::separator . $numberedlogfilename, \@installer::globals::logfileinfo);
508}
509
510###############################################################
511# Removing all directories that are saved in the
512# global directory @installer::globals::removedirs
513###############################################################
514
515sub clean_output_tree
516{
517    installer::logger::print_message( "... cleaning the output tree ...\n" );
518
519    for ( my $i = 0; $i <= $#installer::globals::removedirs; $i++ )
520    {
521        if ( -d $installer::globals::removedirs[$i] )
522        {
523            installer::logger::print_message( "... removing directory $installer::globals::removedirs[$i] ...\n" );
524            installer::systemactions::remove_complete_directory($installer::globals::removedirs[$i], 1);
525        }
526    }
527
528    # Last try to remove the ship test directory
529
530    if ( $installer::globals::shiptestdirectory )
531    {
532        if ( -d $installer::globals::shiptestdirectory )
533        {
534            my $infoline = "Last try to remove $installer::globals::shiptestdirectory . \n";
535            push(@installer::globals::logfileinfo, $infoline);
536            my $systemcall = "rmdir $installer::globals::shiptestdirectory";
537            my $returnvalue = system($systemcall);
538        }
539    }
540}
541
542###############################################################
543# Removing all directories that are saved in the
544# global directory @installer::globals::jdsremovedirs
545###############################################################
546
547sub clean_jds_temp_dirs
548{
549    installer::logger::print_message( "... cleaning jds directories ...\n" );
550
551    for ( my $i = 0; $i <= $#installer::globals::jdsremovedirs; $i++ )
552    {
553        if ( -d $installer::globals::jdsremovedirs[$i] )
554        {
555            installer::logger::print_message( "... removing directory $installer::globals::jdsremovedirs[$i] ...\n" );
556            installer::systemactions::remove_complete_directory($installer::globals::jdsremovedirs[$i], 1);
557        }
558    }
559}
560
561###########################################################
562# Copying a reference array
563###########################################################
564
565sub copy_array_from_references
566{
567    my ( $arrayref ) = @_;
568
569    my @newarray = ();
570
571    for ( my $i = 0; $i <= $#{$arrayref}; $i++ )
572    {
573        push(@newarray, ${$arrayref}[$i]);
574    }
575
576    return \@newarray;
577}
578
579###########################################################
580# Copying a reference hash
581###########################################################
582
583sub copy_hash_from_references
584{
585    my ($hashref) = @_;
586
587    my %newhash = ();
588    my $key;
589
590    foreach $key (keys %{$hashref})
591    {
592        $newhash{$key} = $hashref->{$key};
593    }
594
595    return \%newhash;
596}
597
598###########################################################
599# Setting one language in the language independent
600# array of include pathes with $(LANG)
601###########################################################
602
603sub get_language_specific_include_pathes
604{
605    my ( $patharrayref, $onelanguage ) = @_;
606
607    my @patharray = ();
608
609    for ( my $i = 0; $i <= $#{$patharrayref}; $i++ )
610    {
611        my $line = ${$patharrayref}[$i];
612        $line =~ s/\$\(LANG\)/$onelanguage/g;
613        push(@patharray ,$line);
614    }
615
616    return \@patharray;
617}
618
619##############################################################
620# Returning the first item with a defined flag
621##############################################################
622
623sub return_first_item_with_special_flag
624{
625    my ($itemsref, $flag) = @_;
626
627    my $firstitem = "";
628
629    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
630    {
631        my $oneitem = ${$itemsref}[$i];
632        my $styles = "";
633        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} };
634
635        if ( $styles =~ /\b$flag\b/ )
636        {
637            $firstitem = $oneitem;
638            last;
639        }
640    }
641
642    return $firstitem;
643}
644
645##############################################################
646# Collecting all items with a defined flag
647##############################################################
648
649sub collect_all_items_with_special_flag
650{
651    my ($itemsref, $flag) = @_;
652
653    my @allitems = ();
654
655    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
656    {
657        my $oneitem = ${$itemsref}[$i];
658        my $styles = "";
659        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} };
660
661        if ( $styles =~ /\b$flag\b/ )
662        {
663            push( @allitems, $oneitem );
664        }
665    }
666
667    return \@allitems;
668}
669
670##############################################################
671# Collecting all files without patch flag in
672# $installer::globals::nopatchfilecollector
673##############################################################
674
675sub collect_all_files_without_patch_flag
676{
677    my ($filesref) = @_;
678
679    my $newfiles = collect_all_items_without_special_flag($filesref, "PATCH");
680
681    for ( my $i = 0; $i <= $#{$newfiles}; $i++ ) { push(@{$installer::globals::nopatchfilecollector}, ${$newfiles}[$i]); }
682}
683
684##############################################################
685# Collecting all items without a defined flag
686##############################################################
687
688sub collect_all_items_without_special_flag
689{
690    my ($itemsref, $flag) = @_;
691
692    my @allitems = ();
693
694    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
695    {
696        my $oneitem = ${$itemsref}[$i];
697        my $styles = "";
698        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} };
699
700        if ( !( $styles =~ /\b$flag\b/ ))
701        {
702            push( @allitems, $oneitem );
703        }
704    }
705
706    return \@allitems;
707}
708
709##############################################################
710# Removing all items with a defined flag from collector
711##############################################################
712
713sub remove_all_items_with_special_flag
714{
715    my ($itemsref, $flag) = @_;
716
717    my @allitems = ();
718
719    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
720    {
721        my $oneitem = ${$itemsref}[$i];
722        my $styles = "";
723        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'} };
724        if ( $styles =~ /\b$flag\b/ )
725        {
726            my $infoline = "Attention: Removing from collector: $oneitem->{'Name'} !\n";
727            push( @installer::globals::logfileinfo, $infoline);
728            if ( $flag eq "BINARYTABLE_ONLY" ) { push(@installer::globals::binarytableonlyfiles, $oneitem); }
729            next;
730        }
731        push( @allitems, $oneitem );
732    }
733
734    return \@allitems;
735}
736
737###########################################################
738# Mechanism for simple installation without packing
739###########################################################
740
741sub install_simple ($$$$$$)
742{
743    my ($packagename, $languagestring, $directoriesarray, $filesarray, $linksarray, $unixlinksarray) = @_;
744
745        # locate GNU cp on the system
746        my $gnucp = 'cp';
747        if ( $ENV{'GNUCOPY'} ) { $gnucp = $ENV{'GNUCOPY'}; }
748    my $copyopts = '-af';
749    $copyopts = '-PpRf' unless ( $ENV{'GNUCOPY'} ); # if not gnucopy, assume POSIX copy
750
751    installer::logger::print_message( "... installing module $packagename ...\n" );
752
753    my $destdir = $installer::globals::destdir;
754    my @lines = ();
755
756    installer::logger::print_message( "DestDir: $destdir \n" );
757    installer::logger::print_message( "Rootpath: $installer::globals::rootpath \n" );
758
759    `mkdir -p $destdir` if $destdir ne "";
760    `mkdir -p $destdir$installer::globals::rootpath`;
761
762    # Create Directories
763    for ( my $i = 0; $i <= $#{$directoriesarray}; $i++ )
764    {
765        my $onedir = ${$directoriesarray}[$i];
766        my $dir = "";
767
768        if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
769
770        if ((!($dir =~ /\bPREDEFINED_/ )) || ( $dir =~ /\bPREDEFINED_PROGDIR\b/ ))
771        {
772            # printf "mkdir $destdir$onedir->{'HostName'}\n";
773            mkdir $destdir . $onedir->{'HostName'};
774            push @lines, "%dir " . $onedir->{'HostName'} . "\n";
775        }
776    }
777
778    for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
779    {
780        my $onefile = ${$filesarray}[$i];
781        my $unixrights = $onefile->{'UnixRights'};
782        my $destination = $onefile->{'destination'};
783        my $sourcepath = $onefile->{'sourcepath'};
784
785        # This is necessary to install SDK that includes files with $ in its name
786        # Otherwise, the following shell commands does not work and the file list
787        # is not correct
788        $destination =~ s/\$\$/\$/;
789        $sourcepath =~ s/\$\$/\$/;
790
791        push @lines, "$destination\n";
792        # printf "cp $sourcepath $destdir$destination\n";
793        copy ("$sourcepath", "$destdir$destination") || die "Can't copy file: $sourcepath -> $destdir$destination $!";
794        my $sourcestat = stat($sourcepath);
795        utime ($sourcestat->atime, $sourcestat->mtime, "$destdir$destination");
796        chmod (oct($unixrights), "$destdir$destination") || die "Can't change permissions: $!";
797        push @lines, "$destination\n";
798    }
799
800    for ( my $i = 0; $i <= $#{$linksarray}; $i++ )
801    {
802        my $onelink = ${$linksarray}[$i];
803        my $destination = $onelink->{'destination'};
804        my $destinationfile = $onelink->{'destinationfile'};
805
806        # print "link $destinationfile -> $destdir$destination\n";
807        symlink ("$destinationfile", "$destdir$destination") || die "Can't create symlink: $!";
808        push @lines, "$destination\n";
809    }
810
811    for ( my $i = 0; $i <= $#{$unixlinksarray}; $i++ )
812    {
813        my $onelink = ${$unixlinksarray}[$i];
814        my $target = $onelink->{'Target'};
815        my $destination = $onelink->{'destination'};
816
817        # print "Unix link $target -> $destdir$destination\n";
818        `ln -sf '$target' '$destdir$destination'`;
819        push @lines, "$destination\n";
820    }
821
822    if ( $destdir ne "" )
823    {
824        my $filelist;
825        my $fname = $installer::globals::destdir . "/$packagename";
826        if ($installer::globals::languagepack) { $fname .= ".$languagestring"; }
827        open ($filelist, ">$fname") || die "Can't open $fname: $!";
828        print $filelist @lines;
829        close ($filelist);
830    }
831
832}
833
834###########################################################
835# Adding shellnew files into files collector for
836# user installation
837###########################################################
838
839sub add_shellnewfile_into_filesarray
840{
841    my ($filesref, $onefile, $inffile) = @_;
842
843    my %shellnewfile = ();
844    my $shellnewfileref = \%shellnewfile;
845
846    installer::converter::copy_item_object($inffile, $shellnewfileref);
847
848    $shellnewfileref->{'Name'} = $onefile->{'Name'};
849    $shellnewfileref->{'sourcepath'} = $onefile->{'sourcepath'};
850    $shellnewfileref->{'gid'} = $onefile->{'gid'} . "_Userinstall";
851
852    # the destination has to be adapted
853    my $destination = $inffile->{'destination'};
854    installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
855    $destination = $destination . $onefile->{'Name'};
856    $shellnewfileref->{'destination'} = $destination;
857
858    # add language specific inffile into filesarray
859    push(@{$filesref}, $shellnewfileref);
860}
861
862###########################################################
863# Replacing one placehoder in template file
864###########################################################
865
866sub replace_in_template_file
867{
868    my ($templatefile, $placeholder, $newstring) = @_;
869
870    for ( my $i = 0; $i <= $#{$templatefile}; $i++ )
871    {
872        ${$templatefile}[$i] =~ s/\Q$placeholder\E/$newstring/g;
873    }
874}
875
876###########################################################
877# Replacing one placehoder with an array in template file
878###########################################################
879
880sub replace_array_in_template_file
881{
882    my ($templatefile, $placeholder, $arrayref) = @_;
883
884    for ( my $i = 0; $i <= $#{$templatefile}; $i++ )
885    {
886        if ( ${$templatefile}[$i] =~ /\Q$placeholder\E/ )
887        {
888            my @return = splice(@{$templatefile}, $i, 1, @{$arrayref});
889        }
890    }
891}
892
893###########################################################
894# Collecting all modules from registry items
895###########################################################
896
897sub collect_all_modules
898{
899    my ($registryitemsref) = @_;
900
901    my @allmodules = ();
902
903    for ( my $i = 0; $i <= $#{$registryitemsref}; $i++ )
904    {
905        $registryitem = ${$registryitemsref}[$i];
906        my $module = $registryitem->{'ModuleID'};
907
908        if ( ! installer::existence::exists_in_array($module, \@allmodules) )
909        {
910            push(@allmodules, $module);
911        }
912    }
913
914    return \@allmodules;
915}
916
917###########################################################
918# Changing the content of the inf file
919###########################################################
920
921sub write_content_into_inf_file
922{
923    my ($templatefile, $filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $onelanguage, $inffile, $firstlanguage, $allvariableshashref) = @_;
924
925    # First part: Shellnew files
926    # SHELLNEWFILESPLACEHOLDER
927
928    my $rootmodule = 0;
929    # inf files can be assigned to "gid_Module_Root_Files_2"
930    if ( $inffile->{'modules'} =~ /Module_Root/i ) { $rootmodule = 1; }
931
932    if ( $rootmodule )
933    {
934        my $shellnewstring = "";
935
936        for ( my $i = 0; $i <= $#{$filesref}; $i++ )
937        {
938            my $onefile = ${$filesref}[$i];
939            my $directory = $onefile->{'Dir'};
940
941            if ( $directory =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ )
942            {
943                $shellnewstring = $shellnewstring . $onefile->{'Name'} . "\n";
944                if (( $firstlanguage ) && ( ! $installer::globals::shellnewfilesadded )) { add_shellnewfile_into_filesarray($filesref, $onefile, $inffile); }
945            }
946        }
947
948        $shellnewstring =~ s/\s*$//;
949        replace_in_template_file($templatefile, "SHELLNEWFILESPLACEHOLDER", $shellnewstring);
950
951        $installer::globals::shellnewfilesadded = 1;
952    }
953
954    # Second part: Start menu entries
955
956    # The OfficeMenuFolder is defined as: $productname . " " . $productversion;
957
958    my $productname = $allvariableshashref->{'PRODUCTNAME'};
959    my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
960    my $productkey = $productname . " " . $productversion;
961
962    replace_in_template_file($templatefile, "OFFICEFOLDERPLACEHOLDER", $productkey);
963
964    # Setting name target and infotip for all applications
965
966    for ( my $i = 0; $i <= $#{$folderitemsref}; $i++ )
967    {
968        my $folderitem = ${$folderitemsref}[$i];
969
970        my $styles = "";
971        if ( $folderitem->{'Styles'} ) { $styles = $folderitem->{'Styles'}; }
972        if ( $styles =~ /\bNON_ADVERTISED\b/ ) { next; }    # no entry for non-advertised shortcuts
973
974        if (( ! $folderitem->{'ismultilingual'} ) || (( $folderitem->{'ismultilingual'} ) && ( $folderitem->{'specificlanguage'} eq $onelanguage )))
975        {
976            my $gid = $folderitem->{'gid'};
977            my $app = $gid;
978            $app =~ s/gid_Folderitem_//;
979            $app = uc($app);
980
981            my $name = $folderitem->{'Name'};
982            my $placeholder = "PLACEHOLDER_FOLDERITEM_NAME_" . $app;
983            replace_in_template_file($templatefile, $placeholder, $name);
984
985            my $tooltip = $folderitem->{'Tooltip'};
986            $placeholder = "PLACEHOLDER_FOLDERITEM_TOOLTIP_" . $app;
987            replace_in_template_file($templatefile, $placeholder, $tooltip);
988
989            my $executablegid = $folderitem->{'FileID'};
990            my $exefile = installer::existence::get_specified_file($filesref, $executablegid);
991            my $exefilename = $exefile->{'Name'};
992            $placeholder = "PLACEHOLDER_FOLDERITEM_TARGET_" . $app;
993            replace_in_template_file($templatefile, $placeholder, $exefilename);
994        }
995    }
996
997    # Third part: Windows registry entries
998
999    # collecting all modules
1000
1001    my $allmodules = collect_all_modules($registryitemsref);
1002
1003    my @registryitems = ();
1004    my $allsectionsstring = "";
1005
1006    for ( my $j = 0; $j <= $#{$allmodules}; $j++ )
1007    {
1008        my $moduleid = ${$allmodules}[$j];
1009
1010        my $inffilemodule = $inffile->{'modules'};
1011        # inf files can be assigned to "gid_Module_Root_Files_2", but RegistryItems to "gid_Module_Root"
1012        if ( $inffilemodule =~ /Module_Root/i ) { $inffilemodule = $installer::globals::rootmodulegid; }
1013
1014        if ( ! ( $moduleid eq $inffilemodule )) { next; }
1015
1016        my $shortmodulename = $moduleid;
1017        $shortmodulename =~ s/gid_Module_//;
1018        my $sectionname = "InstRegKeys." . $shortmodulename;
1019        $allsectionsstring = $allsectionsstring . $sectionname . ",";
1020        my $sectionheader = "\[" . $sectionname . "\]" . "\n";
1021        push(@registryitems, $sectionheader);
1022
1023        for ( my $i = 0; $i <= $#{$registryitemsref}; $i++ )
1024        {
1025            my $registryitem = ${$registryitemsref}[$i];
1026
1027            if ( ! ( $registryitem->{'ModuleID'} eq $moduleid )) { next; }
1028
1029            if (( ! $registryitem->{'ismultilingual'} ) || (( $registryitem->{'ismultilingual'} ) && ( $registryitem->{'specificlanguage'} eq $onelanguage )))
1030            {
1031                # Syntax: HKCR,".bau",,,"soffice.StarConfigFile.6"
1032
1033                my $regroot = "";
1034                my $parentid = "";
1035                if ( $registryitem->{'ParentID'} ) { $parentid = $registryitem->{'ParentID'}; }
1036                if ( $parentid eq "PREDEFINED_HKEY_CLASSES_ROOT" ) { $regroot = "HKCR"; }
1037                if ( $parentid eq "PREDEFINED_HKEY_LOCAL_MACHINE" ) { $regroot = "HKCU"; }
1038
1039                my $subkey = "";
1040                if ( $registryitem->{'Subkey'} ) { $subkey = $registryitem->{'Subkey'}; }
1041                if ( $subkey ne "" ) { $subkey = "\"" . $subkey . "\""; }
1042
1043                my $valueentryname = "";
1044                if ( $registryitem->{'Name'} ) { $valueentryname = $registryitem->{'Name'}; }
1045                if ( $valueentryname ne "" ) { $valueentryname = "\"" . $valueentryname . "\""; }
1046
1047                my $flag = "";
1048
1049                my $value = "";
1050                if ( $registryitem->{'Value'} ) { $value = $registryitem->{'Value'}; }
1051                if ( $value =~ /\<progpath\>/ ) { $value =~ s/\\\"/\"\"/g; } # Quoting for INF is done by double ""
1052                $value =~ s/\\\"/\"/g;  # no more masquerading of '"'
1053                $value =~ s/\<progpath\>/\%INSTALLLOCATION\%/g;
1054                if ( $value ne "" ) { $value = "\"" . $value . "\""; }
1055
1056                my $oneline = $regroot . "," . $subkey . "," . $valueentryname . "," . $flag . "," . $value . "\n";
1057
1058                push(@registryitems, $oneline);
1059            }
1060        }
1061
1062        push(@registryitems, "\n"); # empty line after each section
1063    }
1064
1065    # replacing the $allsectionsstring
1066    $allsectionsstring =~ s/\,\s*$//;
1067    replace_in_template_file($templatefile, "ALLREGISTRYSECTIONSPLACEHOLDER", $allsectionsstring);
1068
1069    # replacing the placeholder for all registry keys
1070    replace_array_in_template_file($templatefile, "REGISTRYKEYSPLACEHOLDER", \@registryitems);
1071
1072}
1073
1074###########################################################
1075# Creating inf files for local user system integration
1076###########################################################
1077
1078sub create_inf_file
1079{
1080    my ($filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $languagesarrayref, $languagestringref, $allvariableshashref) = @_;
1081
1082    # collecting all files with flag INFFILE
1083
1084    my $inf_files = collect_all_items_with_special_flag($filesref ,"INFFILE");
1085
1086    if ( $#{$inf_files} > -1 )
1087    {
1088        # create new language specific inffile
1089        installer::logger::include_header_into_logfile("Creating inf files:");
1090
1091        my $infdirname = "inffiles";
1092        my $infdir = installer::systemactions::create_directories($infdirname, $languagestringref);
1093
1094        my $infoline = "Number of inf files: $#{$inf_files} + 1 \n";
1095        push( @installer::globals::logfileinfo, $infoline);
1096
1097        # there are inffiles for all modules
1098
1099        for ( my $i = 0; $i <= $#{$inf_files}; $i++ )
1100        {
1101            my $inffile = ${$inf_files}[$i];
1102            my $inf_file_name = $inffile->{'Name'};
1103
1104            my $templatefilename = $inffile->{'sourcepath'};
1105
1106            if ( ! -f $templatefilename ) { installer::exiter::exit_program("ERROR: Could not find file $templatefilename !", "create_inf_file");  }
1107
1108            # iterating over all languages
1109
1110            for ( my $j = 0; $j <= $#{$languagesarrayref}; $j++ )   # iterating over all languages
1111            {
1112                my $firstlanguage = 0;
1113                if ( $j == 0 ) { $firstlanguage = 1; }
1114
1115                my $onelanguage = ${$languagesarrayref}[$j];
1116
1117                $infoline = "Templatefile: $inf_file_name, Language: $onelanguage \n";
1118                push( @installer::globals::logfileinfo, $infoline);
1119
1120                my $templatefile = installer::files::read_file($templatefilename);
1121
1122                my $linesbefore = $#{$templatefile};
1123
1124                write_content_into_inf_file($templatefile, $filesref, $registryitemsref, $folderref, $folderitemsref, $modulesref, $onelanguage, $inffile, $firstlanguage, $allvariableshashref);
1125
1126                $infoline = "Lines change: From $linesbefore to $#{$templatefile}.\n";
1127                push( @installer::globals::logfileinfo, $infoline);
1128
1129                # rename language specific inffile
1130                my $language_inf_file_name = $inf_file_name;
1131                my $windowslanguage = installer::windows::language::get_windows_language($onelanguage);
1132                $language_inf_file_name =~ s/\.inf/_$windowslanguage\.inf/;
1133
1134                my $sourcepath = $infdir . $installer::globals::separator . $language_inf_file_name;
1135                installer::files::save_file($sourcepath, $templatefile);
1136
1137                $infoline = "Saving file: $sourcepath\n";
1138                push( @installer::globals::logfileinfo, $infoline);
1139
1140                # creating new file object
1141
1142                my %languageinffile = ();
1143                my $languageinifileref = \%languageinffile;
1144
1145                if ( $j < $#{$languagesarrayref} ) { installer::converter::copy_item_object($inffile, $languageinifileref); }
1146                else { $languageinifileref = $inffile; }
1147
1148                $languageinifileref->{'Name'} = $language_inf_file_name;
1149                $languageinifileref->{'sourcepath'} = $sourcepath;
1150                # destination and gid also have to be adapted
1151                $languageinifileref->{'gid'} = $languageinifileref->{'gid'} . "_" . $onelanguage;
1152                my $destination = $languageinifileref->{'destination'};
1153                installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
1154                $destination = $destination . $language_inf_file_name;
1155                $languageinifileref->{'destination'} = $destination;
1156
1157                # add language specific inffile into filesarray
1158                if ( $j < $#{$languagesarrayref} ) { push(@{$filesref}, $languageinifileref); }
1159            }
1160        }
1161    }
1162}
1163
1164###########################################################
1165# Selecting patch items
1166###########################################################
1167
1168sub select_patch_items
1169{
1170    my ( $itemsref, $itemname ) = @_;
1171
1172    installer::logger::include_header_into_logfile("Selecting items for patches. Item: $itemname");
1173
1174    my @itemsarray = ();
1175
1176    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
1177    {
1178        my $oneitem = ${$itemsref}[$i];
1179
1180        my $name = $oneitem->{'Name'};
1181        if (( $name =~ /\bLICENSE/ ) || ( $name =~ /\bREADME/ ))
1182        {
1183            push(@itemsarray, $oneitem);
1184            next;
1185        }
1186
1187        # Items with style "PATCH" have to be included into the patch
1188        my $styles = "";
1189        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; }
1190        if ( $styles =~ /\bPATCH\b/ ) { push(@itemsarray, $oneitem); }
1191    }
1192
1193    return \@itemsarray;
1194}
1195
1196###########################################################
1197# Selecting patch items
1198###########################################################
1199
1200sub select_patch_items_without_name
1201{
1202    my ( $itemsref, $itemname ) = @_;
1203
1204    installer::logger::include_header_into_logfile("Selecting RegistryItems for patches");
1205
1206    my @itemsarray = ();
1207
1208    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
1209    {
1210        my $oneitem = ${$itemsref}[$i];
1211
1212        # Items with style "PATCH" have to be included into the patch
1213        my $styles = "";
1214        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; }
1215        if ( $styles =~ /\bPATCH\b/ ) { push(@itemsarray, $oneitem); }
1216    }
1217
1218    return \@itemsarray;
1219}
1220
1221###########################################################
1222# Selecting patch items
1223###########################################################
1224
1225sub select_langpack_items
1226{
1227    my ( $itemsref, $itemname ) = @_;
1228
1229    installer::logger::include_header_into_logfile("Selecting RegistryItems for Language Packs");
1230
1231    my @itemsarray = ();
1232
1233    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
1234    {
1235        my $oneitem = ${$itemsref}[$i];
1236
1237        # Items with style "LANGUAGEPACK" have to be included into the patch
1238        my $styles = "";
1239        if ( $oneitem->{'Styles'} ) { $styles = $oneitem->{'Styles'}; }
1240        if (( $styles =~ /\bLANGUAGEPACK\b/ ) || ( $styles =~ /\bFORCELANGUAGEPACK\b/ )) { push(@itemsarray, $oneitem); }
1241    }
1242
1243    return \@itemsarray;
1244}
1245
1246###########################################################
1247# Searching if LICENSE and README, which are not removed
1248# in select_patch_items are really needed for the patch.
1249# If not, they are removed now.
1250###########################################################
1251
1252sub analyze_patch_files
1253{
1254    my ( $filesref ) = @_;
1255
1256    installer::logger::include_header_into_logfile("Analyzing patch files");
1257
1258    my @filesarray = ();
1259
1260    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
1261    {
1262        my $onefile = ${$filesref}[$i];
1263        my $styles = "";
1264        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
1265        if ( !( $styles =~ /\bPATCH\b/) ) { next; } # removing all files without flag PATCH (LICENSE, README, ...)
1266
1267        if ( $installer::globals::iswindowsbuild )
1268        {
1269            # all files of the Windows patch belong to the root module
1270            $onefile->{'modules'} = $installer::globals::rootmodulegid;
1271        }
1272
1273        push(@filesarray, $onefile);
1274    }
1275
1276    return \@filesarray;
1277}
1278
1279###########################################################
1280# Sorting an array
1281###########################################################
1282
1283sub sort_array
1284{
1285    my ( $arrayref ) = @_;
1286
1287    for ( my $i = 0; $i <= $#{$arrayref}; $i++ )
1288    {
1289        my $under = ${$arrayref}[$i];
1290
1291        for ( my $j = $i + 1; $j <= $#{$arrayref}; $j++ )
1292        {
1293            my $over = ${$arrayref}[$j];
1294
1295            if ( $under gt $over)
1296            {
1297                ${$arrayref}[$i] = $over;
1298                ${$arrayref}[$j] = $under;
1299                $under = $over;
1300            }
1301        }
1302    }
1303}
1304
1305###########################################################
1306# Renaming linux files with flag LINUXLINK
1307###########################################################
1308
1309sub prepare_linuxlinkfiles
1310{
1311    my ( $filesref ) = @_;
1312
1313    @installer::globals::linuxlinks = (); # empty this array, because it could be already used
1314    @installer::globals::linuxpatchfiles = (); # empty this array, because it could be already used
1315    @installer::globals::allfilessav = (); # empty this array, because it could be already used. Required for forced links
1316
1317    my @filesarray = ();
1318
1319    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
1320    {
1321        my $onefile = ${$filesref}[$i];
1322        my %linkfilehash = ();
1323        my $linkfile = \%linkfilehash;
1324        installer::converter::copy_item_object($onefile, $linkfile);
1325
1326        my $ispatchfile = 0;
1327        my $styles = "";
1328        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
1329        if ( $styles =~ /\bPATCH\b/ ) { $ispatchfile = 1; }
1330
1331        # Collecting all files for the mechanism with forced links
1332        # Saving a copy
1333        my %copyfilehash = ();
1334        my $copyfile = \%copyfilehash;
1335        installer::converter::copy_item_object($onefile, $copyfile);
1336        push( @installer::globals::allfilessav, $copyfile);
1337
1338        my $original_destination = $onefile->{'destination'};
1339        # $onefile->{'destination'} is used in the epm list file. This value can be changed now!
1340
1341        if ( $ispatchfile ) { $onefile->{'destination'} = $onefile->{'destination'} . "\.$installer::globals::linuxlibrarypatchlevel"; }
1342        else { $onefile->{'destination'} = $onefile->{'destination'} . "\.$installer::globals::linuxlibrarybaselevel"; }
1343
1344        my $infoline = "LINUXLINK: Changing file destination from $original_destination to $onefile->{'destination'} !\n";
1345        push( @installer::globals::logfileinfo, $infoline);
1346
1347        # all files without PATCH flag are included into the RPM
1348        if ( ! $ispatchfile ) { push( @filesarray, $onefile); }
1349        else { push( @installer::globals::linuxpatchfiles, $onefile); }
1350
1351        # Preparing the collector for the links
1352        # Setting the new file name as destination of the link
1353        my $linkdestination = $linkfile->{'Name'};
1354        installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination);
1355        if ( $ispatchfile ) { $linkfile->{'destinationfile'} = $linkdestination . "\.$installer::globals::linuxlibrarypatchlevel"; }
1356        else { $linkfile->{'destinationfile'} = $linkdestination . "\.$installer::globals::linuxlibrarybaselevel"; }
1357        push( @installer::globals::linuxlinks, $linkfile );
1358
1359        $infoline = "LINUXLINK: Created link: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n";
1360        push( @installer::globals::logfileinfo, $infoline);
1361    }
1362
1363    return \@filesarray;
1364}
1365
1366###########################################################
1367# Adding links into "u-RPMs", that have the flag
1368# FORCE_INTO_UPDATE_PACKAGE
1369# This is only relevant for Linux
1370###########################################################
1371
1372sub prepare_forced_linuxlinkfiles
1373{
1374    my ( $linksref ) = @_;
1375
1376    my @linksarray = ();
1377
1378    for ( my $i = 0; $i <= $#{$linksref}; $i++ )
1379    {
1380        my $onelink = ${$linksref}[$i];
1381
1382        my $isforcedlink = 0;
1383        my $styles = "";
1384        if ( $onelink->{'Styles'} ) { $styles = $onelink->{'Styles'}; }
1385        if ( $styles =~ /\bFORCE_INTO_UPDATE_PACKAGE\b/ ) { $isforcedlink = 1; }
1386
1387        if ( $isforcedlink )
1388        {
1389            my $fileid = "";
1390
1391            if ( $onelink->{'ShortcutID'} )
1392            {
1393                $fileid = $onelink->{'ShortcutID'};
1394
1395                my $searchedlinkfile = find_file_by_id($linksref, $fileid);
1396
1397                # making a copy!
1398                my %linkfilehash = ();
1399                my $linkfile = \%linkfilehash;
1400                installer::converter::copy_item_object($searchedlinkfile, $linkfile);
1401
1402                $linkfile->{'Name'} = $onelink->{'Name'};
1403                $linkfile->{'destinationfile'} = $linkfile->{'destination'};
1404                my $linkdestination = $linkfile->{'destinationfile'};
1405                installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination);
1406                $linkfile->{'destinationfile'} = $linkdestination;
1407
1408                my $localdestination = $linkfile->{'destination'};
1409                # Getting the path
1410                installer::pathanalyzer::get_path_from_fullqualifiedname(\$localdestination);
1411                $localdestination =~ s/\Q$installer::globals::separator\E\s*$//;
1412                $linkfile->{'destination'} = $localdestination . $installer::globals::separator . $onelink->{'Name'};
1413
1414                $infoline = "Forced link into update file: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n";
1415                push( @installer::globals::logfileinfo, $infoline);
1416
1417                # The file, defined by the link, has to be included into the
1418                # link array @installer::globals::linuxlinks
1419                push( @installer::globals::linuxlinks, $linkfile );
1420            }
1421
1422            if ( $onelink->{'FileID'} )
1423            {
1424                $fileid = $onelink->{'FileID'};
1425
1426                my $searchedlinkfile = find_file_by_id(\@installer::globals::allfilessav, $fileid);
1427
1428                # making a copy!
1429                my %linkfilehash = ();
1430                my $linkfile = \%linkfilehash;
1431                installer::converter::copy_item_object($searchedlinkfile, $linkfile);
1432
1433                $linkfile->{'Name'} = $onelink->{'Name'};
1434                $linkfile->{'destinationfile'} = $linkfile->{'destination'};
1435                my $linkdestination = $linkfile->{'destinationfile'};
1436                installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$linkdestination);
1437                $linkfile->{'destinationfile'} = $linkdestination;
1438
1439                my $localdestination = $linkfile->{'destination'};
1440                # Getting the path
1441                installer::pathanalyzer::get_path_from_fullqualifiedname(\$localdestination);
1442                $localdestination =~ s/\Q$installer::globals::separator\E\s*$//;
1443                $linkfile->{'destination'} = $localdestination . $installer::globals::separator . $onelink->{'Name'};
1444
1445                $infoline = "Forced link into update file: $linkfile->{'destination'} pointing to $linkfile->{'destinationfile'} !\n";
1446                push( @installer::globals::logfileinfo, $infoline);
1447
1448                # The file, defined by the link, has to be included into the
1449                # link array @installer::globals::linuxlinks
1450                push( @installer::globals::linuxlinks, $linkfile );
1451             }
1452
1453            if ( $fileid eq "" ) { installer::exiter::exit_program("ERROR: No FileID assigned to forced link $onelink->{'gid'} !", "prepare_forced_linuxlinkfiles"); }
1454
1455        }
1456        else
1457        {
1458            # Links with flag FORCE_INTO_UPDATE_PACKAGE are forced into "u"-RPM. All other
1459            # links are included into the non-"u"-package.
1460            push( @linksarray, $onelink );
1461        }
1462    }
1463
1464    return \@linksarray;
1465}
1466
1467###########################################################
1468# reorganizing the patchfile content,
1469# sorting for directory to decrease the file size
1470###########################################################
1471
1472sub reorg_patchfile
1473{
1474    my ($patchfiles, $patchfiledirectories) = @_;
1475
1476    my @patchfilesarray = ();
1477    my $line = "";
1478    my $directory = "";
1479
1480    # iterating over all directories, writing content into new patchfiles list
1481
1482    for ( my $i = 0; $i <= $#{$patchfiledirectories}; $i++ )
1483    {
1484        $directory = ${$patchfiledirectories}[$i];
1485        $line = "[" . $directory . "]" . "\n";
1486        push(@patchfilesarray, $line);
1487
1488        for ( my $j = 0; $j <= $#{$patchfiles}; $j++ )
1489        {
1490            # "\tXXXXX\t" . $olddestination . "\n";
1491            if ( ${$patchfiles}[$j] =~ /^\s*(.*?)\s*\tXXXXX\t\Q$directory\E\s*$/ )
1492            {
1493                $line = $1 . "\n";
1494                push(@patchfilesarray, $line);
1495            }
1496        }
1497    }
1498
1499    return \@patchfilesarray;
1500}
1501
1502###########################################################
1503# One special file has to be the last in patchfile.txt.
1504# Controlling this file, guarantees, that all files were
1505# patch correctly. Using version.ini makes it easy to
1506# control this by looking into the about box
1507# -> shifting one section to the end
1508###########################################################
1509
1510sub shift_section_to_end
1511{
1512    my ($patchfilelist) = @_;
1513
1514    my @patchfile = ();
1515    my @lastsection = ();
1516    my $lastsection = "program";
1517    my $notlastsection = "Basis\\program";
1518    my $record = 0;
1519
1520    for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ )
1521    {
1522        my $line = ${$patchfilelist}[$i];
1523
1524        if (( $record ) && ( $line =~ /^\s*\[/ )) { $record = 0; }
1525
1526        if (( $line =~ /^\s*\[\Q$lastsection\E\\\]\s*$/ ) && ( ! ( $line =~ /\Q$notlastsection\E\\\]\s*$/ ))) { $record = 1; }
1527
1528        if ( $record ) { push(@lastsection, $line); }
1529        else { push(@patchfile, $line); }
1530    }
1531
1532    if ( $#lastsection > -1 )
1533    {
1534        for ( my $i = 0; $i <= $#lastsection; $i++ )
1535        {
1536            push(@patchfile, $lastsection[$i]);
1537        }
1538    }
1539
1540    return \@patchfile;
1541}
1542
1543###########################################################
1544# One special file has to be the last in patchfile.txt.
1545# Controlling this file, guarantees, that all files were
1546# patch correctly. Using version.ini makes it easy to
1547# control this by looking into the about box
1548# -> shifting one file of the last section to the end
1549###########################################################
1550
1551sub shift_file_to_end
1552{
1553    my ($patchfilelist) = @_;
1554
1555    my @patchfile = ();
1556    my $lastfilename = "version.ini";
1557    my $lastfileline = "";
1558    my $foundfile = 0;
1559
1560    # Only searching this file in the last section
1561    my $lastsectionname = "";
1562
1563    for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ )
1564    {
1565        my $line = ${$patchfilelist}[$i];
1566        if ( $line =~ /^\s*\[(.*?)\]\s*$/ ) { $lastsectionname = $1; }
1567    }
1568
1569    my $record = 0;
1570    for ( my $i = 0; $i <= $#{$patchfilelist}; $i++ )
1571    {
1572        my $line = ${$patchfilelist}[$i];
1573
1574        if ( $line =~ /^\s*\[\Q$lastsectionname\E\]\s*$/ ) { $record = 1; }
1575
1576        if (( $line =~ /^\s*\"\Q$lastfilename\E\"\=/ ) && ( $record ))
1577        {
1578            $lastfileline = $line;
1579            $foundfile = 1;
1580            $record = 0;
1581            next;
1582        }
1583
1584        push(@patchfile, $line);
1585    }
1586
1587    if ( $foundfile ) { push(@patchfile, $lastfileline); }
1588
1589    return  \@patchfile;
1590}
1591
1592###########################################################
1593# Putting hash content into array and sorting it
1594###########################################################
1595
1596sub sort_hash
1597{
1598    my ( $hashref ) =  @_;
1599
1600    my $item = "";
1601    my @sortedarray = ();
1602
1603    foreach $item (keys %{$hashref}) { push(@sortedarray, $item); }
1604    installer::sorter::sorting_array_of_strings(\@sortedarray);
1605
1606    return \@sortedarray;
1607}
1608
1609###########################################################
1610# Renaming Windows files in Patch and creating file
1611# patchfiles.txt
1612###########################################################
1613
1614sub prepare_windows_patchfiles
1615{
1616    my ( $filesref, $languagestringref, $allvariableshashref ) = @_;
1617
1618    my @patchfiles = ();
1619    my %patchfiledirectories = ();
1620    my $patchfilename = "patchlist.txt";
1621    my $patchfilename2 = "patchmsi.dll";
1622
1623    if ( ! $allvariableshashref->{'WINDOWSPATCHLEVEL'} ) { installer::exiter::exit_program("ERROR: No Windows patch level defined in list file (WINDOWSPATCHLEVEL) !", "prepare_windows_patchfiles"); }
1624    # my $windowspatchlevel = $allvariableshashref->{'WINDOWSPATCHLEVEL'};
1625    my $windowspatchlevel = $installer::globals::buildid;
1626
1627    # the environment variable CWS_WORK_STAMP is set only in CWS
1628    if ( $ENV{'CWS_WORK_STAMP'} ) { $windowspatchlevel = $ENV{'CWS_WORK_STAMP'} . $windowspatchlevel; }
1629
1630    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
1631    {
1632        my $onefile = ${$filesref}[$i];
1633
1634        my $filename = $onefile->{'Name'};
1635        if (( $filename eq $patchfilename ) || ( $filename eq $patchfilename2 )) { next; }
1636
1637        my $styles = "";
1638        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
1639        if ( $styles =~ /\bDONTRENAMEINPATCH\b/ ) { next; }
1640
1641        # special handling for files with flag DONTSHOW. This files get the extension ".dontshow" to be filtered by dialogs.
1642        my $localwindowspatchlevel = $windowspatchlevel;
1643        if ( $styles =~ /\bDONTSHOW\b/ ) { $localwindowspatchlevel = $localwindowspatchlevel . "\.dontshow"; }
1644
1645        my $olddestination = $onefile->{'destination'};
1646        my $newdestination = $olddestination . "." . $localwindowspatchlevel;
1647        my $localfilename = $olddestination;
1648        installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$localfilename);  # file name part
1649        my $line = "\"" . $localfilename . "\"" . "=" . "\"" . "\." . $localwindowspatchlevel . "\"";
1650        $onefile->{'destination'} = $newdestination;
1651
1652        my $newfilename = $onefile->{'Name'} . "." . $localwindowspatchlevel;
1653        $onefile->{'Name'} = $newfilename;
1654
1655        # adding section information (section is the directory)
1656        my $origolddestination = $olddestination;
1657        installer::pathanalyzer::get_path_from_fullqualifiedname(\$olddestination); # directory part
1658        if ( ! $olddestination ) { $olddestination = "_root";  }
1659        if ( ! exists($patchfiledirectories{$olddestination}) ) { $patchfiledirectories{$olddestination} = 1; }
1660        $line = $line . "\tXXXXX\t" . $olddestination . "\n";
1661
1662        push(@patchfiles, $line);
1663
1664        # also collecting all files from patch in @installer::globals::patchfilecollector
1665        my $patchfileline = $origolddestination . "\n";
1666        push(@installer::globals::patchfilecollector, $patchfileline);
1667    }
1668
1669    my $winpatchdirname = "winpatch";
1670    my $winpatchdir = installer::systemactions::create_directories($winpatchdirname, $languagestringref);
1671
1672    my $patchlistfile = installer::existence::get_specified_file_by_name($filesref, $patchfilename);
1673
1674    # reorganizing the patchfile content, sorting for directory to decrease the file size
1675    my $sorteddirectorylist = sort_hash(\%patchfiledirectories);
1676    my $patchfilelist = reorg_patchfile(\@patchfiles, $sorteddirectorylist);
1677
1678    # shifting version.ini to the end of the list, to guarantee, that all files are patched
1679    # if the correct version is shown in the about box
1680    $patchfilelist = shift_section_to_end($patchfilelist);
1681    $patchfilelist = shift_file_to_end($patchfilelist);
1682
1683    # saving the file
1684    $patchfilename = $winpatchdir . $installer::globals::separator . $patchfilename;
1685    installer::files::save_file($patchfilename, $patchfilelist);
1686
1687    my $infoline = "\nCreated list of patch files: $patchfilename\n";
1688    push( @installer::globals::logfileinfo, $infoline);
1689
1690    # and assigning the new source
1691    $patchlistfile->{'sourcepath'} = $patchfilename;
1692
1693    # and finally checking the file size
1694    if ( -f $patchfilename )    # test of existence
1695    {
1696        my $filesize = ( -s $patchfilename );
1697        $infoline = "Size of patch file list: $filesize\n\n";
1698        push( @installer::globals::logfileinfo, $infoline);
1699        installer::logger::print_message( "... size of patch list file: $filesize Byte ... \n" );
1700
1701        # Win 98: Maximum size of ini file is 65 kB
1702        # 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"); }
1703    }
1704
1705}
1706
1707###########################################################
1708# Replacing %-variables with the content
1709# of $allvariableshashref
1710###########################################################
1711
1712sub replace_variables_in_string
1713{
1714    my ( $string, $variableshashref ) = @_;
1715
1716    if ( $string =~ /^.*\%\w+.*$/ )
1717    {
1718        my $key;
1719
1720        foreach $key (keys %{$variableshashref})
1721        {
1722            my $value = $variableshashref->{$key};
1723            $key = "\%" . $key;
1724            $string =~ s/\Q$key\E/$value/g;
1725        }
1726    }
1727
1728    return $string;
1729}
1730
1731###########################################################
1732# Replacing %-variables with the content
1733# of $allvariableshashref
1734###########################################################
1735
1736sub replace_dollar_variables_in_string
1737{
1738    my ( $string, $variableshashref ) = @_;
1739
1740    if ( $string =~ /^.*\$\{\w+\}.*$/ )
1741    {
1742        my $key;
1743
1744        foreach $key (keys %{$variableshashref})
1745        {
1746            my $value = $variableshashref->{$key};
1747            $key = "\$\{" . $key . "\}";
1748            $string =~ s/\Q$key\E/$value/g;
1749        }
1750    }
1751
1752    return $string;
1753}
1754
1755###########################################################
1756# The list file contains the list of packages/RPMs that
1757# have to be copied.
1758###########################################################
1759
1760sub get_all_files_from_filelist
1761{
1762    my ( $listfile, $section ) = @_;
1763
1764    my @allpackages = ();
1765
1766    for ( my $i = 0; $i <= $#{$listfile}; $i++ )
1767    {
1768        my $line = ${$listfile}[$i];
1769        if ( $line =~ /^\s*\#/ ) { next; } # this is a comment line
1770        if ( $line =~ /^\s*$/ ) { next; } # empty line
1771        $line =~ s/^\s*//;
1772        $line =~ s/\s*$//;
1773        push(@allpackages, $line);
1774    }
1775
1776    return \@allpackages;
1777}
1778
1779###########################################################
1780# Getting one section from a file. Section begins with
1781# [xyz] and ends with file end or next [abc].
1782###########################################################
1783
1784sub get_section_from_file
1785{
1786    my ($file, $sectionname) = @_;
1787
1788    my @section = ();
1789    my $record = 0;
1790
1791    for ( my $i = 0; $i <= $#{$file}; $i++ )
1792    {
1793        my $line = ${$file}[$i];
1794
1795        if (( $record ) && ( $line =~ /^\s*\[/ ))
1796        {
1797            $record = 0;
1798            last;
1799        }
1800
1801        if ( $line =~ /^\s*\[\Q$sectionname\E\]\s*$/ ) { $record = 1; }
1802
1803        if ( $line =~ /^\s*\[/ ) { next; } # this is a section line
1804        if ( $line =~ /^\s*\#/ ) { next; } # this is a comment line
1805        if ( $line =~ /^\s*$/ ) { next; }  # empty line
1806        $line =~ s/^\s*//;
1807        $line =~ s/\s*$//;
1808        if ( $record ) { push(@section, $line); }
1809    }
1810
1811    return \@section;
1812
1813}
1814
1815#######################################################
1816# Substituting one variable in the xml file
1817#######################################################
1818
1819sub replace_one_dollar_variable
1820{
1821    my ($file, $variable, $searchstring) = @_;
1822
1823    for ( my $i = 0; $i <= $#{$file}; $i++ )
1824    {
1825        ${$file}[$i] =~ s/\$\{$searchstring\}/$variable/g;
1826    }
1827}
1828
1829#######################################################
1830# Substituting the variables in the xml file
1831#######################################################
1832
1833sub substitute_dollar_variables
1834{
1835    my ($file, $variableshashref) = @_;
1836
1837    my $key;
1838
1839    foreach $key (keys %{$variableshashref})
1840    {
1841        my $value = $variableshashref->{$key};
1842        replace_one_dollar_variable($file, $value, $key);
1843    }
1844}
1845
1846#############################################################################
1847# Collecting all packages or rpms located in the installation directory
1848#############################################################################
1849
1850sub get_all_packages_in_installdir
1851{
1852    my ($directory) = @_;
1853
1854    my $infoline = "";
1855
1856    my @allpackages = ();
1857    my $allpackages = \@allpackages;
1858
1859    if ( $installer::globals::islinuxrpmbuild )
1860    {
1861        $allpackages = installer::systemactions::find_file_with_file_extension("rpm", $directory);
1862    }
1863
1864    if ( $installer::globals::issolarisbuild )
1865    {
1866        $allpackages = installer::systemactions::get_all_directories($directory);
1867    }
1868
1869    return $allpackages;
1870}
1871
1872###############################################################
1873# The list of exclude packages can contain the
1874# beginning of the package name, not the complete name.
1875###############################################################
1876
1877sub is_matching
1878{
1879    my ($onepackage, $allexcludepackages ) = @_;
1880
1881    my $matches = 0;
1882
1883    for ( my $i = 0; $i <= $#{$allexcludepackages}; $i++ )
1884    {
1885        my $oneexcludepackage = ${$allexcludepackages}[$i];
1886
1887        if ( $onepackage =~ /^\s*$oneexcludepackage/ )
1888        {
1889            $matches = 1;
1890            last;
1891        }
1892    }
1893
1894    return $matches;
1895}
1896
1897###############################################################
1898# Copying all Solaris packages or RPMs from installation set
1899###############################################################
1900
1901sub copy_all_packages
1902{
1903    my ($allexcludepackages, $sourcedir, $destdir) = @_;
1904
1905    my $infoline = "";
1906
1907    $sourcedir =~ s/\/\s*$//;
1908    $destdir =~ s/\/\s*$//;
1909
1910    # $allexcludepackages is a list of RPMs and packages, that shall NOT be included into jds product
1911    my $allpackages = get_all_packages_in_installdir($sourcedir);
1912
1913    for ( my $i = 0; $i <= $#{$allpackages}; $i++ )
1914    {
1915        my $onepackage = ${$allpackages}[$i];
1916
1917        my $packagename = $onepackage;
1918
1919        if ( $installer::globals::issolarispkgbuild )   # on Solaris $onepackage contains the complete path
1920        {
1921            installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$packagename);
1922        }
1923
1924        if ( ! installer::existence::exists_in_array($packagename, $allexcludepackages))
1925        {
1926            if ( ! is_matching($packagename, $allexcludepackages ) )
1927            {
1928
1929                if ( $installer::globals::islinuxrpmbuild )
1930                {
1931                    my $sourcepackage = $sourcedir . $installer::globals::separator . $packagename;
1932                    my $destfile = $destdir . $installer::globals::separator . $packagename;
1933                    if ( ! -f $sourcepackage ) { installer::exiter::exit_program("ERROR: Could not find RPM $sourcepackage!", "copy_all_packages"); }
1934                    installer::systemactions::hardlink_one_file($sourcepackage, $destfile);
1935                }
1936
1937                if ( $installer::globals::issolarispkgbuild )
1938                {
1939                    my $destinationdir = $destdir . $installer::globals::separator . $packagename;
1940                    if ( ! -d $onepackage ) { installer::exiter::exit_program("ERROR: Could not find Solaris package $onepackage!", "copy_all_packages"); }
1941                    # installer::systemactions::hardlink_complete_directory($onepackage, $destinationdir);
1942                    # installer::systemactions::copy_complete_directory($onepackage, $destinationdir);
1943
1944                    my $systemcall = "cp -p -R $onepackage $destinationdir";
1945                    make_systemcall($systemcall);
1946                }
1947            }
1948            else
1949            {
1950                $infoline = "Excluding package (matching): $onepackage\n";
1951                push( @installer::globals::logfileinfo, $infoline);
1952            }
1953        }
1954        else
1955        {
1956            $infoline = "Excluding package (precise name): $onepackage\n";
1957            push( @installer::globals::logfileinfo, $infoline);
1958        }
1959    }
1960}
1961
1962######################################################
1963# Making systemcall
1964######################################################
1965
1966sub make_systemcall
1967{
1968    my ($systemcall) = @_;
1969
1970    my $returnvalue = system($systemcall);
1971
1972    my $infoline = "Systemcall: $systemcall\n";
1973    push( @installer::globals::logfileinfo, $infoline);
1974
1975    if ($returnvalue)
1976    {
1977        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
1978        push( @installer::globals::logfileinfo, $infoline);
1979    }
1980    else
1981    {
1982        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
1983        push( @installer::globals::logfileinfo, $infoline);
1984    }
1985}
1986
1987###########################################################
1988# Copying all Solaris packages or RPMs from solver
1989###########################################################
1990
1991sub copy_additional_packages
1992{
1993    my ($allcopypackages, $destdir, $includepatharrayref) = @_;
1994
1995    my $infoline = "Copy additional packages into installation set.\n";
1996    push( @installer::globals::logfileinfo, $infoline);
1997
1998    $destdir =~ s/\/\s*$//;
1999
2000    for ( my $i = 0; $i <= $#{$allcopypackages}; $i++ )
2001    {
2002        my $onepackage = ${$allcopypackages}[$i];
2003        $infoline = "Copy package: $onepackage\n";
2004        push( @installer::globals::logfileinfo, $infoline);
2005
2006        # this package must be delivered into the solver
2007
2008        my $packagesourceref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$onepackage, $includepatharrayref, 0);
2009        if ($$packagesourceref eq "") { installer::exiter::exit_program("ERROR: Could not find jds file $onepackage!", "copy_additional_packages"); }
2010
2011        if ( $onepackage =~ /\.tar\.gz\s*$/ )
2012        {
2013            my $systemcall = "cd $destdir; cat $$packagesourceref | gunzip | tar -xf -";
2014            make_systemcall($systemcall);
2015        }
2016        else
2017        {
2018            my $destfile = $destdir . $installer::globals::separator . $onepackage;
2019            installer::systemactions::copy_one_file($$packagesourceref, $destfile);
2020        }
2021    }
2022}
2023
2024###########################################################
2025# Creating jds installation sets
2026###########################################################
2027
2028sub create_jds_sets
2029{
2030    my ($installationdir, $allvariableshashref, $languagestringref, $languagesarrayref, $includepatharrayref) = @_;
2031
2032    installer::logger::print_message( "\n******************************************\n" );
2033    installer::logger::print_message( "... creating jds installation set ...\n" );
2034    installer::logger::print_message( "******************************************\n" );
2035
2036    installer::logger::include_header_into_logfile("Creating jds installation sets:");
2037
2038    my $firstdir = $installationdir;
2039    installer::pathanalyzer::get_path_from_fullqualifiedname(\$firstdir);
2040
2041    my $lastdir = $installationdir;
2042    installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$lastdir);
2043
2044    if ( $lastdir =~ /\./ ) { $lastdir =~ s/\./_jds_inprogress\./ }
2045    else { $lastdir = $lastdir . "_jds_inprogress"; }
2046
2047    # removing existing directory "_native_packed_inprogress" and "_native_packed_witherror" and "_native_packed"
2048
2049    my $jdsdir = $firstdir . $lastdir;
2050    if ( -d $jdsdir ) { installer::systemactions::remove_complete_directory($jdsdir); }
2051
2052    my $olddir = $jdsdir;
2053    $olddir =~ s/_inprogress/_witherror/;
2054    if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
2055
2056    $olddir = $jdsdir;
2057    $olddir =~ s/_inprogress//;
2058    if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
2059
2060    # creating the new directory
2061
2062    installer::systemactions::create_directory($jdsdir);
2063
2064    $installer::globals::saveinstalldir = $jdsdir;
2065
2066    # find and read jds files list
2067    my $filelistname = $installer::globals::jdsexcludefilename;
2068
2069    my $filelistnameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filelistname, "", 0);
2070    if ($$filelistnameref eq "") { installer::exiter::exit_program("ERROR: Could not find jds list file $filelistname!", "create_jds_sets"); }
2071
2072    my $listfile = installer::files::read_file($$filelistnameref);
2073
2074    my $infoline = "Found jds list file: $$filelistnameref\n";
2075    push( @installer::globals::logfileinfo, $infoline);
2076
2077    # substituting the variables
2078    substitute_dollar_variables($listfile, $allvariableshashref);
2079
2080    # determining the packages/RPMs to copy
2081    my $allexcludepackages = get_section_from_file($listfile, "excludefiles");
2082    my $allcopypackages = get_section_from_file($listfile, "copyfiles");
2083
2084    # determining the source directory
2085    my $alldirs = installer::systemactions::get_all_directories($installationdir);
2086    my $sourcedir = ${$alldirs}[0]; # there is only one directory
2087
2088    if ( $installer::globals::issolarisbuild ) { $sourcedir = $installer::globals::saved_packages_path; }
2089
2090    # copy all packages/RPMs
2091    copy_all_packages($allexcludepackages, $sourcedir, $jdsdir);
2092    copy_additional_packages($allcopypackages, $jdsdir, $includepatharrayref);
2093
2094    return $jdsdir;
2095}
2096
2097#############################################################################
2098# Checking, whether this installation set contains the correct languages
2099#############################################################################
2100
2101sub check_jds_language
2102{
2103    my ($allvariableshashref, $languagestringref) = @_;
2104
2105    my $infoline = "";
2106
2107    # languagesarrayref and $allvariableshashref->{'JDSLANG'}
2108
2109    if ( ! $allvariableshashref->{'JDSLANG'} ) { installer::exiter::exit_program("ERROR: For building JDS installation sets \"JDSLANG\" must be defined!", "check_jds_language"); }
2110    my $languagestring = $allvariableshashref->{'JDSLANG'};
2111
2112    my $sortedarray1 = installer::converter::convert_stringlist_into_array(\$languagestring, ",");
2113
2114    installer::sorter::sorting_array_of_strings($sortedarray1);
2115
2116    my $sortedarray2 = installer::converter::convert_stringlist_into_array($languagestringref, "_");
2117    installer::sorter::sorting_array_of_strings($sortedarray2);
2118
2119    my $string1 = installer::converter::convert_array_to_comma_separated_string($sortedarray1);
2120    my $string2 = installer::converter::convert_array_to_comma_separated_string($sortedarray2);
2121
2122    my $arrays_are_equal = compare_arrays($sortedarray1, $sortedarray2);
2123
2124    return $arrays_are_equal;
2125}
2126
2127###################################################################################
2128# Comparing two arrays. The arrays are equal, if the complete content is equal.
2129###################################################################################
2130
2131sub compare_arrays
2132{
2133    my ($array1, $array2) = @_;
2134
2135    my $arrays_are_equal = 1;
2136
2137    # checking the size
2138
2139    if ( ! ( $#{$array1} == $#{$array2} )) { $arrays_are_equal = 0; }   # different size
2140
2141    if ( $arrays_are_equal ) # only make further investigations if size is equal
2142    {
2143        for ( my $i = 0; $i <= $#{$array1}; $i++ )
2144        {
2145            # ingnoring whitespaces at end and beginning
2146            ${$array1}[$i] =~ s/^\s*//;
2147            ${$array2}[$i] =~ s/^\s*//;
2148            ${$array1}[$i] =~ s/\s*$//;
2149            ${$array2}[$i] =~ s/\s*$//;
2150
2151            if ( ! ( ${$array1}[$i] eq ${$array2}[$i] ))
2152            {
2153                $arrays_are_equal = 0;
2154                last;
2155            }
2156        }
2157    }
2158
2159    return $arrays_are_equal;
2160}
2161
2162#################################################################
2163# Copying the files defined as ScpActions into the
2164# installation set.
2165#################################################################
2166
2167sub put_scpactions_into_installset
2168{
2169    my ($installdir) = @_;
2170
2171    installer::logger::include_header_into_logfile("Start: Copying scp action files into installation set");
2172
2173    for ( my $i = 0; $i <= $#installer::globals::allscpactions; $i++ )
2174    {
2175        my $onescpaction = $installer::globals::allscpactions[$i];
2176
2177        my $subdir = "";
2178        if ( $onescpaction->{'Subdir'} ) { $subdir = $onescpaction->{'Subdir'}; }
2179
2180        if ( $onescpaction->{'Name'} eq "loader.exe" ) { next; }    # do not copy this ScpAction loader
2181
2182        my $destdir = $installdir;
2183        $destdir =~ s/\Q$installer::globals::separator\E\s*$//;
2184        if ( $subdir ) { $destdir = $destdir . $installer::globals::separator . $subdir; }
2185
2186        my $sourcefile = $onescpaction->{'sourcepath'};
2187        my $destfile = $destdir . $installer::globals::separator . $onescpaction->{'DestinationName'};
2188
2189        my $styles = "";
2190        if ( $onescpaction->{'Styles'} ) { $styles = $onescpaction->{'Styles'}; }
2191        if (( $styles =~ /\bFILE_CAN_MISS\b/ ) && ( $sourcefile eq "" )) { next; }
2192
2193        if (( $subdir =~ /\// ) || ( $subdir =~ /\\/ ))
2194        {
2195            installer::systemactions::create_directory_structure($destdir);
2196        }
2197        else
2198        {
2199            installer::systemactions::create_directory($destdir);
2200        }
2201
2202        installer::systemactions::copy_one_file($sourcefile, $destfile);
2203
2204        if ( $onescpaction->{'UnixRights'} )
2205        {
2206            my $localcall = "chmod $onescpaction->{'UnixRights'} $destfile \>\/dev\/null 2\>\&1";
2207            system($localcall);
2208        }
2209
2210    }
2211
2212    installer::logger::include_header_into_logfile("End: Copying scp action files into installation set");
2213
2214}
2215
2216#################################################################
2217# Collecting scp actions for all languages
2218#################################################################
2219
2220sub collect_scpactions
2221{
2222    my ($allscpactions) = @_;
2223
2224    for ( my $i = 0; $i <= $#{$allscpactions}; $i++ )
2225    {
2226        push(@installer::globals::allscpactions, ${$allscpactions}[$i]);
2227    }
2228}
2229
2230#################################################################
2231# Setting the platform name for download
2232#################################################################
2233
2234sub get_platform_name
2235{
2236    my $platformname = "";
2237
2238    if (( $installer::globals::islinuxintelrpmbuild ) || ( $installer::globals::islinuxinteldebbuild ))
2239    {
2240        $platformname = "LinuxIntel";
2241    }
2242    elsif (( $installer::globals::islinuxppcrpmbuild ) || ( $installer::globals::islinuxppcdebbuild ))
2243    {
2244        $platformname = "LinuxPowerPC";
2245    }
2246    elsif (( $installer::globals::islinuxx86_64rpmbuild ) || ( $installer::globals::islinuxx86_64debbuild ))
2247    {
2248        $platformname = "LinuxX86-64";
2249    }
2250    elsif ( $installer::globals::issolarissparcbuild )
2251    {
2252        $platformname = "SolarisSparc";
2253    }
2254    elsif ( $installer::globals::issolarisx86build )
2255    {
2256        $platformname = "Solarisx86";
2257    }
2258    elsif ( $installer::globals::iswindowsbuild )
2259    {
2260        $platformname = "Win32Intel";
2261    }
2262    elsif ( $installer::globals::compiler =~ /^unxmacxi/ )
2263    {
2264        $platformname = "MacOSXIntel";
2265    }
2266    elsif ( $installer::globals::compiler =~ /^unxmacxp/ )
2267    {
2268        $platformname = "MacOSXPowerPC";
2269    }
2270    else
2271    {
2272        # $platformname = $installer::globals::packageformat;
2273        $platformname = $installer::globals::compiler;
2274    }
2275
2276    return $platformname;
2277}
2278
2279###########################################################
2280# Adding additional variables into the variableshashref,
2281# that are defined in include files in the solver. The
2282# names of the include files are stored in
2283# ADD_INCLUDE_FILES (comma separated list).
2284###########################################################
2285
2286sub add_variables_from_inc_to_hashref
2287{
2288    my ($allvariables, $includepatharrayref) = @_;
2289
2290    my $infoline = "";
2291    my $includefilelist = "";
2292    if ( $allvariables->{'ADD_INCLUDE_FILES'} ) { $includefilelist = $allvariables->{'ADD_INCLUDE_FILES'}; }
2293
2294    my $includefiles = installer::converter::convert_stringlist_into_array_without_linebreak_and_quotes(\$includefilelist, ",");
2295
2296    for ( my $i = 0; $i <= $#{$includefiles}; $i++ )
2297    {
2298        my $includefilename = ${$includefiles}[$i];
2299        $includefilename =~ s/^\s*//;
2300        $includefilename =~ s/\s*$//;
2301        $includefilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$includefilename, $includepatharrayref, 1);
2302        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"); }
2303
2304        $infoline = "Including inc file: $$includefilenameref \n";
2305        push( @installer::globals::globallogfileinfo, $infoline);
2306
2307        my $includefile = installer::files::read_file($$includefilenameref);
2308
2309        for ( my $j = 0; $j <= $#{$includefile}; $j++ )
2310        {
2311            # Analyzing all "key=value" lines
2312            my $oneline = ${$includefile}[$j];
2313
2314            if ( $oneline =~ /^\s*(\S+)\s*\=\s*(.*?)\s*$/ ) # no white space allowed in key
2315            {
2316                my $key = $1;
2317                my $value = $2;
2318                $allvariables->{$key} = $value;
2319                $infoline = "Setting of variable: $key = $value\n";
2320                push( @installer::globals::globallogfileinfo, $infoline);
2321            }
2322        }
2323    }
2324
2325    # Allowing different Java versions for Windows and Unix. Instead of "JAVAVERSION"
2326    # the property "WINDOWSJAVAVERSION" has to be used, if it is set.
2327
2328    if ( $installer::globals::iswindowsbuild )
2329    {
2330        if (( exists($allvariables->{'WINDOWSJAVAVERSION'})) && ( $allvariables->{'WINDOWSJAVAVERSION'} ne "" ))
2331        {
2332            $allvariables->{'JAVAVERSION'} = $allvariables->{'WINDOWSJAVAVERSION'};
2333            $infoline = "Changing value of property \"JAVAVERSION\" to $allvariables->{'JAVAVERSION'} (property \"WINDOWSJAVAVERSION\").\n";
2334            push( @installer::globals::globallogfileinfo, $infoline);
2335        }
2336    }
2337}
2338
2339##############################################
2340# Collecting all files from include pathes
2341##############################################
2342
2343sub collect_all_files_from_includepathes
2344{
2345    my ($patharrayref) = @_;
2346
2347    installer::logger::globallog("Reading all directories: Start");
2348    installer::logger::print_message( "... reading include pathes ...\n" );
2349    # empty the global
2350
2351    @installer::globals::allincludepathes =();
2352    my $infoline;
2353
2354    for ( my $i = 0; $i <= $#{$patharrayref}; $i++ )
2355    {
2356        $includepath = ${$patharrayref}[$i];
2357        installer::remover::remove_leading_and_ending_whitespaces(\$includepath);
2358
2359        if ( ! -d $includepath )
2360        {
2361            $infoline = "$includepath does not exist. (Can be removed from include path list?)\n";
2362            push( @installer::globals::globallogfileinfo, $infoline);
2363            next;
2364        }
2365
2366        my @sourcefiles = ();
2367        my $pathstring = "";
2368        # installer::systemactions::read_complete_directory($includepath, $pathstring, \@sourcefiles);
2369        installer::systemactions::read_full_directory($includepath, $pathstring, \@sourcefiles);
2370
2371        if ( ! ( $#sourcefiles > -1 ))
2372        {
2373            $infoline = "$includepath is empty. (Can be removed from include path list?)\n";
2374            push( @installer::globals::globallogfileinfo, $infoline);
2375        }
2376        else
2377        {
2378            my $number = $#sourcefiles + 1;
2379            $infoline = "Directory $includepath contains $number files (including subdirs)\n";
2380            push( @installer::globals::globallogfileinfo, $infoline);
2381
2382            my %allfileshash = ();
2383            $allfileshash{'includepath'} = $includepath;
2384
2385            for ( my $j = 0; $j <= $#sourcefiles; $j++ )
2386            {
2387                $allfileshash{$sourcefiles[$j]} = 1;
2388            }
2389
2390            push(@installer::globals::allincludepathes, \%allfileshash);
2391        }
2392    }
2393
2394    $installer::globals::include_pathes_read = 1;
2395
2396    installer::logger::globallog("Reading all directories: End");
2397    push( @installer::globals::globallogfileinfo, "\n");
2398}
2399
2400##############################################
2401# Searching for a file with the gid
2402##############################################
2403
2404sub find_file_by_id
2405{
2406    my ( $filesref, $gid ) = @_;
2407
2408    my $foundfile = 0;
2409    my $onefile;
2410
2411    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
2412    {
2413        $onefile = ${$filesref}[$i];
2414        my $filegid = $onefile->{'gid'};
2415
2416        if ( $filegid eq $gid )
2417        {
2418            $foundfile = 1;
2419            last;
2420        }
2421    }
2422
2423    # It does not need to exist. For example products that do not contain the libraries.
2424    # if (! $foundfile ) { installer::exiter::exit_program("ERROR: No unique file name found for $filename !", "get_selfreg_file"); }
2425
2426    if (! $foundfile ) { $onefile  = ""; }
2427
2428    return $onefile;
2429}
2430
2431##############################################
2432# Searching for an item with the gid
2433##############################################
2434
2435sub find_item_by_gid
2436{
2437    my ( $itemsref, $gid ) = @_;
2438
2439    my $founditem = 0;
2440    my $oneitem = "";
2441
2442    for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
2443    {
2444        my $localitem = ${$itemsref}[$i];
2445        my $itemgid = $localitem->{'gid'};
2446
2447        if ( $itemgid eq $gid )
2448        {
2449            $oneitem = $localitem;
2450            $founditem = 1;
2451            last;
2452        }
2453    }
2454
2455    return $oneitem;
2456}
2457
2458#########################################################
2459# Calling sum
2460#########################################################
2461
2462sub call_sum
2463{
2464    my ($filename) = @_;
2465
2466    $sumfile = "/usr/bin/sum";
2467
2468    if ( ! -f $sumfile ) { installer::exiter::exit_program("ERROR: No file /usr/bin/sum", "call_sum"); }
2469
2470    my $systemcall = "$sumfile $filename |";
2471
2472    my $sumoutput = "";
2473
2474    open (SUM, "$systemcall");
2475    $sumoutput = <SUM>;
2476    close (SUM);
2477
2478    my $returnvalue = $?;   # $? contains the return value of the systemcall
2479
2480    my $infoline = "Systemcall: $systemcall\n";
2481    push( @installer::globals::logfileinfo, $infoline);
2482
2483    if ($returnvalue)
2484    {
2485        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
2486        push( @installer::globals::logfileinfo, $infoline);
2487    }
2488    else
2489    {
2490        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
2491        push( @installer::globals::logfileinfo, $infoline);
2492    }
2493
2494    return $sumoutput;
2495}
2496
2497#########################################################
2498# Calling wc
2499# wc -c pkginfo | cut -f6 -d' '
2500#########################################################
2501
2502sub call_wc
2503{
2504    my ($filename) = @_;
2505
2506    $wcfile = "/usr/bin/wc";
2507
2508    if ( ! -f $wcfile ) { installer::exiter::exit_program("ERROR: No file /usr/bin/wc", "call_wc"); }
2509
2510    my $systemcall = "$wcfile -c $filename |";
2511
2512    my $wcoutput = "";
2513
2514    open (WC, "$systemcall");
2515    $wcoutput = <WC>;
2516    close (WC);
2517
2518    my $returnvalue = $?;   # $? contains the return value of the systemcall
2519
2520    my $infoline = "Systemcall: $systemcall\n";
2521    push( @installer::globals::logfileinfo, $infoline);
2522
2523    if ($returnvalue)
2524    {
2525        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
2526        push( @installer::globals::logfileinfo, $infoline);
2527    }
2528    else
2529    {
2530        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
2531        push( @installer::globals::logfileinfo, $infoline);
2532    }
2533
2534    return $wcoutput;
2535}
2536
2537##############################################
2538# Setting architecture ARCH=i86pc
2539# instead of ARCH=i386.
2540##############################################
2541
2542sub set_old_architecture_string
2543{
2544    my ($pkginfofile) = @_;
2545
2546    for ( my $i = 0; $i <= $#{$pkginfofile}; $i++ )
2547    {
2548        if ( ${$pkginfofile}[$i] =~ /^\s*ARCH=i386\s*$/ )
2549        {
2550            ${$pkginfofile}[$i] =~ s/i386/i86pc/;
2551            last;
2552        }
2553    }
2554}
2555
2556##############################################
2557# For the new copied package, it is necessary
2558# that a value for the key SUNW_REQUIRES
2559# is set. Otherwise this copied package
2560# with ARCH=i86pc would be useless.
2561##############################################
2562
2563sub check_requires_setting
2564{
2565    my ($pkginfofile) = @_;
2566
2567    my $found = 0;
2568    my $patchid = "";
2569
2570    for ( my $i = 0; $i <= $#{$pkginfofile}; $i++ )
2571    {
2572        if ( ${$pkginfofile}[$i] =~ /^\s*SUNW_REQUIRES=(\S*?)\s*$/ )
2573        {
2574            $patchid = $1;
2575            $found = 1;
2576            last;
2577        }
2578    }
2579
2580    if (( ! $found ) || ( $patchid eq "" )) { installer::exiter::exit_program("ERROR: No patch id defined for SUNW_REQUIRES in patch pkginfo file!", "check_requires_setting"); }
2581}
2582
2583##############################################
2584# Setting checksum and wordcount for changed
2585# pkginfo file into pkgmap.
2586##############################################
2587
2588sub set_pkginfo_line
2589{
2590    my ($pkgmapfile, $pkginfofilename) = @_;
2591
2592    # 1 i pkginfo 442 34577 1166716297
2593    # ->
2594    # 1 i pkginfo 443 34737 1166716297
2595    #
2596    # wc -c pkginfo | cut -f6 -d' '  -> 442  (variable)
2597    # sum pkginfo | cut -f1 -d' '  -> 34577  (variable)
2598    # grep 'pkginfo' pkgmap | cut -f6 -d' '  -> 1166716297  (fix)
2599
2600    my $checksum = call_sum($pkginfofilename);
2601    if ( $checksum =~ /^\s*(\d+)\s+.*$/ ) { $checksum = $1; }
2602
2603    my $wordcount = call_wc($pkginfofilename);
2604    if ( $wordcount =~ /^\s*(\d+)\s+.*$/ ) { $wordcount = $1; }
2605
2606    for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ )
2607    {
2608        if ( ${$pkgmapfile}[$i] =~ /(^.*\bpkginfo\b\s+)(\d+)(\s+)(\d+)(\s+)(\d+)(\s*$)/ )
2609        {
2610            my $newline = $1 . $wordcount . $3 . $checksum . $5 . $6 . $7;
2611            ${$pkgmapfile}[$i] = $newline;
2612            last;
2613        }
2614    }
2615}
2616
2617##############################################
2618# Setting time stamp of copied files to avoid
2619# errors from pkgchk.
2620##############################################
2621
2622sub set_time_stamp
2623{
2624    my ($olddir, $newdir, $copyfiles) = @_;
2625
2626    for ( my $i = 0; $i <= $#{$copyfiles}; $i++ )
2627    {
2628        my $sourcefile = $olddir . $installer::globals::separator . ${$copyfiles}[$i];
2629        my $destfile = $newdir . $installer::globals::separator . ${$copyfiles}[$i];
2630
2631        my $systemcall = "touch -r $sourcefile $destfile";
2632
2633        my $returnvalue = system($systemcall);
2634
2635        my $infoline = "Systemcall: $systemcall\n";
2636        push( @installer::globals::logfileinfo, $infoline);
2637
2638        if ($returnvalue)
2639        {
2640            $infoline = "ERROR: \"$systemcall\" failed!\n";
2641            push( @installer::globals::logfileinfo, $infoline);
2642        }
2643        else
2644        {
2645            $infoline = "Success: \"$systemcall\" !\n";
2646            push( @installer::globals::logfileinfo, $infoline);
2647        }
2648    }
2649}
2650
2651############################################################
2652# Generating pathes for cygwin (first version)
2653# This function has problems with cygwin, if $tmpfilename
2654# contains many thousand files (OpenOffice SDK).
2655############################################################
2656
2657sub generate_cygwin_pathes_old
2658{
2659    my ($filesref) = @_;
2660
2661    my ($tmpfilehandle, $tmpfilename) = tmpnam();
2662    open SOURCEPATHLIST, ">$tmpfilename" or die "oops...\n";
2663    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
2664    {
2665        print SOURCEPATHLIST "${$filesref}[$i]->{'sourcepath'}\n";
2666    }
2667    close SOURCEPATHLIST;
2668    my @cyg_sourcepathlist = qx{cygpath -w -f "$tmpfilename"};
2669    chomp @cyg_sourcepathlist;
2670    unlink "$tmpfilename" or die "oops\n";
2671    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
2672    {
2673        ${$filesref}[$i]->{'cyg_sourcepath'} = $cyg_sourcepathlist[$i];
2674    }
2675
2676}
2677
2678#################################################
2679# Generating pathes for cygwin (second version)
2680# This function generates smaller files for
2681#################################################
2682
2683sub generate_cygwin_pathes
2684{
2685    my ($filesref) = @_;
2686
2687    installer::logger::include_timestamp_into_logfile("Starting generating cygwin pathes");
2688
2689    my $infoline = "Generating cygwin pathes (generate_cygwin_pathes)\n";
2690    push( @installer::globals::logfileinfo, $infoline);
2691
2692    my $max = 5000;  # number of pathes in one file
2693
2694    my @pathcollector = ();
2695    my $startnumber = 0;
2696    my $counter = 0;
2697
2698    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
2699    {
2700        my $line = ${$filesref}[$i]->{'sourcepath'} . "\n";
2701        push(@pathcollector, $line);
2702        $counter++;
2703
2704        if (( $i == $#{$filesref} ) || ((( $counter % $max ) == 0 ) && ( $i > 0 )))
2705        {
2706            my $tmpfilename = "cygwinhelper_" . $i . ".txt";
2707            my $temppath = $installer::globals::temppath;
2708            $temppath =~ s/\Q$installer::globals::separator\E\s*$//;
2709            $tmpfilename = $temppath . $installer::globals::separator . $tmpfilename;
2710            $infoline = "Creating temporary file for cygwin conversion: $tmpfilename (contains $counter pathes)\n";
2711            push( @installer::globals::logfileinfo, $infoline);
2712            if ( -f $tmpfilename ) { unlink $tmpfilename; }
2713
2714            installer::files::save_file($tmpfilename, \@pathcollector);
2715
2716            my $success = 0;
2717            my @cyg_sourcepathlist = qx{cygpath -w -f "$tmpfilename"};
2718            chomp @cyg_sourcepathlist;
2719
2720            # Validating the array, it has to contain the correct number of values
2721            my $new_pathes = $#cyg_sourcepathlist + 1;
2722            if ( $new_pathes == $counter ) { $success = 1; }
2723
2724            if ($success)
2725            {
2726                $infoline = "Success: Successfully converted to cygwin pathes!\n";
2727                push( @installer::globals::logfileinfo, $infoline);
2728            }
2729            else
2730            {
2731                $infoline = "ERROR: Failed to convert to cygwin pathes!\n";
2732                push( @installer::globals::logfileinfo, $infoline);
2733                installer::exiter::exit_program("ERROR: Failed to convert to cygwin pathes!", "generate_cygwin_pathes");
2734            }
2735
2736            for ( my $j = 0; $j <= $#cyg_sourcepathlist; $j++ )
2737            {
2738                my $number = $startnumber + $j;
2739                ${$filesref}[$number]->{'cyg_sourcepath'} = $cyg_sourcepathlist[$j];
2740            }
2741
2742            if ( -f $tmpfilename ) { unlink $tmpfilename; }
2743
2744            @pathcollector = ();
2745            $startnumber = $startnumber + $max;
2746            $counter = 0;
2747        }
2748    }
2749
2750    # Checking existence fo cyg_sourcepath for every file
2751    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
2752    {
2753        if (( ! exists(${$filesref}[$i]->{'cyg_sourcepath'}) ) || ( ${$filesref}[$i]->{'cyg_sourcepath'} eq "" ))
2754        {
2755            $infoline = "ERROR: No cygwin sourcepath defined for file ${$filesref}[$i]->{'sourcepath'}\n";
2756            push( @installer::globals::logfileinfo, $infoline);
2757            installer::exiter::exit_program("ERROR: No cygwin sourcepath defined for file ${$filesref}[$i]->{'sourcepath'}!", "generate_cygwin_pathes");
2758        }
2759    }
2760
2761    installer::logger::include_timestamp_into_logfile("Ending generating cygwin pathes");
2762}
2763
2764##############################################
2765# Include only files from install directory
2766# in pkgmap file.
2767##############################################
2768
2769sub filter_pkgmapfile
2770{
2771    my ($pkgmapfile) = @_;
2772
2773    my @pkgmap = ();
2774
2775    my $line = ": 1 10\n";
2776    push(@pkgmap, $line);
2777
2778    for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ )
2779    {
2780        $line = ${$pkgmapfile}[$i];
2781        if ( $line =~ /^\s*1\si\s/ ) { push(@pkgmap, $line); }
2782    }
2783
2784    return \@pkgmap;
2785}
2786
2787##############################################
2788# Creating double packages for Solaris x86.
2789# One package with ARCH=i386 and one with
2790# ARCH=i86pc.
2791##############################################
2792
2793sub fix_solaris_x86_patch
2794{
2795    my ($packagename, $subdir) = @_;
2796
2797    # changing into directory of packages, important for soft linking
2798    my $startdir = cwd();
2799    chdir($subdir);
2800
2801    # $packagename is: "SUNWstaroffice-core01"
2802    # Current working directory is: "<path>/install/en-US_inprogress"
2803
2804    # create new folder in "packages": $packagename . ".i"
2805    my $newpackagename = $packagename . "\.i";
2806    my $newdir = $newpackagename;
2807    installer::systemactions::create_directory($newdir);
2808
2809    # collecting all directories in the package
2810    my $olddir = $packagename;
2811    my $allsubdirs = installer::systemactions::get_all_directories_without_path($olddir);
2812
2813    # link all directories from $packagename to $packagename . ".i"
2814    for ( my $i = 0; $i <= $#{$allsubdirs}; $i++ )
2815    {
2816        my $sourcedir = $olddir . $installer::globals::separator . ${$allsubdirs}[$i];
2817        my $destdir = $newdir . $installer::globals::separator . ${$allsubdirs}[$i];
2818        my $directory_depth = 2; # important for soft links, two directories already exist
2819        installer::systemactions::softlink_complete_directory($sourcedir, $destdir, $directory_depth);
2820    }
2821
2822    # copy "pkginfo" and "pkgmap" from $packagename to $packagename . ".i"
2823    my @allcopyfiles = ("pkginfo", "pkgmap");
2824    for ( my $i = 0; $i <= $#allcopyfiles; $i++ )
2825    {
2826        my $sourcefile = $olddir . $installer::globals::separator . $allcopyfiles[$i];
2827        my $destfile = $newdir . $installer::globals::separator . $allcopyfiles[$i];
2828        installer::systemactions::copy_one_file($sourcefile, $destfile);
2829    }
2830
2831    # change in pkginfo in $packagename . ".i" the value for ARCH from i386 to i86pc
2832    my $pkginfofilename = "pkginfo";
2833    $pkginfofilename = $newdir . $installer::globals::separator . $pkginfofilename;
2834
2835    my $pkginfofile = installer::files::read_file($pkginfofilename);
2836    set_old_architecture_string($pkginfofile);
2837    installer::files::save_file($pkginfofilename, $pkginfofile);
2838
2839    # adapt the values in pkgmap for pkginfo file, because this file was edited
2840    my $pkgmapfilename = "pkgmap";
2841    $pkgmapfilename = $newdir . $installer::globals::separator . $pkgmapfilename;
2842
2843    my $pkgmapfile = installer::files::read_file($pkgmapfilename);
2844    set_pkginfo_line($pkgmapfile, $pkginfofilename);
2845    installer::files::save_file($pkgmapfilename, $pkgmapfile);
2846
2847    # changing back to startdir
2848    chdir($startdir);
2849}
2850
2851###################################################
2852# Creating double core01 package for Solaris x86.
2853# One package with ARCH=i386 and one with
2854# ARCH=i86pc. This is necessary, to inform the
2855# user about the missing "small patch", if
2856# packages with ARCH=i86pc are installed.
2857###################################################
2858
2859sub fix2_solaris_x86_patch
2860{
2861    my ($packagename, $subdir) = @_;
2862
2863    if ( $packagename =~ /-core01\s*$/ )    # only this one package needs to be duplicated
2864    {
2865        my $startdir = cwd();
2866        chdir($subdir);
2867
2868        # $packagename is: "SUNWstaroffice-core01"
2869        # Current working directory is: "<path>/install/en-US_inprogress"
2870
2871        # create new package in "packages": $packagename . ".i"
2872        my $olddir = $packagename;
2873        my $newpackagename = $packagename . "\.i";
2874        my $newdir = $newpackagename;
2875
2876        installer::systemactions::create_directory($newdir);
2877
2878        my $oldinstalldir = $olddir . $installer::globals::separator . "install";
2879        my $newinstalldir = $newdir . $installer::globals::separator . "install";
2880
2881        installer::systemactions::copy_complete_directory($oldinstalldir, $newinstalldir);
2882
2883        # setting time stamp of all copied files to avoid errors from pkgchk
2884        my $allinstallfiles = installer::systemactions::get_all_files_from_one_directory_without_path($newinstalldir);
2885        set_time_stamp($oldinstalldir, $newinstalldir, $allinstallfiles);
2886
2887        # copy "pkginfo" and "pkgmap" from $packagename to $packagename . ".i"
2888        my @allcopyfiles = ("pkginfo", "pkgmap");
2889        for ( my $i = 0; $i <= $#allcopyfiles; $i++ )
2890        {
2891            my $sourcefile = $olddir . $installer::globals::separator . $allcopyfiles[$i];
2892            my $destfile = $newdir . $installer::globals::separator . $allcopyfiles[$i];
2893            installer::systemactions::copy_one_file($sourcefile, $destfile);
2894        }
2895
2896        # change in pkginfo in $packagename . ".i" the value for ARCH from i386 to i86pc
2897        my $pkginfofilename = "pkginfo";
2898        $pkginfofilename = $newdir . $installer::globals::separator . $pkginfofilename;
2899
2900        my $pkginfofile = installer::files::read_file($pkginfofilename);
2901        set_old_architecture_string($pkginfofile);
2902        check_requires_setting($pkginfofile);
2903        installer::files::save_file($pkginfofilename, $pkginfofile);
2904
2905        # adapt the values in pkgmap for pkginfo file, because this file was edited
2906        my $pkgmapfilename = "pkgmap";
2907        $pkgmapfilename = $newdir . $installer::globals::separator . $pkgmapfilename;
2908
2909        my $pkgmapfile = installer::files::read_file($pkgmapfilename);
2910        set_pkginfo_line($pkgmapfile, $pkginfofilename);
2911        $pkgmapfile = filter_pkgmapfile($pkgmapfile);
2912        installer::files::save_file($pkgmapfilename, $pkgmapfile);
2913
2914        # setting time stamp of all copied files to avoid errors from pkgchk
2915        set_time_stamp($olddir, $newdir, \@allcopyfiles);
2916
2917        # changing back to startdir
2918        chdir($startdir);
2919    }
2920}
2921
2922################################################
2923# Files with flag HIDDEN get a dot at the
2924# beginning of the file name. This cannot be
2925# defined in scp2 project, because tooling
2926# cannot handle files with beginning dot
2927# correctly.
2928################################################
2929
2930sub resolving_hidden_flag
2931{
2932    my ($filesarrayref, $variableshashref, $item, $languagestringref) = @_;
2933
2934    my $diritem = lc($item);
2935    my $infoline = "";
2936
2937    my $hiddendirbase = installer::systemactions::create_directories("hidden_$diritem", $languagestringref);
2938
2939    installer::logger::include_header_into_logfile("$item with flag HIDDEN:");
2940
2941    for ( my $i = 0; $i <= $#{$filesarrayref}; $i++ )
2942    {
2943        my $onefile = ${$filesarrayref}[$i];
2944        my $styles = "";
2945
2946        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
2947
2948        if ( $styles =~ /\bHIDDEN\b/ )
2949        {
2950            # Language specific subdirectory
2951
2952            my $onelanguage = $onefile->{'specificlanguage'};
2953
2954            if ($onelanguage eq "")
2955            {
2956                $onelanguage = "00";    # files without language into directory "00"
2957            }
2958
2959            my $hiddendir = $hiddendirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator;
2960            installer::systemactions::create_directory($hiddendir); # creating language specific directories
2961
2962            # copy files and edit them with the variables defined in the zip.lst
2963
2964            my $onefilename = $onefile->{'Name'};
2965            my $newfilename = "\." . $onefilename;
2966            my $sourcefile = $onefile->{'sourcepath'};
2967            my $destfile = $hiddendir . $newfilename;
2968
2969            my $copysuccess = installer::systemactions::copy_one_file($sourcefile, $destfile);
2970
2971            if ( $copysuccess )
2972            {
2973                # $onefile->{'Name'} = $newfilename;
2974                $onefile->{'sourcepath'} = $destfile;
2975                $destination = $onefile->{'destination'};
2976                installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
2977                if ( $destination eq "" ) { $onefile->{'destination'} = $newfilename; }
2978                else { $onefile->{'destination'} = $destination . $installer::globals::separator . $newfilename; }
2979
2980                $infoline = "Success: Using file with flag HIDDEN from \"$onefile->{'sourcepath'}\"!\n";
2981                push( @installer::globals::logfileinfo, $infoline);
2982            }
2983            else
2984            {
2985                $infoline = "Error: Failed to copy HIDDEN file from \"$sourcefile\" to \"$destfile\"!\n";
2986                push( @installer::globals::logfileinfo, $infoline);
2987            }
2988        }
2989    }
2990
2991    $infoline = "\n";
2992    push( @installer::globals::logfileinfo, $infoline);
2993}
2994
2995################################################
2996# Controlling that all keys in hash A are
2997# also key in hash B.
2998################################################
2999
3000sub key_in_a_is_also_key_in_b
3001{
3002    my ( $hashref_a, $hashref_b) = @_;
3003
3004    my $returnvalue = 1;
3005
3006    my $key;
3007    foreach $key ( keys %{$hashref_a} )
3008    {
3009        if ( ! exists($hashref_b->{$key}) )
3010        {
3011            print "*****\n";
3012            foreach $keyb ( keys %{$hashref_b} ) { print "$keyb : $hashref_b->{$keyb}\n"; }
3013            print "*****\n";
3014            $returnvalue = 0;
3015        }
3016    }
3017
3018    return $returnvalue;
3019}
3020
3021######################################################
3022# Getting the first entry from a list of languages
3023######################################################
3024
3025sub get_first_from_list
3026{
3027    my ( $list ) = @_;
3028
3029    my $first = $list;
3030
3031    if ( $list =~ /^\s*(.+?),(.+)\s*$/) # "?" for minimal matching
3032    {
3033        $first = $1;
3034    }
3035
3036    return $first;
3037}
3038
3039################################################
3040# Setting all spellchecker languages
3041################################################
3042
3043sub set_spellcheckerlanguages
3044{
3045    my ( $productlanguagesarrayref, $allvariables ) = @_;
3046
3047    my %productlanguages = ();
3048    for ( my $i = 0; $i <= $#{$productlanguagesarrayref}; $i++ ) { $productlanguages{${$productlanguagesarrayref}[$i]} = 1;  }
3049
3050    my $spellcheckfilename = $allvariables->{'SPELLCHECKERFILE'};
3051
3052    my $spellcheckfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$spellcheckfilename, "", 1);
3053
3054    if ($$spellcheckfileref eq "") { installer::exiter::exit_program("ERROR: Could not find $spellcheckfilename!", "set_spellcheckerlanguages"); }
3055
3056    my $infoline = "Using spellchecker file: $$spellcheckfileref \n";
3057    push( @installer::globals::globallogfileinfo, $infoline);
3058
3059    my $spellcheckfile = installer::files::read_file($$spellcheckfileref);
3060    my %spellcheckhash = ();
3061
3062    for ( my $j = 0; $j <= $#{$spellcheckfile}; $j++ )
3063    {
3064        # Analyzing all "key=value" lines
3065        my $oneline = ${$spellcheckfile}[$j];
3066
3067        if ( $oneline =~ /^\s*(\S+)\s*\=\s*\"(.*?)\"\s*$/ ) # no white space allowed in key
3068        {
3069            my $onelang = $1;
3070            my $languagelist = $2;
3071
3072            # Special handling for language packs. Only include the first language of the language list.
3073            # If no spellchecker shall be included, the keyword "EMPTY" can be used.
3074
3075            if ( $installer::globals::languagepack )
3076            {
3077                my $first = get_first_from_list($languagelist);
3078
3079                if ( $first eq "EMPTY" )     # no spellchecker into language pack
3080                {
3081                    $languagelist = "";
3082                }
3083                else
3084                {
3085                    $languagelist = $first;
3086                }
3087            }
3088            else  # no language pack, so EMPTY is not required
3089            {
3090                $languagelist =~ s/^\s*EMPTY\s*,//; # removing the entry EMPTY
3091            }
3092
3093            $spellcheckhash{$onelang} = $languagelist;
3094        }
3095    }
3096
3097    # Collecting all required languages in %installer::globals::spellcheckerlanguagehash
3098
3099    foreach my $lang (keys %productlanguages)
3100    {
3101        my $languagelist = "";
3102        if ( exists($spellcheckhash{$lang}) ) { $languagelist = $spellcheckhash{$lang}; }
3103        else { $languagelist = $spellcheckhash{'en-US'}; }  # defaulting to English
3104
3105        my $langlisthash = installer::converter::convert_stringlist_into_hash(\$languagelist, ",");
3106        foreach my $onelang ( keys %{$langlisthash} ) { $installer::globals::spellcheckerlanguagehash{$onelang} = 1; }
3107    }
3108
3109    $installer::globals::analyze_spellcheckerlanguage = 1;
3110
3111    # Logging
3112
3113    my $langstring = "";
3114    foreach my $lang (sort keys %installer::globals::spellcheckerlanguagehash) { $langstring = $langstring . "," . $lang }
3115    $langstring =~ s/^\s*,//;
3116
3117    $infoline = "Collected spellchecker languages for spellchecker: $langstring \n";
3118    push( @installer::globals::globallogfileinfo, $infoline);
3119}
3120
3121################################################
3122# Including a license text into setup script
3123################################################
3124
3125sub put_license_into_setup
3126{
3127    my ($installdir, $includepatharrayref) = @_;
3128
3129    # find and read the license file
3130    my $licenselanguage = "en-US";                  # always english !
3131    my $licensefilename = "LICENSE";
3132#   my $licensefilename = "LICENSE" . ".txt";
3133    my $licenseincludepatharrayref = get_language_specific_include_pathes($includepatharrayref, $licenselanguage);
3134
3135    my $licenseref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$licensefilename, $licenseincludepatharrayref, 0);
3136    if ($$licenseref eq "") { installer::exiter::exit_program("ERROR: Could not find License file $licensefilename!", "put_license_into_setup"); }
3137    my $licensefile = installer::files::read_file($$licenseref);
3138
3139    # Read setup
3140    my $setupfilename = $installdir . $installer::globals::separator . "setup";
3141    my $setupfile = installer::files::read_file($setupfilename);
3142
3143    # Replacement
3144    my $infoline = "Adding licensefile into setup script\n";
3145    push( @installer::globals::logfileinfo, $infoline);
3146
3147    my $includestring = "";
3148    for ( my $i = 0; $i <= $#{$licensefile}; $i++ ) { $includestring = $includestring . ${$licensefile}[$i]; }
3149    for ( my $i = 0; $i <= $#{$setupfile}; $i++ ) { ${$setupfile}[$i] =~ s/LICENSEFILEPLACEHOLDER/$includestring/; }
3150
3151    # Write setup
3152    installer::files::save_file($setupfilename, $setupfile);
3153}
3154
3155################################################
3156# Setting global path to getuid.so library
3157################################################
3158
3159sub set_getuid_path
3160{
3161    my ($includepatharrayref) = @_;
3162
3163    my $getuidlibraryname = "getuid.so";
3164    my $getuidlibraryref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$getuidlibraryname, $includepatharrayref, 0);
3165    if ($$getuidlibraryref eq "") { installer::exiter::exit_program("ERROR: Could not find $getuidlibraryname!", "set_getuid_path"); }
3166
3167    $installer::globals::getuidpath = $$getuidlibraryref;
3168    $installer::globals::getuidpathset = 1;
3169}
3170
3171#########################################################
3172# Create a tar file from the binary package
3173#########################################################
3174
3175sub tar_package
3176{
3177    my ( $installdir, $packagename, $tarfilename, $getuidlibrary) = @_;
3178
3179    my $ldpreloadstring = "";
3180    if ( $getuidlibrary ne "" ) { $ldpreloadstring = "LD_PRELOAD=" . $getuidlibrary; }
3181
3182    my $systemcall = "cd $installdir; $ldpreloadstring tar -cf - $packagename > $tarfilename";
3183    # my $systemcall = "cd $installdir; $ldpreloadstring tar -cf - * > $tarfilename";
3184
3185    my $returnvalue = system($systemcall);
3186
3187    my $infoline = "Systemcall: $systemcall\n";
3188    push( @installer::globals::logfileinfo, $infoline);
3189
3190    if ($returnvalue)
3191    {
3192        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
3193        push( @installer::globals::logfileinfo, $infoline);
3194    }
3195    else
3196    {
3197        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
3198        push( @installer::globals::logfileinfo, $infoline);
3199    }
3200
3201    my $localcall = "chmod 775 $tarfilename \>\/dev\/null 2\>\&1";
3202    $returnvalue = system($localcall);
3203
3204    my $fulltarfile = $installdir . $installer::globals::separator . $tarfilename;
3205    my $filesize = ( -s $fulltarfile );
3206
3207    return $filesize;
3208}
3209
3210#########################################################
3211# Create a tar file from the binary package
3212#########################################################
3213
3214sub untar_package
3215{
3216    my ( $installdir, $tarfilename, $getuidlibrary) = @_;
3217
3218    my $ldpreloadstring = "";
3219    if ( $getuidlibrary ne "" ) { $ldpreloadstring = "LD_PRELOAD=" . $getuidlibrary; }
3220
3221    my $systemcall = "cd $installdir; $ldpreloadstring tar -xf $tarfilename";
3222
3223    my $returnvalue = system($systemcall);
3224
3225    my $infoline = "Systemcall: $systemcall\n";
3226    push( @installer::globals::logfileinfo, $infoline);
3227
3228    if ($returnvalue)
3229    {
3230        $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
3231        push( @installer::globals::logfileinfo, $infoline);
3232    }
3233    else
3234    {
3235        $infoline = "Success: Executed \"$systemcall\" successfully!\n";
3236        push( @installer::globals::logfileinfo, $infoline);
3237    }
3238
3239    my $localcall = "chmod 775 $tarfilename \>\/dev\/null 2\>\&1";
3240    $returnvalue = system($localcall);
3241}
3242
3243#########################################################
3244# Shuffle an array (Fisher Yates shuffle)
3245#########################################################
3246
3247sub shuffle_array
3248{
3249    my ( $arrayref ) = @_;
3250
3251    # my $counter = 0;
3252    # my $infoline = "Old package order: \n";
3253    # push( @installer::globals::logfileinfo, $infoline);
3254    # foreach my $onepackage ( @{$arrayref} )
3255    # {
3256    #   $counter++;
3257    #   $infoline = "$counter: $onepackage->{'module'}\n";
3258    #   push( @installer::globals::logfileinfo, $infoline);
3259    # }
3260
3261    my $i = @$arrayref;
3262    while (--$i)
3263    {
3264        my $j = int rand ($i+1);
3265        @$arrayref[$i,$j] = @$arrayref[$j,$i];
3266    }
3267
3268    # $counter = 0;
3269    # $infoline = "New package order: \n";
3270    # push( @installer::globals::logfileinfo, $infoline);
3271    # foreach my $onepackage ( @{$arrayref} )
3272    # {
3273    #   $counter++;
3274    #   $infoline = "$counter: $onepackage->{'module'}\n";
3275    #   push( @installer::globals::logfileinfo, $infoline);
3276    # }
3277}
3278
3279################################################
3280# Defining the English license text to add
3281# it into Solaris packages.
3282################################################
3283
3284sub set_english_license
3285{
3286    my $additional_license_name = $installer::globals::englishsolarislicensename;   # always the English file
3287    my $licensefileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$additional_license_name, "" , 0);
3288    if ( $$licensefileref eq "" ) { installer::exiter::exit_program("ERROR: Could not find license file $additional_license_name!", "set_english_license"); }
3289    $installer::globals::englishlicenseset = 1;
3290    $installer::globals::englishlicense = installer::files::read_file($$licensefileref);
3291    installer::scpzipfiles::replace_all_ziplistvariables_in_file($installer::globals::englishlicense, $variableshashref);
3292}
3293
3294##############################################
3295# Setting time stamp of copied files to avoid
3296# errors from pkgchk.
3297##############################################
3298
3299sub set_time_stamp_for_file
3300{
3301    my ($sourcefile, $destfile) = @_;
3302
3303    my $systemcall = "touch -r $sourcefile $destfile";
3304
3305    my $returnvalue = system($systemcall);
3306
3307    my $infoline = "Systemcall: $systemcall\n";
3308    push( @installer::globals::logfileinfo, $infoline);
3309
3310    if ($returnvalue)
3311    {
3312        $infoline = "ERROR: \"$systemcall\" failed!\n";
3313        push( @installer::globals::logfileinfo, $infoline);
3314    }
3315    else
3316    {
3317        $infoline = "Success: \"$systemcall\" !\n";
3318        push( @installer::globals::logfileinfo, $infoline);
3319    }
3320}
3321
3322##############################################
3323# Setting checksum and wordcount for changed
3324# pkginfo file into pkgmap.
3325##############################################
3326
3327sub change_onefile_in_pkgmap
3328{
3329    my ($pkgmapfile, $fullfilename, $shortfilename) = @_;
3330
3331    # 1 i pkginfo 442 34577 1166716297
3332    # ->
3333    # 1 i pkginfo 443 34737 1166716297
3334    #
3335    # wc -c pkginfo | cut -f6 -d' '  -> 442  (variable)
3336    # sum pkginfo | cut -f1 -d' '  -> 34577  (variable)
3337    # grep 'pkginfo' pkgmap | cut -f6 -d' '  -> 1166716297  (fix)
3338
3339    my $checksum = call_sum($fullfilename);
3340    if ( $checksum =~ /^\s*(\d+)\s+.*$/ ) { $checksum = $1; }
3341
3342    my $wordcount = call_wc($fullfilename);
3343    if ( $wordcount =~ /^\s*(\d+)\s+.*$/ ) { $wordcount = $1; }
3344
3345    for ( my $i = 0; $i <= $#{$pkgmapfile}; $i++ )
3346    {
3347        if ( ${$pkgmapfile}[$i] =~ /(^.*\b\Q$shortfilename\E\b\s+)(\d+)(\s+)(\d+)(\s+)(\d+)(\s*$)/ )
3348        {
3349            my $newline = $1 . $wordcount . $3 . $checksum . $5 . $6 . $7;
3350            ${$pkgmapfile}[$i] = $newline;
3351            last;
3352        }
3353    }
3354}
3355
3356################################################
3357# Adding the content of the English license
3358# file into the system integration packages.
3359################################################
3360
3361sub add_license_into_systemintegrationpackages
3362{
3363    my ($destdir, $packages) = @_;
3364
3365    for ( my $i = 0; $i <= $#{$packages}; $i++ )
3366    {
3367        my $copyrightfilename = ${$packages}[$i] . $installer::globals::separator . "install" . $installer::globals::separator . "copyright";
3368        if ( ! -f $copyrightfilename ) { installer::exiter::exit_program("ERROR: Could not find license file in system integration package: $copyrightfilename!", "add_license_into_systemintegrationpackages"); }
3369        my $copyrightfile = installer::files::read_file($copyrightfilename);
3370
3371        # Saving time stamp of old copyrightfile
3372        my $savcopyrightfilename = $copyrightfilename . ".sav";
3373        installer::systemactions::copy_one_file($copyrightfilename, $savcopyrightfilename);
3374        set_time_stamp_for_file($copyrightfilename, $savcopyrightfilename); # now $savcopyrightfile has the time stamp of $copyrightfile
3375
3376        # Adding license content to copyright file
3377        push(@{$copyrightfile}, "\n");
3378        for ( my $i = 0; $i <= $#{$installer::globals::englishlicense}; $i++ ) { push(@{$copyrightfile}, ${$installer::globals::englishlicense}[$i]); }
3379        installer::files::save_file($copyrightfilename, $copyrightfile);
3380
3381        # Setting the old time stamp saved with $savcopyrightfilename
3382        set_time_stamp_for_file($savcopyrightfilename, $copyrightfilename); # now $copyrightfile has the time stamp of $savcopyrightfile
3383        unlink($savcopyrightfilename);
3384
3385        # Changing content of copyright file in pkgmap
3386        my $pkgmapfilename = ${$packages}[$i] . $installer::globals::separator . "pkgmap";
3387        if ( ! -f $pkgmapfilename ) { installer::exiter::exit_program("ERROR: Could not find pkgmap in system integration package: $pkgmapfilename!", "add_license_into_systemintegrationpackages"); }
3388        my $pkgmap = installer::files::read_file($pkgmapfilename);
3389        change_onefile_in_pkgmap($pkgmap, $copyrightfilename, "copyright");
3390        installer::files::save_file($pkgmapfilename, $pkgmap);
3391    }
3392}
3393
3394#########################################################
3395# Collecting all pkgmap files from an installation set
3396#########################################################
3397
3398sub collectpackagemaps
3399{
3400    my ( $installdir, $languagestringref, $allvariables ) = @_;
3401
3402    installer::logger::include_header_into_logfile("Collecing all packagemaps (pkgmap):");
3403
3404    my $pkgmapdir = installer::systemactions::create_directories("pkgmap", $languagestringref);
3405    my $subdirname = $allvariables->{'UNIXPRODUCTNAME'} . "_pkgmaps";
3406    my $pkgmapsubdir = $pkgmapdir . $installer::globals::separator . $subdirname;
3407    if ( -d $pkgmapsubdir ) { installer::systemactions::remove_complete_directory($pkgmapsubdir); }
3408    if ( ! -d $pkgmapsubdir ) { installer::systemactions::create_directory($pkgmapsubdir); }
3409
3410    $installdir =~ s/\/\s*$//;
3411    # Collecting all packages in $installdir and its sub package ("packages")
3412    my $searchdir = $installdir . $installer::globals::separator . $installer::globals::epmoutpath;
3413
3414    my $allpackages = installer::systemactions::get_all_directories_without_path($searchdir);
3415
3416    for ( my $i = 0; $i <= $#{$allpackages}; $i++ )
3417    {
3418        my $pkgmapfile = $searchdir . $installer::globals::separator . ${$allpackages}[$i] . $installer::globals::separator . "pkgmap";
3419        my $destfilename = $pkgmapsubdir . $installer::globals::separator . ${$allpackages}[$i] . "_pkgmap";
3420        installer::systemactions::copy_one_file($pkgmapfile, $destfilename);
3421    }
3422
3423    # Create a tar gz file with all package maps
3424    my $tarfilename = $subdirname . ".tar";
3425    my $targzname = $tarfilename . ".gz";
3426    # my $systemcall = "cd $pkgmapdir; tar -cf - $subdirname > $tarfilename";
3427    $systemcall = "cd $pkgmapdir; tar -cf - $subdirname | gzip > $targzname";
3428    make_systemcall($systemcall);
3429    installer::systemactions::remove_complete_directory($pkgmapsubdir, 1);
3430}
3431
34321;
3433