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