1: 2eval 'exec perl -S $0 ${1+"$@"}' 3 if 0; 4#************************************************************************* 5# 6# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7# 8# Copyright 2000, 2010 Oracle and/or its affiliates. 9# 10# OpenOffice.org - a multi-platform office productivity suite 11# 12# This file is part of OpenOffice.org. 13# 14# OpenOffice.org is free software: you can redistribute it and/or modify 15# it under the terms of the GNU Lesser General Public License version 3 16# only, as published by the Free Software Foundation. 17# 18# OpenOffice.org is distributed in the hope that it will be useful, 19# but WITHOUT ANY WARRANTY; without even the implied warranty of 20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21# GNU Lesser General Public License version 3 for more details 22# (a copy is included in the LICENSE file that accompanied this code). 23# 24# You should have received a copy of the GNU Lesser General Public License 25# version 3 along with OpenOffice.org. If not, see 26# <http://www.openoffice.org/license.html> 27# for a copy of the LGPLv3 License. 28# 29#************************************************************************* 30# 31# build_client - client for the build tool in server mode 32# 33 34use strict; 35use Socket; 36use Sys::Hostname; 37use File::Temp qw(tmpnam); 38use POSIX; 39use Cwd qw (cwd); 40 41$SIG{KILL} = \&handle_temp_files; 42$SIG{INT} = \&handle_temp_files; 43 44### main ### 45my $enable_multiprocessing = 1; 46my $server_list_file; 47my $server_list_time_stamp = 0; 48my %ENV_BACKUP; 49$ENV_BACKUP{$_} = $ENV{$_} foreach (keys %ENV); 50 51if ($^O eq 'MSWin32') { 52 eval { require Win32::Process; import Win32::Process; }; 53 $enable_multiprocessing = 0 if ($@); 54} else { 55 use Cwd 'chdir'; 56}; 57my $processes_to_run = 1; 58 59my %hosts_ports = (); 60my $default_port = 7890; 61my @ARGV_COPY = @ARGV; # @ARGV BACKUP 62#$ARGV_COPY{$_}++ foreach (@ARGV); 63print "arguments: @ARGV\n"; 64get_options(); 65 66my $proto = getprotobyname('tcp'); 67my $paddr; 68my $host = hostname(); 69my $current_server = ''; 70my $got_job = 0; 71my %job_temp_files = (); 72my %environments = (); # hash containing all environments 73my $env_alias; 74my %platform_rejects = (); # hash containing paddr of server, that replied "Wrong platform" 75 76my $child = 0; 77if ($processes_to_run > 1) { 78 my $started_processes = 1; 79 if ($^O eq 'MSWin32') { 80 my $process_obj = undef; 81 my $child_args = "perl $0"; 82 foreach (@ARGV_COPY) { 83 /^-P(\d+)$/ and next; 84 /^-P$/ and shift @ARGV_COPY and next; 85 $child_args .= " $_"; 86 }; 87 do { 88 my $rc = Win32::Process::Create($process_obj, $^X, 89 $child_args, 90 0, 0, #NORMAL_PRIORITY_CLASS, 91 "."); 92 print_error("Cannot start child process") if (!$rc); 93 $started_processes++; 94 } while ($started_processes < $processes_to_run); 95 } else { 96 my $pid; 97 do { 98 if ($pid = fork) { # parent 99 $started_processes++; 100 print $started_processes . "\n"; 101 } elsif (defined $pid) { # child 102 $child++; 103 }; 104 } while (($started_processes < $processes_to_run) && !$child); 105 }; 106}; 107 108run_client(); 109### end of main procedure ### 110 111######################### 112# # 113# Procedures # 114# # 115######################### 116sub handle_temp_files { 117 print STDERR "Got signal - clearing up...\n"; 118 foreach (keys %job_temp_files) { 119 if ($job_temp_files{$_}) { 120 rename($_, $job_temp_files{$_}) or system("mv", $_, $job_temp_files{$_}); 121 print STDERR "Could not rename $_ to $job_temp_files{$_}\n" if (-e $_); 122 } else { 123 unlink $_ or system("rm -rf $_"); 124 print STDERR "Could not remove $_\n" if (-e $_); 125 }; 126 }; 127 exit($?); 128}; 129 130sub run_client { 131# initialize host and port 132 if (!scalar keys %hosts_ports) { 133 $hosts_ports{localhost} = $default_port; 134 } 135 136 print "Started client with PID $$, hostname $host\n"; 137 138 my $message = ''; 139 my $current_port = ''; 140 my %active_servers = (); 141 142 do { 143 $got_job = 0; 144 foreach $current_server (keys %hosts_ports) { 145 foreach $current_port (keys %{$hosts_ports{$current_server}}) { 146 147 #before each "inactive" server/port connect - connect to each "active" server/port 148 next if (defined ${$active_servers{$current_server}}{$current_port}); 149 # "active" cycle 150 foreach my $active_server (keys %active_servers) { 151 foreach my $active_port (keys %{$active_servers{$active_server}}) { 152# print "Active: $active_server:$active_port\n"; 153 my $iaddr = inet_aton($active_server); 154 $paddr = sockaddr_in($active_port, $iaddr); 155 do { 156 my $server_is_active = 0; 157 $message = request_job($message, $active_server, $active_port); 158 $server_is_active++ if ($message); 159 if (!$server_is_active) { 160 delete ${$active_servers{$active_server}}{$active_port}; 161 # throw away obsolete environments 162 foreach (keys %environments) { 163 /^\d+@/; 164 if ($' eq "$active_server:$active_port") { 165 delete $environments{$_}; 166 }; 167 }; 168 }; 169 $message = '' if ($message eq 'No job'); 170 } while ($message); 171 }; 172 }; 173 174 # "inactive" cycle 175# print "Inactive: $current_server:$current_port\n"; 176 my $iaddr = inet_aton($current_server); 177 $paddr = sockaddr_in($current_port, $iaddr); 178 do { 179 $message = request_job($message, $current_server, $current_port); 180 if ($message) { 181 if (!defined $active_servers{$current_server}) { 182 my %ports; 183 $active_servers{$current_server} = \%ports; 184 }; 185 ${$active_servers{$current_server}}{$current_port}++; 186 }; 187 $message = '' if ($message eq 'No job'); 188 } while ($message); 189 }; 190 }; 191 sleep 5 if (!$got_job); 192 read_server_list(); 193 } while(1); 194}; 195 196sub usage { 197 my $error = shift; 198 print STDERR "\nbuild_client\n"; 199 print STDERR "Syntax: build_client [-PN] host1[:port1:...:portN] [host2[:port1:...:portN] ... hostN[:port1:...:portN]]|\@server_list_file\n"; 200 print STDERR " -P - start multiprocessing build, with number of processes passed\n"; 201 print STDERR "Example1: build_client myserver1 myserver2:7891:7892\n"; 202 print STDERR " the client will be asking for jobs on myserver1's default ports (7890-7894)\n"; 203 print STDERR " and on myserver2's ports 7891 and 7892\n"; 204 print STDERR "Example2: build_client -P2 myserver1:7990 myserver2\n"; 205 print STDERR " start 2 clients which will be asking for jobs myserver1's port 7990\n"; 206 print STDERR " and myserver2's default ports (7890-7894)\n"; 207 exit ($error); 208}; 209 210sub get_options { 211 my $arg; 212 usage(1) if (!scalar @ARGV); 213 while ($arg = shift @ARGV) { 214 usage(0) if /^--help$/; 215 usage(0) if /^-h$/; 216 $arg =~ /^-P(\d+)$/ and $processes_to_run = $1 and next; 217 $arg =~ /^-P$/ and $processes_to_run = shift @ARGV and next; 218 $arg =~ /^@(\S+)$/ and $server_list_file = $1 and next; 219 store_server($arg); 220 }; 221 if (($processes_to_run > 1) && (!$enable_multiprocessing)) { 222 print_error("Cannot load Win32::Process module for multiple client start"); 223 }; 224 if ($server_list_file) { 225 print_error("$server_list_file is not a regular file!!") if (!-f $server_list_file); 226 read_server_list(); 227 } 228 print_error("No server info") if (!scalar %hosts_ports); 229}; 230 231sub store_server { 232 my $server_string = shift; 233 my @server_params = (); 234 @server_params = split (/:/, $server_string); 235 my $host = shift @server_params; 236 my @names = gethostbyname($host); 237 my $host_full_name = $names[0]; 238 my %ports = (); 239 if (defined $hosts_ports{$host_full_name}) { 240 %ports = %{$hosts_ports{$host_full_name}}; 241 }; 242 # To do: implement keys in form server:port -> priority 243 if (defined $hosts_ports{$host_full_name}) { 244 if (!$server_list_time_stamp) { 245 print "The $host with ip address " . inet_ntoa(inet_aton($host)) . " is at least two times in the server list\n"; 246 }; 247 } else { 248 print "Added server $host as $host_full_name\n"; 249 }; 250 if (scalar @server_params) { 251 $ports{$_}++ foreach (@server_params); 252 } else { 253 $ports{$_}++ foreach ($default_port .. $default_port + 4); 254 }; 255 $hosts_ports{$host_full_name} = \%ports; 256}; 257 258sub read_server_list { 259 open(SERVER_LIST, "<$server_list_file") or return; 260 my $current_time_stamp = (stat($server_list_file))[9]; 261 return if ($server_list_time_stamp >= $current_time_stamp); 262 my @server_array = (); 263 foreach my $file_string(<SERVER_LIST>) { 264 while ($file_string =~ /(\S+)/) { 265 $file_string = $'; 266 store_server($1); 267 }; 268 }; 269 close SERVER_LIST; 270 $server_list_time_stamp = $current_time_stamp; 271}; 272 273sub request_job { 274 my ($message, $current_server, $current_port) = @_; 275 $message = "platform=$ENV_BACKUP{OUTPATH} pid=$$ osname=$^O" if (!$message); 276 # create the socket, connect to the port 277 socket(SOCKET, PF_INET, SOCK_STREAM, $proto) or die "socket: $!"; 278 connect(SOCKET, $paddr) or return '';#die "connect: $!"; 279 my $error_code = 1; 280 $message .= "\n"; 281 syswrite SOCKET, $message, length $message; 282 while (my $line = <SOCKET>) { 283 chomp $line; 284 if ($line eq 'No job') { 285 close SOCKET or die "close: $!"; 286 return $line; 287 }; 288 if ($line eq "Wrong platform") { 289 if (!defined $platform_rejects{$paddr}) { 290 $platform_rejects{$paddr}++; 291 print STDERR $line . "\n"; 292 } 293 close SOCKET or die "close: $!"; 294 delete $hosts_ports{$current_server}; 295 return ''; 296 } elsif (defined $platform_rejects{$paddr}) { 297 delete $platform_rejects{$paddr}; 298 }; 299 $got_job++; 300 $error_code = do_job($line . " server=$current_server port=$current_port"); 301 } 302 close SOCKET or die "close: $!"; 303 return("result=$error_code pid=$$"); 304} 305 306sub do_job { 307 my @job_parameters = split(/ /, shift); 308 my %job_hash = (); 309 my $last_param; 310 my $error_code; 311 print "Client $$@" . "$host\n"; 312 foreach (@job_parameters) { 313 if (/(=)/) { 314 $job_hash{$`} = $'; 315 $last_param = $`; 316 } else { 317 $job_hash{$last_param} .= " $_"; 318 }; 319 }; 320 $env_alias = $job_hash{server_pid} . '@' . $job_hash{server} . ':' . $job_hash{port}; 321 my $result = "1"; # default value 322 my $cmd_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 323 my $tmp_log_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 324 $job_temp_files{$tmp_log_file} = $job_hash{log}; 325 my $setenv_string = ''; 326 if (defined $job_hash{setenv_string}) { 327 # use configuration string from server 328 $setenv_string .= $job_hash{setenv_string}; 329 print "Environment: $setenv_string\n"; 330 331 my $directory = $job_hash{job_dir}; 332 open (COMMAND_FILE, ">$cmd_file"); 333 print COMMAND_FILE "$setenv_string\n"; 334 if (!defined $job_hash{job_dir}) { 335 close COMMAND_FILE; 336 print "No job_dir, cmd file: $cmd_file\n"; 337 foreach (keys %job_hash) { 338 print "key: $_ $job_hash{$_}\n"; 339 }; 340 exit (1); 341 }; 342 343 print COMMAND_FILE "pushd $job_hash{job_dir} && "; 344 print COMMAND_FILE $job_hash{job} ." >& $tmp_log_file\n"; 345 print COMMAND_FILE "exit \$?\n"; 346 close COMMAND_FILE; 347 $job_temp_files{$cmd_file} = 0; 348 $job_temp_files{$tmp_log_file} = $job_hash{log}; 349 $error_code = system($ENV{SHELL}, $cmd_file); 350 unlink $cmd_file or system("rm -rf $cmd_file"); 351 delete $job_temp_files{$cmd_file}; 352 } else { 353 # generate setsolar string 354 if (!defined $environments{$env_alias}) { 355 $error_code = get_setsolar_environment(\%job_hash); 356 return($error_code) if ($error_code); 357 }; 358 my $solar_vars = $environments{$env_alias}; 359 360 delete $ENV{$_} foreach (keys %ENV); 361 $ENV{$_} = $$solar_vars{$_} foreach (keys %$solar_vars); 362 print 'Workspace: '; 363 if (defined $ENV{CWS_WORK_STAMP}) { 364 print $ENV{CWS_WORK_STAMP}; 365 } else { 366 print $ENV{SOLARSRC}; 367 }; 368 369 print "\nplatform: $ENV{INPATH} $^O"; 370 print "\ndir: $job_hash{job_dir}\n"; 371 print "job: $job_hash{job}\n"; 372 chdir $job_hash{job_dir}; 373 getcwd(); 374 my $job_string = $job_hash{job} . ' > ' . $tmp_log_file . ' 2>&1'; 375 $error_code = system($job_string); 376# rename($tmp_log_file, $job_hash{log}) or system("mv", $tmp_log_file, $job_hash{log}); 377# delete $job_temp_files{$tmp_log_file};# = $job_hash{log}; 378 }; 379 rename($tmp_log_file, $job_hash{log}) or system("mv", $tmp_log_file, $job_hash{log}); 380 delete $job_temp_files{$tmp_log_file}; 381 382 if ($error_code) { 383 print "Error code = $error_code\n\n"; 384 } else { 385 print "Success!!\n\n"; 386 }; 387 return $error_code; 388}; 389 390sub get_setsolar_environment { 391 my $job_hash = shift; 392 my $server_pid = $$job_hash{server_pid}; 393 my $setsolar_string = $$job_hash{setsolar_cmd}; 394 # Prepare the string for the client 395 $setsolar_string =~ s/\s-file\s\S+//g; 396 my $error_code = 0; 397 my $cmd_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 398 my $tmp_log_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 399 if (defined $$job_hash{updater}) { 400 $ENV{UPDATER} = $$job_hash{updater}; 401 } else { 402 undef $ENV{UPDATER} if (defined $ENV{UPDATER}); 403 }; 404 if (defined $$job_hash{source_root}) { 405 $ENV{SOURCE_ROOT} = $$job_hash{source_root}; 406 } else { 407 undef $ENV{SOURCE_ROOT} if (defined $ENV{SOURCE_ROOT}); 408 }; 409 $error_code = system("$setsolar_string -file $cmd_file"); 410 store_env_hash($cmd_file); 411 return $error_code; 412}; 413 414sub print_error { 415 my $message = shift; 416 print STDERR "\nERROR: $message\n"; 417 exit(1); 418}; 419sub store_env_hash { 420 my $ss_setenv_file = shift;#($$job_hash{server_pid}.$$job_hash{setsolar_cmd}, $cmd_file); 421 my %solar_vars = (); 422 my $cmd_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 423 my $env_vars_file = File::Temp::tmpnam($ENV_BACKUP{TMP}); 424 print "$cmd_file $env_vars_file\n"; 425 #get all env variables in $env_vars_file 426 open (COMMAND_FILE, ">$cmd_file"); 427 print COMMAND_FILE "source $ss_setenv_file\n"; 428 print COMMAND_FILE "env > $env_vars_file\n"; 429 close COMMAND_FILE; 430 system($ENV{SHELL}, $cmd_file); 431 print_error($?) if ($?); 432 unlink $cmd_file or system("rm -rf $cmd_file"); 433 unlink $ss_setenv_file or system("rm -rf $ss_setenv_file"); 434 435 open SOLARTABLE, "<$env_vars_file" or die "can�t open solarfile $env_vars_file"; 436 while(<SOLARTABLE>) { 437 chomp; 438 s/\r\n//o; 439 /(=)/; 440 $solar_vars{$`} = $'; 441 }; 442 close SOLARTABLE; 443 unlink $env_vars_file or system("rm -rf $env_vars_file"); 444 $environments{$env_alias} = \%solar_vars; 445}; 446