Anthony Oliver wrote:
OK. I have tried that and here is the results in attached files. the file vmware-install.pl points to the file vmware-uninstall.pl do to protections on install.pl I am only sending you the referred to file. All this was done in ROOT and as ROOT.>From the shell(console) did you just try: sh vmware-install.pl make sure to run as root or if you are on a distribution like Ubuntu which doesn't have a root account you can use Sudo as well: sudo sh install.pl when prompted for password it's the same pword you used to login to that account.
I did a couple of changes to the file, as you can see I ran it three different times. The changes were on the first line and only deleting the "#!" in front of /usr/bin/perl -w line. The last time it was running for over 20 minutes with no results showing so I killed process, since halting it did not do anything. Any questions just ask.
--------Craig Kimmer -- ----- Blackholes are where God forgot and divided by ZERO!!!
Attachment:
errormessages.rtf
Description: RTF file
/usr/bin/perl -w
# If your copy of perl is not in /usr/bin, please adjust the line above.
#
# Copyright 1998 VMware, Inc. All rights reserved.
#
# Tar package manager for VMware
use strict;
# Constants
my $cInstallerFileName = 'vmware-install.pl';
my $cModuleUpdaterFileName = 'install.pl';
my $cInstallerDir = './installer';
my $cStartupFileName = $cInstallerDir . '/services.sh';
my $cRegistryDir = '/etc/vmware';
my $cInstallerMainDB = $cRegistryDir . '/locations';
my $cInstallerObject = $cRegistryDir . '/installer.sh';
my $cConfFlag = $cRegistryDir . '/not_configured';
my $gDefaultAuthdPort = 902;
my $cServices = '/etc/services';
my $cMarkerBegin = "# Beginning of the block added by the VMware software\n";
my $cMarkerEnd = "# End of the block added by the VMware software\n";
# External helper programs
my %gHelper;
# Has the uninstaller been installed?
my $gIsUninstallerInstalled;
# BEGINNING OF THE SECOND LIBRARY FUNCTIONS
# Global variables
my $gRegistryDir;
my $gStateDir;
my $gInstallerMainDB;
my $gInstallerObject;
my $gConfFlag;
my $gUninstallerFileName;
my $gConfigurator;
my %gDBAnswer;
my %gDBFile;
my %gDBDir;
my %gDBLink;
my %gDBMove;
# Load the installer database
sub db_load {
undef %gDBAnswer;
undef %gDBFile;
undef %gDBDir;
undef %gDBLink;
undef %gDBMove;
open(INSTALLDB, '<' . $gInstallerMainDB)
or error('Unable to open the installer database '
. $gInstallerMainDB . ' in read-mode.' . "\n\n");
while (<INSTALLDB>) {
chomp;
if (/^answer (\S+) (.+)$/) {
$gDBAnswer{$1} = $2;
} elsif (/^answer (\S+)/) {
$gDBAnswer{$1} = '';
} elsif (/^remove_answer (\S+)/) {
delete $gDBAnswer{$1};
} elsif (/^file (.+) (\d+)$/) {
$gDBFile{$1} = $2;
} elsif (/^file (.+)$/) {
$gDBFile{$1} = 0;
} elsif (/^remove_file (.+)$/) {
delete $gDBFile{$1};
} elsif (/^directory (.+)$/) {
$gDBDir{$1} = '';
} elsif (/^remove_directory (.+)$/) {
delete $gDBDir{$1};
} elsif (/^link (\S+) (\S+)/) {
$gDBLink{$2} = $1;
} elsif (/^move (\S+) (\S+)/) {
$gDBMove{$2} = $1;
}
}
close(INSTALLDB);
}
# Open the database on disk in append mode
sub db_append {
if (not open(INSTALLDB, '>>' . $gInstallerMainDB)) {
error('Unable to open the installer database ' . $gInstallerMainDB . ' in append-mode.' . "\n\n");
}
# Force a flush after every write operation.
# See 'Programming Perl', p. 110
select((select(INSTALLDB), $| = 1)[0]);
}
# Add a file to the tar installer database
# flags:
# 0x1 write time stamp
sub db_add_file {
my $file = shift;
my $flags = shift;
if ($flags & 0x1) {
my @statbuf;
@statbuf = stat($file);
if (not (defined($statbuf[9]))) {
error('Unable to get the last modification timestamp of the destination file ' . $file . '.' . "\n\n");
}
$gDBFile{$file} = $statbuf[9];
print INSTALLDB 'file ' . $file . ' ' . $statbuf[9] . "\n";
} else {
$gDBFile{$file} = 0;
print INSTALLDB 'file ' . $file . "\n";
}
}
# Remove a file from the tar installer database
sub db_remove_file {
my $file = shift;
print INSTALLDB 'remove_file ' . $file . "\n";
delete $gDBFile{$file};
}
# Remove a directory from the tar installer database
sub db_remove_dir {
my $dir = shift;
print INSTALLDB 'remove_directory ' . $dir . "\n";
delete $gDBDir{$dir};
}
# Determine if a file belongs to the tar installer database
sub db_file_in {
my $file = shift;
return defined($gDBFile{$file});
}
# Determine if a directory belongs to the tar installer database
sub db_dir_in {
my $dir = shift;
return defined($gDBDir{$dir});
}
# Return the timestamp of an installed file
sub db_file_ts {
my $file = shift;
return $gDBFile{$file};
}
# Add a directory to the tar installer database
sub db_add_dir {
my $dir = shift;
$gDBDir{$dir} = '';
print INSTALLDB 'directory ' . $dir . "\n";
}
# Remove an answer from the tar installer database
sub db_remove_answer {
my $id = shift;
if (defined($gDBAnswer{$id})) {
print INSTALLDB 'remove_answer ' . $id . "\n";
delete $gDBAnswer{$id};
}
}
# Add an answer to the tar installer database
sub db_add_answer {
my $id = shift;
my $value = shift;
db_remove_answer($id);
$gDBAnswer{$id} = $value;
print INSTALLDB 'answer ' . $id . ' ' . $value . "\n";
}
# Retrieve an answer that must be present in the database
sub db_get_answer {
my $id = shift;
if (not defined($gDBAnswer{$id})) {
error('Unable to find the answer ' . $id . ' in the installer database ('
. $gInstallerMainDB . '). You may want to re-install '
. vmware_product_name() . "." . "\n\n");
}
return $gDBAnswer{$id};
}
# Retrieves an answer if it exists in the database, else returns undef;
sub db_get_answer_if_exists {
my $id = shift;
if (not defined($gDBAnswer{$id})) {
return undef;
}
if ($gDBAnswer{$id} eq '') {
return undef;
}
return $gDBAnswer{$id};
}
# Save the tar installer database
sub db_save {
close(INSTALLDB);
}
# END OF THE SECOND LIBRARY FUNCTIONS
# BEGINNING OF THE LIBRARY FUNCTIONS
# Constants
my $cTerminalLineSize = 80;
# Global variables
my %gOption;
my %gAnswerSize;
my %gCheckAnswerFct;
# Tell if the user is the super user
sub is_root {
return $> == 0;
}
# Wordwrap system: append some content to the output
sub append_output {
my $output = shift;
my $pos = shift;
my $append = shift;
$output .= $append;
$pos += length($append);
if ($pos >= $cTerminalLineSize) {
$output .= "\n";
$pos = 0;
}
return ($output, $pos);
}
# Wordwrap system: deal with the next character
sub wrap_one_char {
my $output = shift;
my $pos = shift;
my $word = shift;
my $char = shift;
my $reserved = shift;
my $length;
if (not (($char eq "\n") || ($char eq ' ') || ($char eq ''))) {
$word .= $char;
return ($output, $pos, $word);
}
# We found a separator. Process the last word
$length = length($word) + $reserved;
if (($pos + $length) > $cTerminalLineSize) {
# The last word doesn't fit in the end of the line. Break the line before it
$output .= "\n";
$pos = 0;
}
($output, $pos) = append_output($output, $pos, $word);
$word = '';
if ($char eq "\n") {
$output .= "\n";
$pos = 0;
} elsif ($char eq ' ') {
if ($pos) {
($output, $pos) = append_output($output, $pos, ' ');
}
}
return ($output, $pos, $word);
}
# Wordwrap system: word-wrap a string plus some reserved trailing space
sub wrap {
my $input = shift;
my $reserved = shift;
my $output;
my $pos;
my $word;
my $i;
$output = '';
$pos = 0;
$word = '';
for ($i = 0; $i < length($input); $i++) {
($output, $pos, $word) = wrap_one_char($output, $pos, $word, substr($input, $i, 1), 0);
}
# Use an artifical last '' separator to process the last word
($output, $pos, $word) = wrap_one_char($output, $pos, $word, '', $reserved);
return $output;
}
# Print an error message and exit
sub error {
my $msg = shift;
print STDERR wrap($msg . 'Execution aborted.' . "\n\n", 0);
exit 1;
}
# Convert a string to its equivalent shell representation
sub shell_string {
my $single_quoted = shift;
$single_quoted =~ s/'/'"'"'/g;
# This comment is a fix for emacs's broken syntax-highlighting code --hpreg
return '\'' . $single_quoted . '\'';
}
# Contrary to a popular belief, 'which' is not always a shell builtin command.
# So we can not trust it to determine the location of other binaries.
# Moreover, SuSE 6.1's 'which' is unable to handle program names beginning with
# a '/'...
#
# Return value is the complete path if found, or '' if not found
sub internal_which {
my $bin = shift;
if (substr($bin, 0, 1) eq '/') {
# Absolute name
if ((-f $bin) && (-x $bin)) {
return $bin;
}
} else {
# Relative name
my @paths;
my $path;
if (index($bin, '/') == -1) {
# There is no other '/' in the name
@paths = split(':', $ENV{'PATH'});
foreach $path (@paths) {
my $fullbin;
$fullbin = $path . '/' . $bin;
if ((-f $fullbin) && (-x $fullbin)) {
return $fullbin;
}
}
}
}
return '';
}
# Remove leading and trailing whitespaces
sub remove_whitespaces {
my $string = shift;
$string =~ s/^\s*//;
$string =~ s/\s*$//;
return $string;
}
# Ask a question to the user and propose an optional default value
# Use this when you don't care about the validity of the answer
sub query {
my $message = shift;
my $defaultreply = shift;
my $reserved = shift;
my $reply;
# Reserve some room for the reply
print wrap($message . (($defaultreply eq '') ? '' : (' [' . $defaultreply . ']')), 1 + $reserved);
# This is what the 1 is for
print ' ';
if ($gOption{'default'} == 1) {
# Simulate the enter key
print "\n";
$reply = '';
} else {
chop($reply = <STDIN>);
}
print "\n";
$reply = remove_whitespaces($reply);
if ($reply eq '') {
$reply = $defaultreply;
}
return $reply;
}
# Check the validity of an answer whose type is yesno
# Return a clean answer if valid, or ''
sub check_answer_binpath {
my $answer = shift;
my $source = shift;
if (not (internal_which($answer) eq '')) {
return $answer;
}
if ($source eq 'user') {
print wrap('The answer "' . $answer . '" is invalid. It must be the complete name of a binary file.' . "\n\n", 0);
}
return '';
}
$gAnswerSize{'binpath'} = 20;
$gCheckAnswerFct{'binpath'} = \&check_answer_binpath;
# Prompts the user if a binary is not found
# Return value is:
# '': the binary has not been found
# the binary name if it has been found
sub DoesBinaryExist_Prompt {
my $bin = shift;
my $answer;
$answer = check_answer_binpath($bin, 'default');
if (not ($answer eq '')) {
return $answer;
}
if (get_answer('Setup is unable to find the "' . $bin . '" program on your machine. Please make sure it is installed. Do you want to specify the location of this program by hand?', 'yesno', 'yes') eq 'no') {
return '';
}
return get_answer('What is the location of the "' . $bin . '" program on your machine?', 'binpath', '');
}
# Execute the command passed as an argument
# _without_ interpolating variables (Perl does it by default)
sub direct_command {
return `$_[0]`;
}
# chmod() that reports errors
sub safe_chmod {
my $mode = shift;
my $file = shift;
if (chmod($mode, $file) != 1) {
error('Unable to change the access rights of the file ' . $file . '.' . "\n\n");
}
}
# Emulate a simplified ls program for directories
sub internal_ls {
my $dir = shift;
my @fn;
opendir(LS, $dir);
@fn = grep(!/^\.\.?$/, readdir(LS));
closedir(LS);
return @fn;
}
# Install a file permission
sub install_permission {
my $src = shift;
my $dst = shift;
my @statbuf;
@statbuf = stat($src);
if (not (defined($statbuf[2]))) {
error('Unable to get the access rights of source file "' . $src . '".' . "\n\n");
}
safe_chmod($statbuf[2] & 07777, $dst);
}
# Emulate a simplified sed program
# Return 1 if success, 0 if failure
# XXX as a side effect, if the string being replaced is '', remove
# the entire line. Remove this, once we have better "block handling" of
# our config data in config files.
sub internal_sed {
my $src = shift;
my $dst = shift;
my $append = shift;
my $patchRef = shift;
my @patchKeys;
if (not open(SRC, '<' . $src)) {
return 0;
}
if (not open(DST, (($append == 1) ? '>>' : '>') . $dst)) {
return 0;
}
@patchKeys = keys(%$patchRef);
if ($#patchKeys == -1) {
while(defined($_ = <SRC>)) {
print DST $_;
}
} else {
while(defined($_ = <SRC>)) {
my $patchKey;
my $del = 0;
foreach $patchKey (@patchKeys) {
if (s/$patchKey/$$patchRef{$patchKey}/g) {
if ($_ eq "\n") {
$del = 1;
}
}
}
next if ($del);
print DST $_;
}
}
close(SRC);
close(DST);
return 1;
}
# Check if a file name exists
sub file_name_exist {
my $file = shift;
# Note: We must test for -l before, because if an existing symlink points to
# a non-existing file, -e will be false
return ((-l $file) || (-e $file))
}
# Check if a file name already exists and prompt the user
# Return 0 if the file can be written safely, 1 otherwise
sub file_check_exist {
my $file = shift;
if (not file_name_exist($file)) {
return 0;
}
# The default must make sure that the product will be correctly installed
# We give the user the choice so that a sysadmin can perform a normal
# install on a NFS server and then answer 'no' NFS clients
return (get_answer('The file ' . $file . ' that this program was about to '
. 'install already exists. Overwrite?',
'yesno', 'yes') eq 'yes') ? 0 : 1;
}
# Install one file
# flags are forwarded to db_add_file()
sub install_file {
my $src = shift;
my $dst = shift;
my $patchRef = shift;
my $flags = shift;
uninstall_file($dst);
if (file_check_exist($dst)) {
return;
}
# The file could be a symlink to another location. Remove it
unlink($dst);
if (not internal_sed($src, $dst, 0, $patchRef)) {
error('Unable to copy the source file ' . $src . ' to the destination file ' . $dst . '.' . "\n\n");
}
db_add_file($dst, $flags);
install_permission($src, $dst);
}
# mkdir() that reports errors
sub safe_mkdir {
my $file = shift;
if (mkdir($file, 0000) == 0) {
error('Unable to create the directory ' . $file . '.' . "\n\n");
}
}
# Remove trailing slashes in a dir path
sub dir_remove_trailing_slashes {
my $path = shift;
for(;;) {
my $len;
my $pos;
$len = length($path);
if ($len < 2) {
# Could be '/' or any other character. Ok.
return $path;
}
$pos = rindex($path, '/');
if ($pos != $len - 1) {
# No trailing slash
return $path;
}
# Remove the trailing slash
$path = substr($path, 0, $len - 1)
}
}
# Emulate a simplified dirname program
sub internal_dirname {
my $path = shift;
my $pos;
$path = dir_remove_trailing_slashes($path);
$pos = rindex($path, '/');
if ($pos == -1) {
# No slash
return '.';
}
if ($pos == 0) {
# The only slash is at the beginning
return '/';
}
return substr($path, 0, $pos);
}
# Create a hierarchy of directories with permission 0755
# flags:
# 0x1 write this directory creation in the installer database
# Return 1 if the directory existed before
sub create_dir {
my $dir = shift;
my $flags = shift;
if (-d $dir) {
return 1;
}
if (index($dir, '/') != -1) {
create_dir(internal_dirname($dir), $flags);
}
safe_mkdir($dir);
if ($flags & 0x1) {
db_add_dir($dir);
}
safe_chmod(0755, $dir);
return 0;
}
# Get a valid non-persistent answer to a question
# Use this when the answer shouldn't be stored in the database
sub get_answer {
my $msg = shift;
my $type = shift;
my $default = shift;
my $answer;
if (not defined($gAnswerSize{$type})) {
die 'get_answer(): type ' . $type . ' not implemented :(' . "\n\n";
}
for (;;) {
$answer = check_answer(query($msg, $default, $gAnswerSize{$type}), $type, 'user');
if (not ($answer eq '')) {
return $answer;
}
}
}
# Get a valid persistent answer to a question
# Use this when you want an answer to be stored in the database
sub get_persistent_answer {
my $msg = shift;
my $id = shift;
my $type = shift;
my $default = shift;
my $answer;
if (defined($gDBAnswer{$id})) {
# There is a previous answer in the database
$answer = check_answer($gDBAnswer{$id}, $type, 'db');
if (not ($answer eq '')) {
# The previous answer is valid. Make it the default value
$default = $answer;
}
}
$answer = get_answer($msg, $type, $default);
db_add_answer($id, $answer);
return $answer;
}
# Find a suitable backup name and backup a file
sub backup_file {
my $file = shift;
my $i;
for ($i = 0; $i < 100; $i++) {
if (not file_name_exist($file . '.old.' . $i)) {
my %patch;
undef %patch;
if (internal_sed($file, $file . '.old.' . $i, 0, \%patch)) {
print wrap('File ' . $file . ' is backed up to ' . $file .
'.old.' . $i . '.' . "\n\n", 0);
} else {
print STDERR wrap('Unable to backup the file ' . $file .
' to ' . $file . '.old.' . $i .'.' . "\n\n", 0);
}
return;
}
}
print STDERR wrap('Unable to backup the file ' . $file .
'. You have too many backups files. They are files of the form ' .
$file . '.old.N, where N is a number. Please delete some of them.' . "\n\n", 0);
}
# Uninstall a file previously installed by us
sub uninstall_file {
my $file = shift;
if (not db_file_in($file)) {
# Not installed by this program
return;
}
if (file_name_exist($file)) {
if (db_file_ts($file)) {
my @statbuf;
@statbuf = stat($file);
if (defined($statbuf[9])) {
if (db_file_ts($file) != $statbuf[9]) {
# Modified since this program installed it
backup_file($file);
}
} else {
print STDERR wrap('Unable to get the last modification timestamp of the file ' .
$file . '.' . "\n\n", 0);
}
}
if (not unlink($file)) {
print STDERR wrap('Unable to remove the file ' . $file . '.' . "\n\n", 0);
}
} else {
print wrap('This program previously created the file ' . $file
. ', and was about to remove it. Somebody else apparently did '
. 'it already.' . "\n\n", 0);
}
db_remove_file($file);
}
# Uninstall a directory previously installed by us
sub uninstall_dir {
my $dir = shift;
if (not db_dir_in($dir)) {
# Not installed by this program
return;
}
if (-d $dir) {
if (not rmdir($dir)) {
print wrap('This program previously created the directory ' . $dir
. ', and was about to remove it. Since there are files in '
. 'that directory that this program did not create, it will '
. 'not be removed.' . "\n\n", 0);
if ( defined($ENV{'VMWARE_DEBUG'})
&& ($ENV{'VMWARE_DEBUG'} eq 'yes')) {
system('ls -AlR ' . shell_string($dir));
}
}
} else {
print wrap('This program previously created the directory ' . $dir
. ', and was about to remove it. Somebody else apparently did '
. 'it already.' . "\n\n", 0);
}
db_remove_dir($dir);
}
# Return the version of VMware
sub vmware_version {
my $buildNr;
$buildNr = 'e.x.p build-11608';
return remove_whitespaces($buildNr);
}
# Check the validity of an answer whose type is yesno
# Return a clean answer if valid, or ''
sub check_answer_yesno {
my $answer = shift;
my $source = shift;
if (lc($answer) =~ /^y(es)?$/) {
return 'yes';
}
if (lc($answer) =~ /^n(o)?$/) {
return 'no';
}
if ($source eq 'user') {
print wrap('The answer "' . $answer . '" is invalid. It must be one of "y" or "n".' . "\n\n", 0);
}
return '';
}
$gAnswerSize{'yesno'} = 3;
$gCheckAnswerFct{'yesno'} = \&check_answer_yesno;
# Check the validity of an answer based on its type
# Return a clean answer if valid, or ''
sub check_answer {
my $answer = shift;
my $type = shift;
my $source = shift;
if (not defined($gCheckAnswerFct{$type})) {
die 'check_answer(): type ' . $type . ' not implemented :(' . "\n\n";
}
return &{$gCheckAnswerFct{$type}}($answer, $source);
}
# END OF THE LIBRARY FUNCTIONS
# BEGINNING_OF_TMPDIR_DOT_PL
#!/usr/bin/perl
use strict;
# Create a temporary directory
#
# They are a lot of small utility programs to create temporary files in a
# secure way, but none of them is standard. So I wrote this --hpreg
sub make_tmp_dir {
my $prefix = shift;
my $tmp;
my $serial;
my $loop;
$tmp = defined($ENV{'TMPDIR'}) ? $ENV{'TMPDIR'} : '/tmp';
# Don't overwrite existing user data
# -> Create a directory with a name that didn't exist before
#
# This may never succeed (if we are racing with a malicious process), but at
# least it is secure
$serial = 0;
for (;;) {
# Check the validity of the temporary directory. We do this in the loop
# because it can change over time
if (not (-d $tmp)) {
error('"' . $tmp . '" is not a directory.' . "\n\n");
}
if (not ((-w $tmp) && (-x $tmp))) {
error('"' . $tmp . '" should be writable and executable.' . "\n\n");
}
# Be secure
# -> Don't give write access to other users (so that they can not use this
# directory to launch a symlink attack)
if (mkdir($tmp . '/' . $prefix . $serial, 0755)) {
last;
}
$serial++;
if ($serial % 200 == 0) {
print STDERR 'Warning: The "' . $tmp . '" directory may be under attack.' . "\n\n";
}
}
return $tmp . '/' . $prefix . $serial;
}
# END_OF_TMPDIR_DOT_PL
# Append a clearly delimited block to an unstructured text file --hpreg
# Result:
# 1 on success
# -1 on failure
sub block_append {
my $file = shift;
my $begin = shift;
my $block = shift;
my $end = shift;
if (not open(BLOCK, '>>' . $file)) {
return -1;
}
print BLOCK $begin . $block . $end;
if (not close(BLOCK)) {
return -1;
}
return 1;
}
# Remove all clearly delimited blocks from an unstructured text file --hpreg
# Result:
# >= 0 number of blocks removed on success
# -1 on failure
sub block_remove {
my $src = shift;
my $dst = shift;
my $begin = shift;
my $end = shift;
my $count;
my $state;
if (not open(SRC, '<' . $src)) {
return -1;
}
if (not open(DST, '>' . $dst)) {
close(SRC);
return -1;
}
$count = 0;
$state = 'outside';
while (<SRC>) {
if ($state eq 'outside') {
if ($_ eq $begin) {
$state = 'inside';
$count++;
} else {
print DST $_;
}
} elsif ($state eq 'inside') {
if ($_ eq $end) {
$state = 'outside';
}
}
}
if (not close(DST)) {
close(SRC);
return -1;
}
if (not close(SRC)) {
return -1;
}
return $count;
}
# Emulate a simplified basename program
sub internal_basename {
return substr($_[0], rindex($_[0], '/') + 1);
}
# Set the name of the main /etc/vmware* directory.
sub initialize_globals {
if (vmware_product() eq 'console') {
$gRegistryDir = '/etc/vmware-console';
$gUninstallerFileName = 'vmware-uninstall-console.pl';
$gConfigurator = 'vmware-config-console.pl';
} elsif (vmware_product() eq 'api') {
$gRegistryDir = '/etc/vmware-api';
$gUninstallerFileName = 'vmware-uninstall-api.pl';
$gConfigurator = 'vmware-config-api.pl';
} elsif (vmware_product() eq 'mui') {
$gRegistryDir = '/etc/vmware-mui';
$gUninstallerFileName = 'vmware-uninstall-mui.pl';
$gConfigurator = 'vmware-config-mui.pl';
} elsif (vmware_product() eq 'tools-for-linux' ||
vmware_product() eq 'tools-for-freebsd') {
$gRegistryDir = '/etc/vmware-tools';
$gUninstallerFileName = 'vmware-uninstall-tools.pl';
$gConfigurator = 'vmware-config-tools.pl';
} else {
$gRegistryDir = '/etc/vmware';
$gUninstallerFileName = 'vmware-uninstall.pl';
$gConfigurator = 'vmware-config.pl';
}
$gStateDir = $gRegistryDir . '/state';
$gInstallerMainDB = $gRegistryDir . '/locations';
$gInstallerObject = $gRegistryDir . '/installer.sh';
$gConfFlag = $gRegistryDir . '/not_configured';
$gOption{'default'} = 0;
$gOption{'eula_agreed'} = 0;
}
# Set up the location of external helpers
sub initialize_external_helpers {
my $program;
my @programList;
if (not defined($gHelper{'more'})) {
$gHelper{'more'} = '';
if (defined($ENV{'PAGER'})) {
my @tokens;
# The environment variable sometimes contains the pager name _followed by
# a few command line options_.
#
# Isolate the program name (we are certain it does not contain a
# whitespace) before dealing with it.
@tokens = split(' ', $ENV{'PAGER'});
$tokens[0] = DoesBinaryExist_Prompt($tokens[0]);
if (not ($tokens[0] eq '')) {
$gHelper{'more'} = join(' ', @tokens); # This is _already_ a shell string
}
}
if ($gHelper{'more'} eq '') {
$gHelper{'more'} = DoesBinaryExist_Prompt('more');
if ($gHelper{'more'} eq '') {
error('Unable to continue.' . "\n\n");
}
$gHelper{'more'} = shell_string($gHelper{'more'}); # Save it as a shell string
}
}
if (vmware_product() eq 'tools-for-freebsd') {
@programList = ('tar', 'sed', 'rm', 'killall', 'kldstat', 'umount', 'mv');
} else {
@programList = ('tar', 'sed', 'rm', 'killall', 'lsmod', 'umount', 'mv');
}
foreach $program (@programList) {
if (not defined($gHelper{$program})) {
$gHelper{$program} = DoesBinaryExist_Prompt($program);
if ($gHelper{$program} eq '') {
error('Unable to continue.' . "\n\n");
}
}
}
$gHelper{'insserv'} = internal_which('insserv');
}
# Check the validity of an answer whose type is dirpath
# Return a clean answer if valid, or ''
sub check_answer_dirpath {
my $answer = shift;
my $source = shift;
$answer = dir_remove_trailing_slashes($answer);
if (substr($answer, 0, 1) ne '/') {
print wrap('The path "' . $answer . '" is a relative path. Please enter '
. 'an absolute path.' . "\n\n", 0);
return '';
}
if (-d $answer) {
# The path is an existing directory
return $answer;
}
# The path is not a directory
if (file_name_exist($answer)) {
if ($source eq 'user') {
print wrap('The path "' . $answer . '" exists, but is not a directory.'
. "\n\n", 0);
}
return '';
}
# The path does not exist
if ($source eq 'user') {
return (get_answer('The path "' . $answer . '" does not exist currently. '
. 'This program is going to create it, including needed '
. 'parent directories. Is this what you want?',
'yesno', 'yes') eq 'yes') ? $answer : '';
} else {
return $answer;
}
}
$gAnswerSize{'dirpath'} = 20;
$gCheckAnswerFct{'dirpath'} = \&check_answer_dirpath;
# Check the validity of an answer whose type is initdirpath
# Return a clean answer if valid, or ''
sub check_answer_initdirpath {
my $answer = shift;
my $source = shift;
my $testdir;
$answer = dir_remove_trailing_slashes($answer);
if (not (-d $answer)) {
if ($source eq 'user') {
print wrap('The path "' . $answer . '" is not an existing directory.' . "\n\n", 0);
}
return '';
}
foreach $testdir ('rc0.d', 'rc1.d', 'rc2.d', 'rc3.d', 'rc4.d', 'rc5.d', 'rc6.d') {
if (not (-d $answer . '/' . $testdir)) {
if ($source eq 'user') {
print wrap('The path "' . $answer . '" is a directory which does not contain a ' .
$testdir . ' directory.' . "\n\n", 0);
}
return '';
}
}
return $answer;
}
$gAnswerSize{'initdirpath'} = 15;
$gCheckAnswerFct{'initdirpath'} = \&check_answer_initdirpath;
# Check the validity of an answer whose type is initscriptsdirpath
# Return a clean answer if valid, or ''
sub check_answer_initscriptsdirpath {
my $answer = shift;
my $source = shift;
$answer = dir_remove_trailing_slashes($answer);
if (not (-d $answer)) {
if ($source eq 'user') {
print wrap('The path "' . $answer . '" is not an existing directory.' . "\n\n", 0);
}
return '';
}
return $answer;
}
$gAnswerSize{'initscriptsdirpath'} = 15;
$gCheckAnswerFct{'initscriptsdirpath'} = \&check_answer_initscriptsdirpath;
# Check the validity of an answer whose type is authdport
# Return a clean answer if valid, or ''
sub check_answer_authdport {
my $answer = shift;
my $source = shift;
if (($answer =~ /^\d+$/) && ($answer > 0) && ($answer < 65536)) {
return $answer;
}
if ($source eq 'user') {
print wrap('The answer '. $answer . ' is invalid. Please enter a valid '
. 'port number in the range 1 to 65535.' . "\n\n", 0);
}
return '';
}
$gAnswerSize{'authdport'} = 5;
$gCheckAnswerFct{'authdport'} = \&check_answer_authdport;
# Install one directory (recursively)
sub install_dir {
my $src_dir = shift;
my $dst_dir = shift;
my $patchRef = shift;
my $file;
if (create_dir($dst_dir, 0x1)) {
my @statbuf;
@statbuf = stat($dst_dir);
if (not (defined($statbuf[2]))) {
error('Unable to get the access rights of destination directory "' . $dst_dir . '".' . "\n\n");
}
# Was bug 15880 --hpreg
if ( ($statbuf[2] & 0555) != 0555
&& get_answer('Current access permissions on directory "' . $dst_dir
. '" will prevent some users from using '
. vmware_product_name()
. '. Do you want to set those permissions properly?',
'yesno', 'yes') eq 'yes') {
safe_chmod(($statbuf[2] & 07777) | 0555, $dst_dir);
}
} else {
install_permission($src_dir, $dst_dir);
}
foreach $file (internal_ls($src_dir)) {
if (-d $src_dir . '/' . $file) {
install_dir($src_dir . '/' . $file, $dst_dir . '/' . $file, $patchRef);
} else {
install_file($src_dir . '/' . $file, $dst_dir . '/' . $file, $patchRef, 0x1);
}
}
}
# Display the end-user license agreement
sub show_EULA {
if ((not defined($gDBAnswer{'EULA_AGREED'}))
|| (db_get_answer('EULA_AGREED') eq 'no')) {
query('You must read and accept the End User License Agreement to continue.' .
"\n" . 'Press enter to display it.', '', 0);
# $gHelper{'more'} is already a shell string
system($gHelper{'more'} . ' ./doc/EULA');
print "\n";
# Make sure there is no default answer here
if (get_answer('Do you accept? (yes/no)', 'yesno', '') eq 'no') {
print wrap('Please try again when you are ready to accept.' . "\n\n", 0);
exit 0;
}
print wrap('Thank you.' . "\n\n", 0);
}
}
# XXX This code is mostly duplicated from the main server installer. -jhu
sub build_perl_api {
my $control;
my $build_dir;
my $program;
my $cTmpDirPrefix = 'api-config';
foreach $program ('tar', 'perl', 'make', 'touch') {
if (not defined($gHelper{$program})) {
$gHelper{$program} = DoesBinaryExist_Prompt($program);
if ($gHelper{$program} eq '') {
error('Unable to continue.' . "\n\n");
}
}
}
print wrap('Installing the VMware VmPerl Scripting API.' . "\n", 0);
$control = './control.tar';
if (not (file_name_exist($control))) {
error('Unable to find the VMware VmPerl Scripting API. '
. 'You may want to re-install ' . vmware_product_name()
. '.' . "\n\n");
}
$build_dir = make_tmp_dir($cTmpDirPrefix);
if (system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($build_dir) . ' -xopf ' .
shell_string($control))) {
print wrap('Unable to untar the "' . $control . '" file in the "' . $build_dir .
'" directory.' . "\n\n", 0);
error('');
}
if (system('cd ' . shell_string($build_dir . '/control-only') . ' && ' .
shell_string($gHelper{'perl'}) . ' Makefile.PL > make.log 2>&1')) {
print wrap('Unable to create the VMware VmPerl Scripting API makefile.' . "\n\n", 0);
# Look for the header files needed to build the Perl module. If we don't
# find them, suggest to the user how they can install the files. -jhu
if (open(PERLINC, shell_string($gHelper{'perl'}) . ' -MExtUtils::Embed ' .
'-e perl_inc |')) {
my $inc = <PERLINC>;
close(PERLINC);
$inc =~ s/\s*-I//;
if (not file_name_exist($inc . '/perl.h')) {
print wrap('Could not find necessary components to build the '
. 'VMware VmPerl Scripting API. Look in your Linux '
. 'distribution to see if there is a perl-devel package. '
. 'Install that package if it exists and then re-run this '
. 'installation program.' . "\n\n", 0);
}
}
return(perl_config_fail($build_dir));
}
print wrap("\n", 0);
print wrap('Building the VMware VmPerl Scripting API.' . "\n\n", 0);
# Make sure we have a compiler available
if (get_cc() eq '') {
print wrap('Unable to install the VMware VmPerl Scripting API.', 0);
print wrap('A C compiler is required to install the API.' . "\n\n", 0);
remove_tmp_dir($build_dir);
return;
}
# We touch all our files in case the system clock is set to the past. Make will get confused and
# delete our shipped .o file(s).
# More code duplication from pkg_mgr.pl (really, really bad)
system(shell_string($gHelper{'touch'}) . ' '
. shell_string($build_dir . '/control-only') . '/* >>'
. shell_string($build_dir . '/control-only') . '/make.log 2>&1');
if (system(shell_string($gHelper{'make'}) . ' -C '
. shell_string($build_dir . '/control-only') . ' '
. shell_string('CC=' . $gHelper{'gcc'}) . ' '
. ' >>' . shell_string($build_dir . '/control-only') . '/make.log 2>&1')) {
print wrap('Unable to compile the VMware VmPerl Scripting API.' . "\n\n", 0);
return(perl_config_fail($build_dir));
}
print wrap("Installing the VMware VmPerl Scripting API.\n\n", 0);
# XXX This is deeply broken: we let a third party tool install a file without
# adding it to our installer database. This file will never get
# uninstalled by our uninstaller --hpreg
if (system(shell_string($gHelper{'make'}) . ' -C '
. shell_string($build_dir . '/control-only') . ' '
. shell_string('CC=' . $gHelper{'gcc'}) . ' '
. ' install >>' . shell_string($build_dir . '/control-only')
. '/make.log 2>&1')) {
print wrap('Unable to install the VMware VmPerl Scripting API.' . "\n\n", 0);
return(perl_config_fail($build_dir));
}
print wrap('The installation of the VMware VmPerl Scripting API succeeded.' . "\n\n", 0);
remove_tmp_dir($build_dir);
}
# XXX Mostly duplicated from the main server installer. -jhu
# Common error message when we can't compile or install our perl modules
sub perl_config_fail {
my $dir = shift;
print wrap('********' . "\n". 'The VMware VmPerl Scripting API was not '
. 'installed. Errors encountered during compilation and '
. 'installation of the module can be found here: ' . $dir
. "\n\n" . 'You will not be able to use the "vmware-cmd" '
. 'program.' . "\n\n" . 'Errors can be found in the log file: '
. shell_string($dir . '/control-only/make.log')
. "\n" . '********' . "\n\n", 0);
error('');
}
# Handle the installation and configuration of vmware's perl module
sub install_perl_api {
my $rootdir;
my $answer;
my $mandir;
my $docdir;
my %patch;
undef %patch;
install_dir('./etc', $gRegistryDir, \%patch);
$rootdir = '/usr';
$answer = get_persistent_answer('In which directory do you want to install the executable files?',
'BINDIR', 'dirpath', $rootdir . '/bin');
undef %patch;
install_dir('./bin', $answer, \%patch);
$gIsUninstallerInstalled = 1;
$rootdir = internal_dirname($answer);
# Don't display a double slash (was bug 14109) --hpreg
if ($rootdir eq '/') {
$rootdir = '';
}
# We don't use get_persistent_answer() here because once the user has
# selected the root directory, we can give him better default answers than
# his/her previous answers.
$answer = get_answer('In which directory do you want to install the library files?',
'dirpath', $rootdir . '/lib/vmware-api');
db_add_answer('LIBDIR', $answer);
undef %patch;
install_dir('./lib', $answer, \%patch);
$docdir = $rootdir . '/share/doc';
if (not (-d $docdir)) {
$docdir = $rootdir . '/doc';
}
$answer = get_answer('In which directory do you want to install the documentation files?'
, 'dirpath', $docdir . '/vmware-api');
db_add_answer('DOCDIR', $answer);
undef %patch;
install_dir('./doc', $answer, \%patch);
build_perl_api();
}
sub vmware_guestd_app_name {
return db_get_answer('SBINDIR') . '/vmware-guestd';
}
# Install the content of the tools tar package
sub install_content_tools {
my $rootdir;
my $answer;
my %patch;
my $mandir;
my $docdir;
undef %patch;
install_dir('./etc', $gRegistryDir, \%patch);
if(vmware_product() eq 'tools-for-freebsd') {
$rootdir = '/usr/local';
} else {
$rootdir = '/usr';
}
$answer = get_persistent_answer('In which directory do you want to '
. 'install the binary files?', 'BINDIR',
'dirpath', $rootdir . '/bin');
undef %patch;
install_dir('./bin', $answer, \%patch);
$rootdir = internal_dirname($answer);
# Don't display a double slash (was bug 14109) --hpreg
if ($rootdir eq '/') {
$rootdir = '';
}
# Finds the location of the initscripts dir
$answer = get_initscriptsdir();
# install the service script.
if (vmware_product() eq 'tools-for-freebsd') {
$answer = get_answer('In which directory do you want to install the '
. 'startup script?', 'dirpath', $answer);
create_dir($answer,0);
}
undef %patch;
install_file($cStartupFileName,
$answer . (vmware_product() eq 'tools-for-freebsd' ?
'/vmware-tools.sh' : '/vmware-tools'), \%patch, 0x1);
$gIsUninstallerInstalled = 1;
# We don't use get_persistent_answer() here because once the user has
# selected the root directory, we can give him better default answers than
# his/her previous answers.
$answer = get_answer('In which directory do you want to install '
. 'the daemon files?', 'dirpath', $rootdir . '/sbin');
db_add_answer('SBINDIR', $answer);
undef %patch;
install_dir('./sbin', $answer, \%patch);
$answer = get_answer('In which directory do you want to install '
. 'the library files?', 'dirpath', $rootdir
. '/lib/vmware-tools');
db_add_answer('LIBDIR', $answer);
undef %patch;
install_dir('./lib', $answer, \%patch);
$docdir = $rootdir . '/share/doc';
if (not (-d $docdir)) {
$docdir = $rootdir . '/doc';
}
$answer = get_answer('In which directory do you want to install the '
. 'documentation files?', 'dirpath', $docdir
. '/vmware-tools');
db_add_answer('DOCDIR', $answer);
undef %patch;
install_dir('./doc', $answer, \%patch);
#
# Make sure the tools image is unmounted so that the tools media
# disconnection can go ahead smoothly.
#
{
my $path;
my @pathToArch = ('cdrom', 'mnt', 'mnt/cdrom');
foreach $path (@pathToArch) {
if (file_name_exist('/' . $path . '/vmware-linux-tools.tar.gz')) {
print wrap('Unmounting the Tools ISO image ' . $path . " .\n", 0);
system(shell_string($gHelper{'umount'}) . ' /' . $path
. ' > /dev/null 2>&1');
}
}
}
#
# Now that everything is correctly setup, tell VMware that it can remove the
# tool installation CD image
#
# Note: The trailing space is for backward compatibility with VMware
# pre-wgs-beta2
system(shell_string(vmware_guestd_app_name())
. ' --cmd ' . shell_string('toolinstall.end ')
. ' 2>&1 > /dev/null');
}
sub uninstall_content_old_tools {
my $OldInstallerDB = '/etc/vmware-tools/tools_log';
my $OldInstallerDBOld = '/etc/vmware/tools_log';
my $TmpMainDB = $gInstallerMainDB;
my $File;
my @Files;
my $MovedFile;
my $LinkedFile;
my $answer;
my $runlevel;
# This is necessary for old installations of the tools
# when /etc/vmware was one and unique dump for all the products
if (-e $OldInstallerDBOld) {
$OldInstallerDB = $OldInstallerDBOld;
}
if (!-e $OldInstallerDB) {
# Old tools database not found, assume that the system is clean.
return;
}
# Swap the db with the old one temporarely.
$gInstallerMainDB = $OldInstallerDB;
db_load();
if (not open(INSTALLDB, '>>' . $gInstallerMainDB)) {
error('Unable to open the tar installer database ' . $gInstallerMainDB
. ' in write-mode.' . "\n\n");
}
$answer = get_answer('An old installation of the tools is detected. '
. 'Should this installation be removed ?',
'yesno', 'yes');
if ($answer eq 'no') {
error('');
}
# Stop the services
foreach $File (keys %gDBFile) {
if ($File =~ /\S+\/dualconf$/) {
system(shell_string($File) . ' stop');
print "\n";
last;
}
}
# Remove the files
foreach $File (keys %gDBFile) {
if ($File !~ /\/tmp\S+/) {
uninstall_file($File);
}
}
# Remove the links
foreach $LinkedFile (keys %gDBLink) {
unlink $LinkedFile;
}
# At last, replace the original files.
foreach $MovedFile (keys %gDBMove) {
# XXX we do not have a timestamp for those files so we can't
# know if the user changed it, so I back it up.
if (-e $gDBMove{$MovedFile}) {
backup_file($gDBMove{$MovedFile});
unlink $gDBMove{$MovedFile};
if ($MovedFile =~ /\S+\.org/) {
rename $MovedFile, $gDBMove{$MovedFile};
} else {
backup_file($MovedFile);
unlink $MovedFile;
}
}
}
# Clean up the broken links.
foreach $File (qw(/etc/modules.conf /etc/conf.modules /etc/XF86Config
/etc/X11/XF86Config /etc/X11/XF86Config-4)) {
if ((-l $File) && (-e ($File . '.org'))) {
unlink $File;
rename $File . '.org', $File;
}
}
get_initscriptsdir();
$Files[0] = db_get_answer('INITSCRIPTSDIR') . '/vmmemctl';
foreach $runlevel ('0', '1', '2', '3', '4', '5', '6', 'S', 's') {
$Files[$#Files + 1] = db_get_answer('INITDIR') . '/rc' . $runlevel
. '.d/S99vmmemctl';
}
# Cleanup the files that aren't mentionned in the install database.
foreach $File (@Files) {
if (file_name_exist($File)) {
unlink $File;
}
}
db_save();
unlink $gInstallerMainDB;
if (direct_command('LANG=C ' .
shell_string(vmware_product() eq 'tools-for-freebsd' ?
$gHelper{'kldstat'} : $gHelper{'lsmod'})) =~
/vmmemctl/) {
print wrap('The uninstallation of the old tools completed. '
. 'Please restart this virtual machine to ensure that '
. 'all the loaded components are removed from the memory and '
. 'run this installer again to continue with the upgrade.'
. "\n\n", 0);
exit 0;
}
# Restore the original database file name in case we don't have
# to reboot because of the loaded vmmemctl.
$gInstallerMainDB = $TmpMainDB;
}
# Install the content of the WGS client tar package
sub install_content_console {
my $rootdir;
my $answer;
my %patch;
my $mandir;
my $docdir;
undef %patch;
install_dir('./etc', $gRegistryDir, \%patch);
$rootdir = '/usr';
$answer = get_persistent_answer('In which directory do you want to install the binary files?', 'BINDIR', 'dirpath', $rootdir . '/bin');
undef %patch;
install_dir('./bin', $answer, \%patch);
$gIsUninstallerInstalled = 1;
$rootdir = internal_dirname($answer);
# Don't display a double slash (was bug 14109) --hpreg
if ($rootdir eq '/') {
$rootdir = '';
}
# We don't use get_persistent_answer() here because once the user has
# selected the root directory, we can give him better default answers than
# his/her previous answers.
$answer = get_answer('In which directory do you want to install the library files?', 'dirpath', $rootdir . '/lib/vmware-console');
db_add_answer('LIBDIR', $answer);
undef %patch;
install_dir('./lib', $answer, \%patch);
$mandir = $rootdir . '/share/man';
if (not (-d $mandir)) {
$mandir = $rootdir . '/man';
}
$answer = get_answer('In which directory do you want to install the manual files?', 'dirpath', $mandir);
db_add_answer('MANDIR', $answer);
undef %patch;
install_dir('./man', $answer, \%patch);
$docdir = $rootdir . '/share/doc';
if (not (-d $docdir)) {
$docdir = $rootdir . '/doc';
}
$answer = get_answer('In which directory do you want to install the documentation files?', 'dirpath', $docdir . '/vmware-console');
db_add_answer('DOCDIR', $answer);
undef %patch;
install_dir('./doc', $answer, \%patch);
}
# Return GSX or ESX for server products, Workstation for ws
sub installed_vmware_version {
my $vmware_version;
my $vmware_version_string;
if (not defined($gHelper{"vmware"})) {
$gHelper{"vmware"} = DoesBinaryExist_Prompt("vmware");
if ($gHelper{"vmware"} eq '') {
error('Unable to continue.' . "\n\n");
}
}
$vmware_version_string = direct_command(shell_string($gHelper{"vmware"})
. ' -v 2>&1 < /dev/null');
if ($vmware_version_string =~ /.*VMware\s*(\S+)\s*Server.*/) {
$vmware_version = $1;
} else {
$vmware_version = "Workstation";
}
return $vmware_version;
}
# Install the mui package
sub install_content_mui {
my $rootdir;
my $answer;
my %patch;
my $program;
my $vmware_version;
my $mui_dir = "./mui";
my $docdir;
# Find the programs we need to go ahead with the install
foreach $program ('vmware', 'hostname', 'tar', 'rm', 'cp', 'rmdir') {
if (not defined($gHelper{$program})) {
$gHelper{$program} = DoesBinaryExist_Prompt($program);
if ($gHelper{$program} eq '') {
error('Unable to continue.' . "\n\n");
}
}
}
$vmware_version = installed_vmware_version();
# Force use of the RPM if this is ESX
if ($vmware_version eq "ESX") {
error('VMware ESX Server requires that the ' . vmware_product_name() .
' be installed via RPM' . "\n\n");
}
# Make sure GSX is installed
if ($vmware_version ne "GSX") {
error('VMware GSX Server must be installed on this machine for the ' .
vmware_product_name() . ' to work'
. "\n\n");
}
# remove install made by old installer
removeExistingInstall();
# Install the uninstaller
undef %patch;
install_dir('./etc', $gRegistryDir, \%patch);
$rootdir = '/usr';
$answer = get_persistent_answer('In which directory do you want to install '
. 'the binary files?', 'BINDIR', 'dirpath',
$rootdir . '/bin');
undef %patch;
install_dir( './bin' , $answer, \%patch);
# Finds the location of the initscripts dir
get_initscriptsdir();
$rootdir = '/usr/lib/vmware-mui';
db_add_answer('INSTALLDIR', $rootdir);
$gIsUninstallerInstalled = 1;
# Find whether this is an install of gsx or esx
$vmware_version = installed_vmware_version();
$rootdir = '/home/vmware/mui';
$answer = get_persistent_answer('In which directory do you want to install '
. 'the ' . vmware_product_name(). ' files?',
'INSTALLDIR', 'dirpath', $rootdir);
$rootdir = $answer;
# Install the mui package to the right place
undef %patch;
install_dir($mui_dir, $rootdir, \%patch);
# Install the console distrib package
undef %patch;
install_dir('./console-distrib', $rootdir . '/apache/htdocs/vmware/bin'
, \%patch);
# Install the documentation
$docdir = $rootdir . '/share/doc';
if (not (-d $docdir)) {
$docdir = $rootdir . '/doc';
}
$answer = get_answer('In which directory would you like to install the '
. 'documentation files?', 'dirpath', $docdir);
db_add_answer('DOCDIR', $answer);
undef %patch;
install_dir('./doc', $answer, \%patch);
}
#BEGIN UNINSTALLER SECTION
# Uninstaller section for old style MUI installer: Most of this code is
# directly copied over from the old installer
my %gConfData;
# Read the config vars to our internal array
sub readConfig {
my $registryFile = shift;
if (open(OLDCONFIG, $registryFile)) {
# Populate our array with everthing from the conf file.
while (<OLDCONFIG>) {
m/^\s*(\S*)\s*=\s*(\S*)/;
$gConfData{$1} = $2;
}
close(OLDCONFIG);
return(1);
}
return(0);
}
# Remove our files at a very high level
sub uninstallAllFiles {
my $key;
my @killFiles = (
"EULA.txt",
"VMware",
"apache",
"bin",
"include",
"lib",
"man",
"ssl",
);
my %rCLinks = (
"rc3.d/S91httpd.vmware", "httpd.vmware",
"rc4.d/S91httpd.vmware", "httpd.vmware",
"rc5.d/S91httpd.vmware", "httpd.vmware",
"rc3.d/K07httpd.vmware", "httpd.vmware",
"rc4.d/K07httpd.vmware", "httpd.vmware",
"rc5.d/K07httpd.vmware", "httpd.vmware",
);
print wrap('Removing the old installation....' . "\n" , 0);
# Remove our init.d symlinks and files
foreach $key (keys %rCLinks ) {
system(shell_string($gHelper{'rm'}). ' -f '
. shell_string("$gConfData{'mui.initd.fullpath'}/../$key"));
system(shell_string($gHelper{'rm'}). ' -f '
. shell_string("$gConfData{'mui.initd.fullpath'}/$key"));
system(shell_string($gHelper{'rm'}). ' -f '
. shell_string("$gConfData{'mui.initd.fullpath'}/$rCLinks{$key}"));
}
# Remove our MUI directories and files
foreach $key (@killFiles) {
system(shell_string($gHelper{'rm'}) . ' -rf '
. shell_string("$gConfData{'mui.fullpath'}/$key"));
}
system(shell_string($gHelper{'rmdir'}) . ' '
. shell_string("$gConfData{'mui.fullpath'}") .' > /dev/null 2>&1');
# Remove secuity-config.pl
system(shell_string($gHelper{'rm'}) . ' -f '
. shell_string("$gConfData{'security.fullpath'}"));
return(1);
}
#
# check to see if this is a certificate that was generated
# by this program (or the mui). If so, then it is safe to delete
# it. (don't want to accidently blow away an expensive certificate).
#
sub certSafeToDelete {
my $instDir = shift;
my $certLoc = "/etc/vmware-mui/ssl";
my $certUniqIdent = "(564d7761726520496e632e)";
local *F;
if (not open(F, "$instDir/bin/openssl x509 -in $certLoc/mui.crt " .
" -noout -subject" . '|')) {
return 1;
}
while (<F>) {
if (m/$certUniqIdent/) {
return 1;
}
}
close (F);
#Certificate didn't have our uniq identifier, so don't delete it.
return 0;
}
# See if we've installed already and nuke it if found.
sub removeExistingInstall {
my $instDir;
my $key;
my $registryDir = "/etc/vmware-mui";
my $registryFile = "$registryDir/config";
my $readSuccess;
if (-e "$registryDir") {
# Populate our array with the data from the conf file.
$readSuccess = readConfig($registryFile);
if ($readSuccess) {
$instDir = $gConfData{'mui.fullpath'};
# Warn them if we can't figure out where thier old install is.
if (not -e $instDir) {
print wrap('You seem to have a previous installation of '
. vmware_product_name() . ' but the installer '
. 'cant find where it is. You might want to '
. 'remove your old installation by hand.' . "\n", 0);
return;
}
stop_mui($instDir);
if (!certSafeToDelete($instDir)) {
print wrap('The SSL certificate in ' . "$registryDir " . 'doesn\'t appear'
. ' to have been generated by ' . vmware_product_name()
. '. Not deleting files in ' . "$registryDir"
. ' as a precaution.' . "\n" , 0);
} else {
# We cant just delete the entire $registryDir directory since it
# will now contain our locations file that we created to hold the
# new install database
system(shell_string($gHelper{'rm'}) . ' -rf '
. shell_string($registryDir . '/ssl'));
system(shell_string($gHelper{'rm'}) . ' -rf '
. shell_string($registryDir . '/config'));
# Since this directory existed due to the old install, we need
# to add it to our database to make it be deleted properly on
# uninstall
db_add_dir($registryDir, 0x1);
}
uninstallAllFiles();
return(1);
}
}
return(0);
}
# END UNINSTALLER SECTION
# Install the content of the tar package
sub install_content {
my $rootdir;
my $answer;
my %patch;
my $mandir;
my $docdir;
my $initdir;
my $initscriptsdir;
undef %patch;
install_dir('./etc', $gRegistryDir, \%patch);
$rootdir = '/usr';
$answer = get_persistent_answer('In which directory do you want to install the binary files?',
'BINDIR', 'dirpath', $rootdir . '/bin');
undef %patch;
install_dir('./bin', $answer, \%patch);
#
# Install the startup script (and make the old installer aware of this one)
#
undef %patch;
install_file($cStartupFileName,
get_initscriptsdir() . '/vmware', \%patch, 0x1);
$gIsUninstallerInstalled = 1;
# Setuid root
safe_chmod(04555, $answer . '/vmware-ping');
$rootdir = internal_dirname($answer);
# Don't display a double slash (was bug 14109) --hpreg
if ($rootdir eq '/') {
$rootdir = '';
}
# We don't use get_persistent_answer() here because once the user has
# selected the root directory, we can give him better default answers than
# his/her previous answers.
if (vmware_product() eq 'wgs') {
$answer = get_answer('In which directory do you want to install '
. 'the daemon files?', 'dirpath', $rootdir . '/sbin');
db_add_answer('SBINDIR', $answer);
undef %patch;
install_dir('./sbin', $answer, \%patch);
# Setuid root
safe_chmod(04555, $answer . '/vmware-authd');
}
$answer = get_answer('In which directory do you want to install the library files?',
'dirpath', $rootdir . '/lib/vmware');
db_add_answer('LIBDIR', $answer);
undef %patch;
install_dir('./lib', $answer, \%patch);
# Setuid root
safe_chmod(04555, $answer . '/bin/vmware-vmx');
safe_chmod(04555, $answer . '/bin-debug/vmware-vmx');
$mandir = $rootdir . '/share/man';
if (not (-d $mandir)) {
$mandir = $rootdir . '/man';
}
$answer = get_answer('In which directory do you want to install the manual files?',
'dirpath', $mandir);
db_add_answer('MANDIR', $answer);
undef %patch;
install_dir('./man', $answer, \%patch);
$docdir = $rootdir . '/share/doc';
if (not (-d $docdir)) {
$docdir = $rootdir . '/doc';
}
$answer = get_answer('In which directory do you want to install the documentation files?',
'dirpath', $docdir . '/vmware');
db_add_answer('DOCDIR', $answer);
undef %patch;
install_dir('./doc', $answer, \%patch);
}
sub get_initscriptsdir {
my $initdir;
my $initscriptsdir;
my $answer;
if (vmware_product() eq 'tools-for-freebsd') {
$initdir = '/usr/local/etc/rc.d';
$initscriptsdir = '/usr/local/etc/rc.d';
db_add_answer('INITDIR', $initdir);
db_add_answer('INITSCRIPTSDIR', $initscriptsdir);
return $initscriptsdir;
}
# The "SuSE version >= 7.1" way
$initdir = '/etc/init.d';
if (check_answer_initdirpath($initdir, 'default') eq '') {
# The "SuSE version < 7.1" way
$initdir = '/sbin/init.d';
if (check_answer_initdirpath($initdir, 'default') eq '') {
# The "RedHat" way
$initdir = '/etc/rc.d';
if (check_answer_initdirpath($initdir, 'default') eq '') {
# The "Debian" way
$initdir = '/etc';
if (check_answer_initdirpath($initdir, 'default') eq '') {
$initdir = '';
}
}
}
}
$answer = get_persistent_answer('What is the directory that contains the init'
.' directories (rc0.d/ to rc6.d/)?'
, 'INITDIR', 'initdirpath', $initdir);
# The usual way
$initscriptsdir = $answer . '/init.d';
if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
# The "SuSE version >= 7.1" way
$initscriptsdir = $answer;
if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
$initscriptsdir = '';
}
}
$answer = get_persistent_answer('What is the directory that contains the init'
.' scripts?', 'INITSCRIPTSDIR'
, 'initscriptsdirpath', $initscriptsdir);
return $answer;
}
# Install a tar package or upgrade an already installed tar package
sub install_or_upgrade {
print wrap('Installing the content of the package.' . "\n\n", 0);
if (vmware_product() eq 'console') {
install_content_console();
} elsif (vmware_product() eq 'api') {
install_perl_api();
} elsif (vmware_product() eq 'mui') {
install_content_mui();
} elsif (vmware_product() eq 'tools-for-linux' ||
vmware_product() eq 'tools-for-freebsd') {
install_content_tools();
} else {
install_content();
}
print wrap('The installation of ' . vmware_longname()
. ' completed successfully. '
. 'You can decide to remove this software from your system at any '
. 'time by invoking the following command: "'
. db_get_answer('BINDIR') . '/' . $gUninstallerFileName . '".'
. "\n\n", 0);
}
# Uninstall files and directories beginning with a given prefix
sub uninstall_prefix {
my $prefix = shift;
my $prefix_len;
my $file;
my $dir;
$prefix_len = length($prefix);
# Remove all files beginning with $prefix
foreach $file (keys %gDBFile) {
if (substr($file, 0, $prefix_len) eq $prefix) {
uninstall_file($file);
}
}
# Remove all directories beginning with $prefix
# We sort them by decreasing order of their length, to ensure that we will
# remove the inner ones before the outer ones
foreach $dir (sort {length($b) <=> length($a)} keys %gDBDir) {
if (substr($dir, 0, $prefix_len) eq $prefix) {
uninstall_dir($dir);
}
}
}
# Uninstall a tar package
sub uninstall {
my $service_name = shift;
if (defined($gDBAnswer{'INITSCRIPTSDIR'})
&& db_file_in(db_get_answer('INITSCRIPTSDIR') . $service_name)) {
# The installation process ran far enough to create the startup script
my $status;
# In case service links were created the LSB way, remove them
if (not ($gHelper{'insserv'} eq '')) {
system(shell_string($gHelper{'insserv'}) . ' -r '
. shell_string(db_get_answer('INITSCRIPTSDIR') . $service_name));
}
# Stop the services
$status = system(shell_string(db_get_answer('INITSCRIPTSDIR')
. $service_name) . ' stop') >> 8;
if ($status) {
if ($status == 2) {
# At least one instance of VMware is still running. We must refuse to
# uninstall
error('Unable to stop ' . vmware_product_name()
. '\'s services. Aborting the uninstallation.' . "\n\n");
}
# Oh well, at worst the user will have to reboot the machine... The
# uninstallation process should go as far as possible
print STDERR wrap('Unable to stop ' . vmware_product_name()
. '\'s services.' . "\n\n", 0);
} else {
print "\n";
}
}
uninstall_prefix('');
}
# Return the specific VMware product
sub vmware_product {
return 'ws';
}
# this is a function instead of a macro in the off chance that product_name
# will one day contain a language-specific escape character. (ask hpreg)
sub vmware_product_name {
return 'VMware Workstation';
}
# Stop any currently running instance of the mui
sub stop_mui {
my $installDir = shift;
if (-e "$installDir/apache/bin") {
system(shell_string($installDir) . '/apache/bin/apachectl stop > /dev/null 2>&1');
} else {
# Maybe the install didnt get this far! We will ignore it
print wrap('Couldnt find a running instance of Apache.' . "\n\n", 0);
}
}
# Delete the mui log files that were created once the mui started running
sub clear_mui_logs {
my $installDir = db_get_answer('INSTALLDIR');
if (-e "$installDir/apache/logs") {
system(shell_string($gHelper{'rm'}) . ' -f ' . "$installDir/apache/logs/*");
}
}
# Return product name and version
sub vmware_longname {
my $name = vmware_product_name() . ' ' . vmware_version();
if (not (vmware_product() eq 'server')) {
$name .= (vmware_product() eq 'tools-for-freebsd') ?
' for Free BSD' : ' for Linux';
}
return $name;
}
# If this was a WGS build, remove our inetd.conf entry for auth daemon
# and stop the vmware-serverd
sub wgs_uninstall {
system(shell_string($gHelper{'killall'}) . ' -TERM vmware-serverd >/dev/null 2>&1');
uninstall_superserver();
}
# Try and figure out which "superserver" is installed and unconfigure correct
# one.
sub uninstall_superserver {
my $inetd_conf = "/etc/inetd.conf";
my $xinetd_dir = "/etc/xinetd.d";
# check for xinetd
# XXX Could be a problem, as they could start xinetd with '-f config_file'.
# We could do a ps -ax, look for xinetd, parse the line, find the config
# file, parse the config file to find the xinet.d directory. Or parse if
# from the init.d script somewhere. If they use init.d.
if ( -d $xinetd_dir ) {
uninstall_xinetd($xinetd_dir);
}
# check for inetd
if ( -e $inetd_conf ) {
uninstall_inetd($inetd_conf);
}
}
# Restart the inetd service
sub restart_inetd {
my $inetd_restart = db_get_answer('INITSCRIPTSDIR') . '/inetd';
if (-e $inetd_restart) {
if (!system(shell_string($inetd_restart) . ' restart')) {
return;
}
}
system(shell_string($gHelper{'killall'}) . ' -HUP inetd');
}
# Cleanup the inetd.conf file.
sub uninstall_inetd {
my $inetd = shift;
my %patch = ('^# VMware auth.*$' => '',
'^.*stream\s+tcp\s+nowait.*vmauthd.*$' => '',
'^.*stream\s+tcp\s+nowait.*vmware-authd.*$' => '');
my $tmp_dir = make_tmp_dir('vmware-installer');
# Build the temp file's path
my $tmp = $tmp_dir . '/tmp';
# XXX Use the block_*() API instead, like we do for $cServices. --hpreg
internal_sed($inetd, $tmp, 0, \%patch);
undef %patch;
if (not internal_sed($tmp, $inetd, 0, \%patch)) {
print STDERR wrap('Unable to copy file ' . $tmp . ' back to ' . $inetd
. '.' . "\n" . 'The authentication daemon was not removed from '
. $inetd . "\n\n", 0);
}
remove_tmp_dir($tmp_dir);
restart_inetd();
}
#Restart xinetd
sub restart_xinetd {
my $xinetd_restart = db_get_answer('INITSCRIPTSDIR') . '/xinetd';
if (-e $xinetd_restart) {
if (!system(shell_string($xinetd_restart) . ' restart')) {
return;
}
}
system(shell_string($gHelper{'killall'}) . ' -USR2 xinetd');
}
# Cleanup the xinetd.d directory.
sub uninstall_xinetd {
my $conf_dir = shift;
my $tmp_dir;
my $tmp;
# XXX What the heck is that? Why isn't this file registered with the
# installer's database, and automatically removed? --hpreg
unlink($conf_dir . '/vmware-authd');
# Unregister the IP service. --hpreg
$tmp_dir = make_tmp_dir('vmware-installer');
$tmp = $tmp_dir . '/tmp';
if (block_remove($cServices, $tmp, $cMarkerBegin, $cMarkerEnd) >= 0) {
system(shell_string($gHelper{'mv'}) . ' -f ' . shell_string($tmp) . ' '
. shell_string($cServices));
}
remove_tmp_dir($tmp_dir);
restart_xinetd();
}
# Display a usage error message for the install program and exit
sub install_usage {
print STDERR wrap(vmware_longname() . ' installer' . "\n" . 'Usage: ' . $0
. ' [[-][-]d[efault]]' . "\n"
. ' default: Automatically answer questions with the '
. 'proposed answer.' . "\n\n", 0);
exit 1;
}
# Remove a temporary directory
sub remove_tmp_dir {
my $dir = shift;
if (system(shell_string($gHelper{'rm'}) . ' -rf ' . shell_string($dir))) {
error('Unable to remove the temporary directory ' . $dir . '.' . "\n\n");
};
}
# ARGH! More code duplication from pkg_mgr.pl
# We really need to have some kind of include system
sub get_cc {
$gHelper{'gcc'} = '';
if (defined($ENV{'CC'}) && (not ($ENV{'CC'} eq ''))) {
$gHelper{'gcc'} = internal_which($ENV{'CC'});
if ($gHelper{'gcc'} eq '') {
print wrap('Unable to find the compiler specified in the CC environnment variable: "'
. $ENV{'CC'} . '".' . "\n\n");
}
}
if ($gHelper{'gcc'} eq '') {
$gHelper{'gcc'} = internal_which('gcc');
if ($gHelper{'gcc'} eq '') {
$gHelper{'gcc'} = internal_which('egcs');
if ($gHelper{'gcc'} eq '') {
$gHelper{'gcc'} = internal_which('kgcc');
if ($gHelper{'gcc'} eq '') {
$gHelper{'gcc'} = DoesBinaryExist_Prompt('gcc');
}
}
}
}
print wrap('Using compiler "' . $gHelper{'gcc'}
. '". Use environment variable CC to override.' . "\n\n", 0);
return $gHelper{'gcc'};
}
# Make sure we have an initial database suitable for this installer. The goal
# is to encapsulates all the compatibilty issues in this (consequently ugly)
# function
sub get_initial_database {
my $made_dir1;
my $made_dir2;
my $bkp_dir;
my $bkp;
my $kind;
my $version;
my $intermediate_format;
my $status;
my $state_file;
my $state_files;
if (not (-e $gInstallerMainDB)) {
# This is the first installation. Create the installer database from
# scratch
print wrap('Creating a new installer database using the tar3 format.' . "\n\n", 0);
$made_dir1 = 0;
if (not (-d $gRegistryDir)) {
safe_mkdir($gRegistryDir);
$made_dir1 = 1;
}
safe_chmod(0755, $gRegistryDir);
if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
if ($made_dir1) {
rmdir($gRegistryDir);
}
error('Unable to open the tar installer database ' . $gInstallerMainDB
. ' in write-mode.' . "\n\n");
}
# Force a flush after every write operation.
# See 'Programming Perl', p. 110
select((select(INSTALLDB), $| = 1)[0]);
if ($made_dir1) {
db_add_dir($gRegistryDir);
}
# This file is going to be modified after its creation by this program.
# Do not timestamp it
db_add_file($gInstallerMainDB, 0);
return;
}
print wrap('A previous installation of VMware software has been detected.' . "\n\n", 0);
#
# Convert the previous installer database to our format and backup it
# Uninstall the previous installation
#
$bkp_dir = make_tmp_dir('vmware-installer');
$bkp = $bkp_dir . '/prev_db.tar.gz';
if (-x $gInstallerObject) {
$kind = direct_command(shell_string($gInstallerObject) . ' kind');
chop($kind);
if (system(shell_string($gInstallerObject) . ' version >/dev/null 2>&1')) {
# No version method -> this is version 1
$version = '1';
} else {
$version = direct_command(shell_string($gInstallerObject) . ' version');
chop($version);
}
print wrap('The previous installation was made by the ' . $kind
. ' installer (version ' . $version . ').' . "\n\n", 0);
if ($version < 2) {
# The best database format those installers know is tar. We will have to
# upgrade the format
$intermediate_format = 'tar';
} elsif ($version == 2) {
# Those installers at least know about the tar2 database format. We won't
# have to do much
$intermediate_format='tar2'
} else {
# Those installers at least know about the tar3 database format. We won't
# have to do anything
$intermediate_format = 'tar3';
}
system(shell_string($gInstallerObject) . ' convertdb '
. shell_string($intermediate_format) . ' ' . shell_string($bkp));
# Uninstall the previous installation
$status = system(shell_string($gInstallerObject) . ' uninstall');
# Beware, beyond this point, $gInstallerObject does not exist
# anymore.
} else {
# No installer object -> this is the old installer, which we don't support
# anymore.
$status = 1;
}
if ($status) {
remove_tmp_dir($bkp_dir);
error('Failure' . "\n\n");
}
# Create the directory structure to welcome the restored database
$made_dir1 = 0;
if (not (-d $gRegistryDir)) {
safe_mkdir($gRegistryDir);
$made_dir1 = 1;
}
safe_chmod(0755, $gRegistryDir);
$made_dir2 = 0;
if ($version >= 2) {
if (not (-d $gStateDir)) {
safe_mkdir($gStateDir);
$made_dir2 = 1;
}
safe_chmod(0755, $gStateDir);
}
# Some versions of tar (1.13.17+ are ok) do not untar directory permissions
# as described in their documentation (they overwrite permissions of
# existing, non-empty directories with permissions stored in the archive)
#
# Because we didn't know about that at the beginning, the previous
# uninstallation may have included the directory structure in their database
# backup.
#
# To avoid that, we must re-package the database backup
system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
. ' -xzopf ' . shell_string($bkp));
$state_files = '';
if (-d $bkp_dir . $gStateDir) {
foreach $state_file (internal_ls($bkp_dir . $gStateDir)) {
$state_files .= ' ' . shell_string('.' . $gStateDir . '/'. $state_file);
}
}
$bkp = $bkp_dir . '/prev_db2.tar.gz';
system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
. ' -czopf ' . shell_string($bkp) . ' '
. shell_string('.' . $gInstallerMainDB) . $state_files);
# Restore the database ready to be used by our installer
system(shell_string($gHelper{'tar'}) . ' -C / -xzopf ' . shell_string($bkp));
remove_tmp_dir($bkp_dir);
if ($version < 2) {
print wrap('Converting the ' . $intermediate_format
. ' installer database format to the tar3 installer database format.'
. "\n\n", 0);
# Upgrade the database format: keep only the 'answer' statements, and add a
# 'file' statement for the main database file
my $id;
db_load();
if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
error('Unable to open the tar installer database ' . $gInstallerMainDB
. ' in write-mode.' . "\n\n");
}
db_add_file($gInstallerMainDB, 0);
foreach $id (keys %gDBAnswer) {
print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
}
db_save();
} elsif( $version == 2 ) {
print wrap('Converting the ' . $intermediate_format
. ' installer database format to the tar3 installer database format.'
. "\n\n", 0);
# Upgrade the database format: keep only the 'answer' statements, and add a
# 'file' statement for the main database file
my $id;
db_load();
if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
error('Unable to open the tar installer database ' . $gInstallerMainDB
. ' in write-mode.' . "\n\n");
}
db_add_file($gInstallerMainDB, 0);
foreach $id (keys %gDBAnswer) {
# For the rpm3|tar3 format, a number of keywords were removed. In their
# place a more flexible scheme was implemented for which each has a semantic
# equivalent:
#
# VNET_SAMBA -> VNET_1_SAMBA
# VNET_SAMBA_MACHINESID -> VNET_1_SAMBA_MACHINESID
# VNET_SAMBA_SMBPASSWD -> VNET_1_SAMBA_SMBPASSWD
# VNET_HOSTONLY -> VNET_1_HOSTONLY
# VNET_HOSTONLY_HOSTADDR -> VNET_1_HOSTONLY_HOSTADDR
# VNET_HOSTONLY_NETMASK -> VNET_1_HOSTONLY_NETMASK
# VNET_INTERFACE -> VNET_0_INTERFACE
my $newid = $id;
if ($id eq 'VNET_SAMBA') {
$newid='VNET_1_SAMBA';
} elsif ($id eq 'VNET_SAMBA_MACHINESID') {
$newid='VNET_1_SAMBA_MACHINESID';
} elsif ($id eq 'VNET_SAMBA_SMBPASSWD') {
$newid='VNET_1_SAMBA_SMBPASSWD';
} elsif ("$id" eq 'VNET_HOSTONLY') {
$newid='VNET_1_HOSTONLY';
} elsif ("$id" eq 'VNET_HOSTONLY_HOSTADDR') {
$newid='VNET_1_HOSTONLY_HOSTADDR';
} elsif ("$id" eq 'VNET_HOSTONLY_NETMASK') {
$newid='VNET_1_HOSTONLY_NETMASK';
} elsif ("$id" eq 'VNET_INTERFACE') {
$newid='VNET_0_INTERFACE';
}
print INSTALLDB 'answer ' . $newid . ' ' . $gDBAnswer{$id} . "\n";
}
db_save();
}
db_load();
db_append();
if ($made_dir1) {
db_add_dir($gRegistryDir);
}
if ($made_dir2) {
db_add_dir($gStateDir);
}
}
# SIGINT handler
sub sigint_handler {
my $signame = shift;
if ($gIsUninstallerInstalled == 0) {
print STDERR wrap("\n\n" . 'Ignoring attempt to kill the installer with Control-C, because the uninstaller has not been installed yet. Please use the Control-Z / fg combination instead.' . "\n\n", 0);
return;
}
error('');
}
# Write the VMware host-wide configuration file - only if console
sub write_vmware_config {
my $name;
$name = $gRegistryDir . '/config';
uninstall_file($name);
if (file_check_exist($name)) {
return;
}
# The file could be a symlink to another location. Remove it
unlink($name);
open(CONFIGFILE, '>' . $name) or error('Unable to open the configuration file '
. $name . ' in write-mode.' . "\n\n");
db_add_file($name, 0x1);
safe_chmod(0444, $name);
print CONFIGFILE 'libdir = "' . db_get_answer('LIBDIR') . '"' . "\n";
close(CONFIGFILE);
}
# Get the installed version of VMware
# Return the version if found, or ''
sub get_installed_version() {
my $backslash;
my $dollar;
my $pattern;
my $version;
my $nameTag;
# XXX In the future, we should use a method of the installer object to
# retrieve the installed version --hpreg
#
# Try to retrieve the installed version from the configurator program. This
# works for both the tar and the rpm installers --hpreg
#
if (not defined($gDBAnswer{'BINDIR'})) {
return '';
}
if (not open(FILE, '<' . db_get_answer('BINDIR') . $gConfigurator)) {
return '';
}
# Build the pattern without using the dollar character, so that CVS doesn't
# modify the pattern in tagged builds (bug 9303) --hpreg
$backslash = chr(92);
$dollar = chr(36);
$pattern = '^ ' . $backslash . $dollar . 'buildNr = ' .
"'" . '(\S+) ' . "'" . ' ' . $backslash . '. q' .
$backslash . $dollar . 'Name: (\S+)? ' . $backslash . $dollar . ';' . $dollar;
$version = '';
$nameTag = '';
while (<FILE>) {
if (/$pattern/) {
$version = $1;
$nameTag = defined($2) ? $2 : '';
}
}
close(FILE);
return $version;
}
# Get the installed kind of VMware
# Return the kind if found, or ''
sub get_installed_kind() {
my $kind;
if (not (-x $cInstallerObject)) {
return '';
}
$kind = direct_command(shell_string($cInstallerObject) . ' kind');
chop($kind);
return $kind;
}
# Install the content of the module package
sub install_module {
my %patch;
print wrap('Installing the kernel modules contained in this package.' . "\n\n", 0);
undef %patch;
install_dir('./lib', db_get_answer('LIBDIR'), \%patch);
}
# Uninstall modules
sub uninstall_module {
print wrap('Uninstalling currently installed kernel modules.' . "\n\n", 0);
uninstall_prefix(db_get_answer('LIBDIR') . '/modules');
}
# XXX Duplicated in config.pl
# format of the returned hash:
# - key is the system file
# - value is the backed up file.
# This function should never know about filenames. Only database
# operations.
sub db_get_files_to_restore {
my %fileToRestore;
undef %fileToRestore;
my $restorePrefix = 'RESTORE_';
my $restoreBackupSuffix = '_BAK';
my $restoreBackList = 'RESTORE_BACK_LIST';
if (defined db_get_answer_if_exists($restoreBackList)) {
my $restoreStr;
foreach $restoreStr (split(/:/, db_get_answer($restoreBackList))) {
if (defined db_get_answer_if_exists($restorePrefix . $restoreStr)) {
$fileToRestore{db_get_answer($restorePrefix . $restoreStr)} =
db_get_answer($restorePrefix . $restoreStr
. $restoreBackupSuffix);
}
}
}
return %fileToRestore;
}
# Returns an array with the list of files that changed since we installed
# them.
sub db_is_file_changed {
my $file = shift;
my @statbuf;
@statbuf = stat($file);
if (defined $gDBFile{$file} && $gDBFile{$file} ne '0' &&
$gDBFile{$file} ne $statbuf[9]) {
return 'yes';
} else {
return 'no';
}
}
sub filter_out_bkp_changed_files {
my $filesToRestoreRef = shift;
my $origFile;
foreach $origFile (keys %$filesToRestoreRef) {
if (db_file_in($origFile) && !-l $origFile &&
db_is_file_changed($origFile) eq 'yes') {
# We are in the case of bug 25444 where we are restoring a file
# that we backed up and was changed in the mean time by someone else
db_remove_file($origFile);
backup_file($$filesToRestoreRef{$origFile});
unlink $$filesToRestoreRef{$origFile};
print wrap("\n" . 'File ' . $$filesToRestoreRef{$origFile}
. ' was not restored from backup because our file '
. $origFile
. ' got changed or overwritten between the time '
. vmware_product_name()
. ' installed the file and now.' . "\n\n"
,0);
delete $$filesToRestoreRef{$origFile};
}
}
}
sub restore_backedup_files {
my $fileToRestore = shift;
my $origFile;
foreach $origFile (keys %$fileToRestore) {
if (file_name_exist($origFile) &&
file_name_exist($$fileToRestore{$origFile})) {
backup_file($origFile);
unlink $origFile;
}
if ((not file_name_exist($origFile)) &&
file_name_exist($$fileToRestore{$origFile})) {
rename $$fileToRestore{$origFile}, $origFile;
}
}
}
# Program entry point
sub main {
my (@setOption, $opt);
if (not is_root()) {
error('Please re-run this program as the super user.' . "\n\n");
}
# Force the path to reduce the risk of using "modified" external helpers
# If the user has a special system setup, he will will prompted for the
# proper location anyway
$ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
initialize_globals();
initialize_external_helpers();
# List of questions answered with command-line arguments
@setOption = ();
if (internal_basename($0) eq $cInstallerFileName) {
my $answer;
if ($#ARGV > -1) {
if ($#ARGV > 1) {
install_usage();
}
# There are only two possible arguments
while ($#ARGV != -1) {
my $arg;
$arg = shift(@ARGV);
if (lc($arg) =~ /^(-)?(-)?d(efault)?/) {
$gOption{'default'} = 1;
} elsif ($arg =~ /=yes/ || $arg =~ /=no/) {
push(@setOption, $arg);
} else {
install_usage();
}
}
}
# Other installers will be able to remove this installation cleanly only if
# they find the uninstaller. That's why we:
# . Install the uninstaller ASAP
# . Prevent dumb users from playing with Control-C while doing so
$gIsUninstallerInstalled = 0;
# Install the SIGINT handler
$SIG{INT} = \&sigint_handler;
# The uninstall of the old tools must come before get_initial_database()
if (vmware_product() eq 'tools-for-linux') {
if (direct_command('LANG=C ' . shell_string($gHelper{'lsmod'})) =~
/vmxnet\D+\d+\D+\d+/ ) {
print wrap('The vmxnet network driver is in use, please stop '
. 'the network by invoking the command:' . "\n\n"
. ' /etc/init.d/network stop' . "\n"
. ' rmmod vmxnet' . "\n\n"
. 'After that, run this program again. You can start the '
. 'network after the tools are installed by '
. 'running the command:' . "\n\n"
. ' /etc/init.d/network start' . "\n\n", 0);
exit 0;
}
}
if (vmware_product() eq 'tools-for-linux' ||
vmware_product() eq 'tools-for-freebsd') {
uninstall_content_old_tools();
}
get_initial_database();
# Binary wrappers can be run by any user and need to read the
# database. --hpreg
safe_chmod(0644, $gInstallerMainDB);
if (@setOption > 0) {
$gOption{'default'} = 1;
}
foreach $opt (@setOption) {
my ($key, $val);
($key, $val) = ($opt =~ /^([^=]*)=([^=]*)/);
db_add_answer($key, $val);
}
if (vmware_product() eq 'console' || vmware_product() eq 'api'
|| vmware_product() eq 'mui') {
show_EULA();
}
install_or_upgrade();
# Reset the handler
$SIG{INT} = 'DEFAULT';
# Reset these answers in case we have installed new versions of these
# documents
db_remove_answer('EULA_AGREED');
db_remove_answer('ISC_COPYRIGHT_SEEN');
# We need to write the config file for the remote console
if (vmware_product() eq 'console') {
write_vmware_config();
}
if (!(vmware_product() eq 'api')) {
if (file_name_exist($gConfFlag)) {
$answer = get_persistent_answer('Before running '
. vmware_product_name()
. ' for the first time, you need to '
. 'configure it by invoking the '
. 'following command: "'
. db_get_answer('BINDIR')
. '/' . "$gConfigurator" . '". Do you '
. 'want this program to invoke the '
. 'command for you now?'
, 'RUN_CONFIGURATOR', 'yesno', 'yes');
} else {
print wrap('Before running ' . vmware_product_name() . ' for the first'
. ' time, you need to configure it by invoking the'
. ' following command: "' . db_get_answer('BINDIR')
. '/' . "$gConfigurator" . '"' . "\n\n", 0);
$answer = 'no';
}
}
db_save();
if (!(vmware_product() eq 'api') && ($answer eq 'yes')) {
system(shell_string(db_get_answer('BINDIR') . '/' . $gConfigurator));
} else {
print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
}
exit 0;
}
#
# Module updater.
#
# XXX This is not clean. We really need separate packages, managed
# by the VMware package manager --hpreg
#
if (internal_basename($0) eq $cModuleUpdaterFileName) {
my $installed_version;
my $installed_kind;
my $answer;
print wrap('Looking for a currently installed '
. vmware_longname() . ' tar package.' . "\n\n", 0);
if (not (-e $cInstallerMainDB)) {
error('Unable to find the ' . vmware_product_name() .
' installer database file (' . $cInstallerMainDB . ').' .
"\n\n" . 'You may want to re-install the ' .
vmware_longname() . ' package, then re-run this program.' . "\n\n");
}
db_load();
$installed_version = get_installed_version();
$installed_kind = get_installed_kind();
if (not (($installed_version eq 'e.x.p') and
($installed_kind eq 'tar'))) {
error('This ' . vmware_product_name()
. ' Kernel Modules package is intended to be used in conjunction '
. 'with the ' . vmware_longname() . ' tar package only.' . "\n\n");
}
# All module files are under LIBDIR --hpreg
if (not defined($gDBAnswer{'LIBDIR'})) {
error('Unable to determine where the ' . vmware_longname()
. ' package installed the library files.' . "\n\n"
. 'You may want to re-install the ' . vmware_product_name() . ' '
. vmware_version() . ' package, then re-run this program.' . "\n\n");
}
db_append();
uninstall_module();
install_module();
print wrap('The installation of ' . vmware_product_name()
. ' Kernel Modules '
. vmware_version() . ' completed successfully.' . "\n\n", 0);
if (-e $cConfFlag) {
$answer = get_persistent_answer('Before running the VMware software for '
. 'the first time after this update, you'
. ' need to configure it for your '
. 'running kernel by invoking the '
. 'following command: "'
. db_get_answer('BINDIR')
. '/' . $gConfigurator . '". Do you want this '
. 'program to invoke the command for you now?',
'RUN_CONFIGURATOR', 'yesno', 'yes');
} else {
$answer = 'no';
}
db_save();
if ($answer eq 'yes') {
system(shell_string(db_get_answer('BINDIR') . '/' . $gConfigurator));
} else {
print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
}
exit 0;
}
if (internal_basename($0) eq $gUninstallerFileName) {
print wrap('Uninstalling the tar installation of ' .
vmware_product_name() . '.' . "\n\n", 0);
if (not (-e $gInstallerMainDB)) {
error('Unable to find the tar installer database file (' .
$gInstallerMainDB . ')' . "\n\n");
}
db_load();
db_append();
if (vmware_product() eq 'wgs') {
wgs_uninstall();
}
if (vmware_product() eq 'mui') {
stop_mui(db_get_answer('INSTALLDIR'));
clear_mui_logs();
uninstall('/httpd.vmware');
} elsif (vmware_product() eq 'tools-for-linux' ||
vmware_product() eq 'tools-for-freebsd') {
my %fileToRestore;
# Clean up the module loader config file from vmxnet.
if (vmware_product() eq 'tools-for-freebsd' &&
defined db_get_answer_if_exists('VMXNET_CONFED') &&
db_get_answer('VMXNET_CONFED') eq 'yes') {
my $loader_conf = '/boot/loader.conf';
my $tmp_dir;
my $tmp;
$tmp_dir = make_tmp_dir('vmware-installer');
$tmp = $tmp_dir . '/loader.conf';
if (block_remove($loader_conf, $tmp, $cMarkerBegin, $cMarkerEnd) >= 0) {
system(shell_string($gHelper{'mv'}) . ' -f ' . shell_string($tmp)
. ' '
. shell_string($loader_conf));
}
remove_tmp_dir($tmp_dir);
}
# Get the file names before they disappear from the database.
%fileToRestore = db_get_files_to_restore();
filter_out_bkp_changed_files(\%fileToRestore);
uninstall('/vmware-tools');
restore_backedup_files(\%fileToRestore);
} else {
uninstall('/vmware');
}
db_save();
print wrap('The removal of ' . vmware_longname() . ' completed '
. 'successfully. Thank you for having tried this software.'
. "\n\n", 0);
exit 0;
}
error('This program must be named ' . $cInstallerFileName . ' or '
. $gUninstallerFileName . '.' . "\n\n");
}
main();