home *** CD-ROM | disk | FTP | other *** search
/ Chip: Linux Special / CorelLinux_CHIP.iso / VMware / bin / vmware-uninstall.pl < prev    next >
Encoding:
Perl Script  |  1999-11-10  |  28.2 KB  |  1,064 lines

  1. #!/usr/bin/perl -w
  2. # If your copy of perl is not in /usr/bin, please adjust the line above.
  3. #
  4. # Copyright (C) 1998, 1999 VMware, Inc.  All Rights Reserved.
  5. #
  6. # Tar package manager for VMware
  7.  
  8. use strict;
  9.  
  10. # Constants
  11. my $cInstallerFileName = 'vmware-install.pl';
  12. my $cUninstallerFileName = 'vmware-uninstall.pl';
  13. my $cInstallerDir = './installer';
  14. my $cOldInstaller = $cInstallerDir . '/old-install.pl';
  15. my $cStartupFileName = $cInstallerDir . '/services.sh';
  16. my $cEtcDir = '/etc';
  17. my $cInstallDBDir = $cEtcDir . '/vmware';
  18. my $cInstallDBFileName = $cInstallDBDir . '/locations';
  19. my $cInstallDBBackupFileName = $cInstallDBDir . '/db.tar.gz';
  20. my $cInstallerObjectFileName = $cInstallDBDir . '/installer.sh';
  21. my $cConfFlag = $cInstallDBDir . '/not_configured';
  22.  
  23. # External helper programs
  24. my %gHelper;
  25.  
  26. # BEGINNING OF THE SECOND LIBRARY FUNCTIONS
  27. # Global variables
  28. my %gDBAnswer;
  29. my %gDBFile;
  30. my %gDBDir;
  31.  
  32. # Load the installer database
  33. sub db_load { 
  34.   open(INSTALLDB, '<' . $cInstallDBFileName) or error('Unable to open the installer database ' . $cInstallDBFileName . ' in read-mode.' . "\n\n");
  35.   while (<INSTALLDB>) {
  36.     if (/^answer (\S+) (\S+)/) {
  37.       $gDBAnswer{$1} = $2;
  38.     } elsif (/^answer (\S+)/) {
  39.       $gDBAnswer{$1} = '';
  40.     } elsif (/^remove_answer (\S+)/) {
  41.       delete $gDBAnswer{$1};
  42.     } elsif (/^file (\S+) (\S+)/) {
  43.       $gDBFile{$1} = $2;
  44.     } elsif (/^file (\S+)/) {
  45.       $gDBFile{$1} = 0;
  46.     } elsif (/^remove_file (\S+)/) {
  47.       delete $gDBFile{$1};
  48.     } elsif (/^directory (\S+)/) {
  49.       $gDBDir{$1} = '';
  50.     }
  51.   }
  52.   close(INSTALLDB);
  53. }
  54.  
  55. # Open the database on disk in append mode
  56. sub db_append {
  57.   if (not open(INSTALLDB, '>>' . $cInstallDBFileName)) {
  58.     error('Unable to open the installer database ' . $cInstallDBFileName . ' in append-mode.' . "\n\n");
  59.   }
  60.   # Force a flush after every write operation.
  61.   # See 'Programming Perl', p. 110
  62.   select((select(INSTALLDB), $| = 1)[0]);
  63. }
  64.  
  65. # Add a file to the tar installer database
  66. sub db_add_file {
  67.   my $file = shift;
  68.   my $flags = shift;
  69.  
  70.   if ($flags & 0x1) {
  71.     my @statbuf;
  72.  
  73.     @statbuf = stat($file);
  74.     if (not (defined($statbuf[9]))) {
  75.       error('Unable to get the last modification timestamp of the destination file ' . $file . '.' . "\n\n");
  76.     }
  77.  
  78.     $gDBFile{$file} = $statbuf[9];
  79.     print INSTALLDB 'file ' . $file . ' ' . $statbuf[9] . "\n";
  80.   } else {
  81.     $gDBFile{$file} = 0;
  82.     print INSTALLDB 'file ' . $file . "\n";
  83.   }
  84. }
  85.  
  86. # Remove a file from the tar installer database
  87. sub db_remove_file {
  88.   my $file = shift;
  89.  
  90.   print INSTALLDB 'remove_file ' . $file . "\n";
  91.   delete $gDBFile{$file};
  92. }
  93.  
  94. # Determine if a file belongs to the tar installer database
  95. sub db_file_in {
  96.   my $file = shift;
  97.  
  98.   return defined($gDBFile{$file});
  99. }
  100.  
  101. # Return the timestamp of an installed file
  102. sub db_file_ts {
  103.   my $file = shift;
  104.  
  105.   return $gDBFile{$file};
  106. }
  107.  
  108. # Add a directory to the tar installer database
  109. sub db_add_dir {
  110.   my $dir = shift;
  111.  
  112.   $gDBDir{$dir} = '';
  113.   print INSTALLDB 'directory ' . $dir . "\n";
  114. }
  115.  
  116. # Remove an answer from the tar installer database
  117. sub db_remove_answer {
  118.   my $id = shift;
  119.  
  120.   if (defined($gDBAnswer{$id})) {
  121.     print INSTALLDB 'remove_answer ' . $id . "\n";
  122.     delete $gDBAnswer{$id};
  123.   }
  124. }
  125.  
  126. # Add an answer to the tar installer database
  127. sub db_add_answer {
  128.   my $id = shift;
  129.   my $value = shift;
  130.  
  131.   db_remove_answer($id);
  132.   $gDBAnswer{$id} = $value;
  133.   print INSTALLDB 'answer ' . $id . ' ' . $value . "\n";
  134. }
  135.  
  136. # Retrieve an answer that must be present in the database
  137. sub db_get_answer {
  138.   my $id = shift;
  139.  
  140.   if (not defined($gDBAnswer{$id})) {
  141.     error('Unable to find the answer ' . $id . ' in the installer database (' . $cInstallDBFileName . '). You may want to re-install VMware.' . "\n\n");
  142.   }
  143.  
  144.   return $gDBAnswer{$id};
  145. }
  146.  
  147. # Save the tar installer database
  148. sub db_save {
  149.   close(INSTALLDB);
  150. }
  151. # END OF THE SECOND LIBRARY FUNCTIONS
  152.  
  153. # BEGINNING OF THE LIBRARY FUNCTIONS
  154. # Constants
  155. my $cTerminalLineSize = 80;
  156.  
  157. # Global variables
  158. my %gOption;
  159. my %gAnswerSize;
  160. my %gCheckAnswerFct;
  161.  
  162. # Tell if the user is the super user
  163. sub is_root {
  164.   return $> == 0;
  165. }
  166.  
  167. # Wordwrap system: append some content to the output
  168. sub append_output {
  169.   my $output = shift;
  170.   my $pos = shift;
  171.   my $append = shift;
  172.  
  173.   $output .= $append;
  174.   $pos = ($pos + length($append)) % $cTerminalLineSize;
  175.  
  176.   return ($output, $pos);
  177. }
  178.  
  179. # Wordwrap system: deal with the next character
  180. sub wrap_one_char {
  181.   my $output = shift;
  182.   my $pos = shift;
  183.   my $word = shift;
  184.   my $char = shift;
  185.   my $reserved = shift;
  186.   my $length;
  187.  
  188.   if (not (($char eq "\n") || ($char eq ' ') || ($char eq ''))) {
  189.     $word .= $char;
  190.  
  191.     return ($output, $pos, $word);
  192.   }
  193.  
  194.   # We found a separator. Process the last word
  195.  
  196.   $length = length($word) + $reserved;
  197.   if ((($pos + $length) > $cTerminalLineSize) && ($length <= $cTerminalLineSize)) {
  198.     # The word is too large to fit in the end of line, but can fit in a new
  199.     # empty line, let's create one for it
  200.     $output .= "\n";
  201.     $pos = 0;
  202.   }
  203.  
  204.   ($output, $pos) = append_output($output, $pos, $word);
  205.   $word = '';
  206.  
  207.   if ($char eq "\n") {
  208.     $output .= "\n";
  209.     $pos = 0;
  210.   } elsif ($char eq ' ') {
  211.     if ($pos) {
  212.       ($output, $pos) = append_output($output, $pos, ' ');
  213.     }
  214.   }
  215.  
  216.   return ($output, $pos, $word);
  217. }
  218.  
  219. # Wordwrap system: word-wrap a string plus some reserved trailing space
  220. sub wrap {
  221.   my $input = shift;
  222.   my $reserved = shift;
  223.   my $output;
  224.   my $pos;
  225.   my $word;
  226.   my $i;
  227.  
  228.   $output = '';
  229.   $pos = 0;
  230.   $word = '';
  231.   for ($i = 0; $i < length($input); $i++) {
  232.     ($output, $pos, $word) = wrap_one_char($output, $pos, $word, substr($input, $i, 1), 0);
  233.   }
  234.   # Use an artifical last '' separator to process the last word
  235.   ($output, $pos, $word) = wrap_one_char($output, $pos, $word, '', $reserved);
  236.  
  237.   return $output;
  238. }
  239.  
  240. # Print an error message and exit
  241. sub error {
  242.   my $msg = shift;
  243.  
  244.   print STDERR wrap($msg . 'Execution aborted.' . "\n\n", 0);
  245.   exit 1;
  246. }
  247.  
  248. # Convert a string to its equivalent shell representation
  249. sub shell_string {
  250.   my $single_quoted = shift;
  251.  
  252.   $single_quoted =~ s/'/'"'"'/g;
  253.   # This comment is a fix for emacs's broken syntax-highlighting code --hpreg
  254.   return '\'' . $single_quoted . '\'';
  255. }
  256.  
  257. # Contrary to a popular belief, 'which' is not always a shell builtin command.
  258. # So we can not trust it to determine the location of other binaries.
  259. # Moreover, SuSE 6.1's 'which' is unable to handle program names beginning with
  260. # a '/'...
  261. #
  262. # Return value is the complete path if found, or '' if not found
  263. sub internal_which {
  264.   my $bin = shift;
  265.  
  266.   if (substr($bin, 0, 1) eq '/') {
  267.     # Absolute name
  268.     if ((-f $bin) && (-x $bin)) {
  269.       return $bin;
  270.     }
  271.   } else {
  272.     # Relative name
  273.     my @paths;
  274.     my $path;
  275.  
  276.     if (index($bin, '/') == -1) {
  277.       # There is no other '/' in the name
  278.       @paths = split(':', $ENV{'PATH'});
  279.       foreach $path (@paths) {
  280.     my $fullbin;
  281.  
  282.     $fullbin = $path . '/' . $bin;
  283.     if ((-f $fullbin) && (-x $fullbin)) {
  284.       return $fullbin;
  285.     }
  286.       }
  287.     }
  288.   }
  289.  
  290.   return '';
  291. }
  292.  
  293. # Remove leading and trailing whitespaces
  294. sub remove_whitespaces {
  295.   my $string = shift;
  296.  
  297.   $string =~ s/^\s*//;
  298.   $string =~ s/\s*$//;
  299.   return $string;
  300. }
  301.  
  302. # Ask a question to the user and propose an optional default value
  303. # Use this when you don't care about the validity of the answer
  304. sub query {
  305.     my $message = shift;
  306.     my $defaultreply = shift;
  307.     my $reserved = shift;
  308.     my $reply;
  309.  
  310.     # Reserve some room for the reply
  311.     print wrap($message . (($defaultreply eq '') ? '' : (' [' . $defaultreply . ']')), 1 + $reserved);
  312.     # This is what the 1 is for
  313.     print ' ';
  314.        
  315.     if ($gOption{'default'} == 1) {
  316.       # Simulate the enter key
  317.       print "\n";
  318.       $reply = '';
  319.     } else {
  320.       chop($reply = <STDIN>);
  321.     }
  322.  
  323.     print "\n";
  324.     $reply = remove_whitespaces($reply);
  325.     if ($reply eq '') {
  326.       $reply = $defaultreply;
  327.     }
  328.     return $reply;
  329. }
  330.  
  331. # Check the validity of an answer whose type is yesno
  332. # Return a clean answer if valid, or ''
  333. sub check_answer_binpath {
  334.   my $answer = shift;
  335.   my $source = shift;
  336.  
  337.   if (not (internal_which($answer) eq '')) {
  338.     return $answer;
  339.   }
  340.  
  341.   if ($source eq 'user') {
  342.     print wrap('The answer "' . $answer . '" is invalid. It must be the complete name of a binary file.' . "\n\n", 0);
  343.   }
  344.   return '';
  345. }
  346. $gAnswerSize{'binpath'} = 20;
  347. $gCheckAnswerFct{'binpath'} = \&check_answer_binpath;
  348.  
  349. # Prompts the user if a binary is not found
  350. # Return value is:
  351. #  '': the binary has not been found
  352. #  the binary name if it has been found
  353. sub DoesBinaryExist_Prompt {
  354.   my $bin = shift;
  355.   my $answer;
  356.  
  357.   $answer = check_answer_binpath($bin, 'default');
  358.   if (not ($answer eq '')) {
  359.     return $answer;
  360.   }
  361.  
  362.   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') {
  363.     return '';
  364.   }
  365.  
  366.   return get_answer('What is the location of the "' . $bin . '" program on your machine?', 'binpath', '');
  367. }
  368.  
  369. # Execute the command passed as an argument
  370. # _without_ interpolating variables (Perl does it by default)
  371. sub direct_command {
  372.   return `$_[0]`;
  373. }
  374.  
  375. # chmod() that reports errors
  376. sub safe_chmod {
  377.   my $mode = shift;
  378.   my $file = shift;
  379.  
  380.   if (chmod($mode, $file) != 1) {
  381.     error('Unable to change the access rights of the file ' . $file . '.' . "\n\n");
  382.   }
  383. }
  384.  
  385. # Emulate a simplified ls program for directories
  386. sub internal_ls {
  387.   my $dir = shift;
  388.   my @fn;
  389.  
  390.   opendir(LS, $dir);
  391.   @fn = grep(!/^\.\.?$/, readdir(LS));
  392.   closedir(LS);
  393.  
  394.   return @fn;
  395. }
  396.  
  397. # Install a file permission
  398. sub install_permission {
  399.   my $src = shift;
  400.   my $dst = shift;
  401.   my @statbuf;
  402.  
  403.   @statbuf = stat($src);
  404.   if (not (defined($statbuf[2]))) {
  405.     error('Unable to get the access rights of the source file ' . $src . '.' . "\n\n");
  406.   }
  407.   safe_chmod($statbuf[2] & 0xFFF, $dst);
  408. }
  409.  
  410. # Emulate a simplified sed program
  411. # Return 1 if success, 0 if failure
  412. sub internal_sed {
  413.   my $src = shift;
  414.   my $dst = shift;
  415.   my $append = shift;
  416.   my $patchRef = shift;
  417.   my @patchKeys;
  418.  
  419.   if (not open(SRC, '<' . $src)) {
  420.     return 0;
  421.   }
  422.   if (not open(DST, (($append == 1) ? '>>' : '>') . $dst)) {
  423.     return 0;
  424.   }
  425.  
  426.   @patchKeys = keys(%$patchRef);
  427.   if ($#patchKeys == -1) {
  428.     while(defined($_ = <SRC>)) {
  429.       print DST $_;
  430.     }
  431.   } else {
  432.     while(defined($_ = <SRC>)) {
  433.       my $patchKey;
  434.  
  435.       foreach $patchKey (@patchKeys) {
  436.     s/$patchKey/$$patchRef{$patchKey}/g;
  437.       }
  438.  
  439.       print DST $_;
  440.     }
  441.   }
  442.  
  443.   close(SRC);
  444.   close(DST);
  445.   return 1;
  446. }
  447.  
  448. # Check if a file name exists
  449. sub file_name_exist {
  450.   my $file = shift;
  451.  
  452.   # Note: We must test for -l before, because if an existing symlink points to
  453.   #       a non-existing file, -e will be false
  454.   return ((-l $file) || (-e $file))
  455. }
  456.  
  457. # Check if a file already exists and prompt the user
  458. # Return 0 if the file can be written safely, 1 otherwise
  459. sub file_check_exist {
  460.   my $file = shift;
  461.  
  462.   if (not file_name_exist($file)) {
  463.     return 0;
  464.   }
  465.  
  466.   # The default must make sure that the product will be correctly installed
  467.   # We give the user the choice so that a sysadmin can perform a normal
  468.   # install on a NFS server and then answer 'no' NFS clients
  469.   return (get_answer('The file ' . $file . ' that this script was about to install already exists. Overwrite?', 'yesno', 'yes') eq 'yes') ? 0 : 1;
  470. }
  471.  
  472. # Install one file
  473. sub install_file {
  474.   my $src = shift;
  475.   my $dst = shift;
  476.   my $patchRef = shift;
  477.   my $ts = shift;
  478.  
  479.   uninstall_file($dst);
  480.   if (file_check_exist($dst)) {
  481.     return;
  482.   }
  483.   # The file could be a symlink to another location. Remove it
  484.   unlink($dst);
  485.   if (not internal_sed($src, $dst, 0, $patchRef)) {
  486.     error('Unable to copy the source file ' . $src . ' to the destination file ' . $dst . '.' . "\n\n");
  487.   }
  488.   db_add_file($dst, $ts);
  489.   install_permission($src, $dst);
  490. }
  491.  
  492. # mkdir() that reports errors
  493. sub safe_mkdir {
  494.   my $file = shift;
  495.  
  496.   if (mkdir($file, 0000) == 0) {
  497.     error('Unable to create the directory ' . $file . '.' . "\n\n");
  498.   }
  499. }
  500.  
  501. # Remove trailing slashes in a dir path
  502. sub dir_remove_trailing_slashes {
  503.   my $path = shift;
  504.  
  505.   for(;;) {
  506.     my $len;
  507.     my $pos;
  508.  
  509.     $len = length($path);
  510.     if ($len < 2) {
  511.       # Could be '/' or any other character. Ok.
  512.       return $path;
  513.     }
  514.  
  515.     $pos = rindex($path, '/');
  516.     if ($pos != $len - 1) {
  517.       # No trailing slash
  518.       return $path;
  519.     }
  520.  
  521.     # Remove the trailing slash
  522.     $path = substr($path, 0, $len - 1)
  523.   }
  524. }
  525.  
  526. # Emulate a simplified dirname program
  527. sub internal_dirname {
  528.   my $path = shift;
  529.   my $pos;
  530.  
  531.   $path = dir_remove_trailing_slashes($path);
  532.  
  533.   $pos = rindex($path, '/');
  534.   if ($pos == -1) {
  535.     # No slash
  536.     return '.';
  537.   }
  538.  
  539.   if ($pos == 0) {
  540.     # The only slash is at the beginning
  541.     return '/';
  542.   }
  543.  
  544.   return substr($path, 0, $pos);
  545. }
  546.  
  547. # Create a hierarchy of directories with permission 0755
  548. # Return 1 if the directory existed before
  549. sub create_dir {
  550.   my $dir = shift;
  551.   my $use_db = shift;
  552.  
  553.   if (-d $dir) {
  554.     return 1;
  555.   }
  556.  
  557.   if (index($dir, '/') != -1) {
  558.     create_dir(internal_dirname($dir), $use_db);
  559.   }
  560.   safe_mkdir($dir);
  561.   if ($use_db) {
  562.     db_add_dir($dir);
  563.   }
  564.   safe_chmod(0755, $dir);
  565.   return 0;
  566. }
  567.  
  568. # Get a valid non-persistent answer to a question
  569. # Use this when the answer shouldn't be stored in the database
  570. sub get_answer {
  571.   my $msg = shift;
  572.   my $type = shift;
  573.   my $default = shift;
  574.   my $answer;
  575.  
  576.   if (not defined($gAnswerSize{$type})) {
  577.     die 'get_answer(): type ' . $type . ' not implemented :(' . "\n\n";
  578.   }
  579.   for (;;) {
  580.     $answer = check_answer(query($msg, $default, $gAnswerSize{$type}), $type, 'user');
  581.     if (not ($answer eq '')) {
  582.       return $answer;
  583.     }
  584.   }
  585. }
  586.  
  587. # Get a valid persistent answer to a question
  588. # Use this when you want an answer to be stored in the database
  589. sub get_persistent_answer {
  590.   my $msg = shift;
  591.   my $id = shift;
  592.   my $type = shift;
  593.   my $default = shift;
  594.   my $answer;
  595.  
  596.   if (defined($gDBAnswer{$id})) {
  597.     # There is a previous answer in the database
  598.     $answer = check_answer($gDBAnswer{$id}, $type, 'db');
  599.     if (not ($answer eq '')) {
  600.       # The previous answer is valid. Make it the default value
  601.       $default = $answer;
  602.     }
  603.   }
  604.  
  605.   $answer = get_answer($msg, $type, $default);
  606.   db_add_answer($id, $answer);
  607.   return $answer;
  608. }
  609.  
  610. # Find a suitable backup name and backup a file
  611. sub backup_file {
  612.   my $file = shift;
  613.   my $i;
  614.  
  615.   for ($i = 0; $i < 100; $i++) {
  616.     if (! -e $file . '.old.' . $i) {
  617.       my %patch;
  618.  
  619.       undef %patch;
  620.       if (internal_sed($file, $file . '.old.' . $i, 0, \%patch)) {
  621.     print wrap('File ' . $file . ' is backed up to ' . $file . '.old.' . $i . '.' . "\n\n", 0);
  622.       } else {
  623.     print STDERR wrap('Unable to backup the file ' . $file . ' to ' . $file . '.old.' . $i .'.' . "\n\n", 0);
  624.       }
  625.       return;
  626.     }
  627.   }
  628.  
  629.   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);
  630. }
  631.  
  632. # Uninstall a file previously installed by us
  633. sub uninstall_file {
  634.   my $file = shift;
  635.  
  636.   if (not db_file_in($file)) {
  637.     # Not installed by this script
  638.     return;
  639.   }
  640.  
  641.   if (file_name_exist($file)) {
  642.     if (db_file_ts($file)) {
  643.       my @statbuf;
  644.  
  645.       @statbuf = stat($file);
  646.       if (defined($statbuf[9])) {
  647.     if (db_file_ts($file) != $statbuf[9]) {
  648.       # Modified since this script installed it
  649.       backup_file($file);
  650.     }
  651.       } else {
  652.     print STDERR wrap('Unable to get the last modification timestamp of the file ' . $file . '.' . "\n\n", 0);
  653.       }
  654.     }
  655.  
  656.     if (not unlink($file)) {
  657.       print STDERR wrap('Unable to remove the file ' . $file . '.' . "\n\n", 0);
  658.     }
  659.   } else {
  660.     print wrap('This script previously created the file ' . $file . ', and was about to remove it. Somebody else apparently did it already.' . "\n\n", 0);
  661.   }
  662.  
  663.   db_remove_file($file);
  664. }
  665.  
  666. # Return the version of VMware
  667. sub vmware_version {
  668.   my $buildNr;
  669.  
  670.   $buildNr = '1.1.2 ' . q$Name:  $;
  671.   $buildNr =~ s/Name: //;
  672.   return remove_whitespaces($buildNr);
  673. }
  674.  
  675. # Check the validity of an answer whose type is yesno
  676. # Return a clean answer if valid, or ''
  677. sub check_answer_yesno {
  678.   my $answer = shift;
  679.   my $source = shift;
  680.  
  681.   if (lc($answer) =~ /^y(es)?$/) {
  682.     return 'yes';
  683.   }
  684.  
  685.   if (lc($answer) =~ /^n(o)?$/) {
  686.     return 'no';
  687.   }
  688.  
  689.   if ($source eq 'user') {
  690.     print wrap('The answer "' . $answer . '" is invalid. It must be one of "y" or "n".' . "\n\n", 0);
  691.   }
  692.   return '';
  693. }
  694. $gAnswerSize{'yesno'} = 3;
  695. $gCheckAnswerFct{'yesno'} = \&check_answer_yesno;
  696.  
  697. # Check the validity of an answer based on its type
  698. # Return a clean answer if valid, or ''
  699. sub check_answer {
  700.   my $answer = shift;
  701.   my $type = shift;
  702.   my $source = shift;
  703.  
  704.   if (not defined($gCheckAnswerFct{$type})) {
  705.     die 'check_answer(): type ' . $type . ' not implemented :(' . "\n\n";
  706.   }
  707.   return &{$gCheckAnswerFct{$type}}($answer, $source);
  708. }
  709. # END OF THE LIBRARY FUNCTIONS
  710.  
  711. # Emulate a simplified basename program
  712. sub internal_basename {
  713.   return substr($_[0], rindex($_[0], '/') + 1);
  714. }
  715.  
  716. # Set up the location of external helpers
  717. sub initialize_external_helpers {
  718.   my $program;
  719.  
  720.   foreach $program ('tar', 'sed') {
  721.     $gHelper{$program} = DoesBinaryExist_Prompt($program);
  722.     if ($gHelper{$program} eq '') {
  723.       error('Unable to continue.' . "\n\n");
  724.     }
  725.   }
  726. }
  727.  
  728. # Reset the database
  729. sub db_reset {
  730.   my $made_dir;
  731.   my $id;
  732.  
  733.   undef %gDBFile;
  734.   undef %gDBDir;
  735.   $made_dir = 0;
  736.   if (not (-d $cInstallDBDir)) {
  737.     safe_mkdir($cInstallDBDir);
  738.     $gDBDir{$cInstallDBDir} = '';
  739.     $made_dir = 1;
  740.   }
  741.   safe_chmod(0755, $cInstallDBDir);
  742.  
  743.   if (open(INSTALLDB, '>' . $cInstallDBFileName) == 0) {
  744.     if ($made_dir) {
  745.       rmdir($cInstallDBDir);
  746.     }
  747.     error('Unable to open the tar installer database ' . $cInstallDBFileName . ' in write-mode.' . "\n\n");
  748.   }
  749.   # Force a flush after every write operation.
  750.   # See 'Programming Perl', p. 110
  751.   select((select(INSTALLDB), $| = 1)[0]);
  752.  
  753.   if ($made_dir) {
  754.     db_add_dir($cInstallDBDir);
  755.   }
  756.   # This file is going to be modified after its creation by this script.
  757.   # Consequently, if we timestamp it, it will be backed up, which is silly.
  758.   # Since the user has really no reason to modify it by hand, it is ok not
  759.   # to time stamp it
  760.   db_add_file($cInstallDBFileName, 0);
  761.  
  762.   # Rewrite all answers
  763.   foreach $id (keys %gDBAnswer) {
  764.     print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
  765.   }
  766. }
  767.  
  768. # Check the validity of an answer whose type is dirpath
  769. # Return a clean answer if valid, or ''
  770. sub check_answer_dirpath {
  771.   my $answer = shift;
  772.   my $source = shift;
  773.  
  774.   $answer = dir_remove_trailing_slashes($answer);
  775.  
  776.   if (-d $answer) {
  777.     # The path is an existing directory
  778.     return $answer;
  779.   }
  780.  
  781.   # The path is not a directory
  782.   if (-e $answer) {
  783.     if ($source eq 'user') {
  784.       print wrap('The path "' . $answer . '" exists, but is not a directory.' . "\n\n", 0);
  785.     }
  786.     return '';
  787.   }
  788.  
  789.   # The path does not exist
  790.   if ($source eq 'user') {
  791.     return (get_answer('The path "' . $answer . '" does not exist currently. This script is going to create it, including needed parent directories. Is this what you want?', 'yesno', 'yes') eq 'yes') ? $answer : '';
  792.   } else {
  793.     return $answer;
  794.   }
  795. }
  796. $gAnswerSize{'dirpath'} = 20;
  797. $gCheckAnswerFct{'dirpath'} = \&check_answer_dirpath;
  798.  
  799. # Check the validity of an answer whose type is initdirpath
  800. # Return a clean answer if valid, or ''
  801. sub check_answer_initdirpath {
  802.   my $answer = shift;
  803.   my $source = shift;
  804.   my $testdir;
  805.  
  806.   $answer = dir_remove_trailing_slashes($answer);
  807.  
  808.   if (not (-d $answer)) {
  809.     if ($source eq 'user') {
  810.       print wrap('The path "' . $answer . '" is not an existing directory.' . "\n\n", 0);
  811.     }
  812.     return '';
  813.   }
  814.  
  815.   foreach $testdir ('init.d', 'rc0.d',  'rc1.d', 'rc2.d', 'rc3.d', 'rc4.d', 'rc5.d', 'rc6.d') {
  816.     if (not (-d $answer . '/' . $testdir)) {
  817.       if ($source eq 'user') {
  818.     print wrap('The path "' . $answer . '" is a directory which does not contain a ' . $testdir . ' directory.' . "\n\n", 0);
  819.       }
  820.       return '';
  821.     }
  822.   }
  823.  
  824.   return $answer;
  825. }
  826. $gAnswerSize{'initdirpath'} = 15;
  827. $gCheckAnswerFct{'initdirpath'} = \&check_answer_initdirpath;
  828.  
  829. # Install one directory (recursively)
  830. sub install_dir {
  831.   my $src_dir = shift;
  832.   my $dst_dir = shift;
  833.   my $patchRef = shift;
  834.   my $file;
  835.  
  836.   if (create_dir($dst_dir, 1) == 0) {
  837.     install_permission($src_dir, $dst_dir);
  838.   }
  839.   foreach $file (internal_ls($src_dir)) {
  840.     if (-d $src_dir . '/' . $file) {
  841.       install_dir($src_dir . '/' . $file, $dst_dir . '/' . $file, $patchRef);
  842.     } else {
  843.       install_file($src_dir . '/' . $file, $dst_dir . '/' . $file, $patchRef, 1);
  844.     }
  845.   }
  846. }
  847.  
  848. # Install the content of the tar package
  849. sub install_content {
  850.   my $rootdir;
  851.   my $answer;
  852.   my %patch;
  853.   my $initdir;
  854.  
  855.   undef %patch;
  856.   install_dir('./etc', '/etc/vmware', \%patch);
  857.  
  858.   $rootdir = '/usr';
  859.  
  860.   # Install the uninstaller ASAP, otherwise other installers will not be able
  861.   # remove this installation cleanly
  862.   $answer = get_persistent_answer('In which directory do you want to install the binary files?', 'BINDIR', 'dirpath', $rootdir . '/bin');
  863.   undef %patch;
  864.   install_dir('./bin', $answer, \%patch);
  865.   # Make vmware and vmware-ping suid root
  866.   safe_chmod(04555, $answer . '/vmware');
  867.   safe_chmod(04555, $answer . '/vmware-ping');
  868.  
  869.   $rootdir = internal_dirname($answer);
  870.  
  871.   # We don't use get_persistent_answer() here because once the user has
  872.   # selected the root directory, we can give him better default answers than
  873.   # his/her previous answers.
  874.  
  875.   $answer = get_answer('In which directory do you want to install the library files?', 'dirpath', $rootdir . '/lib/vmware');
  876.   db_add_answer('LIBDIR', $answer);
  877.   undef %patch;
  878.   install_dir('./lib', $answer, \%patch);
  879.  
  880.   $answer = get_answer('In which directory do you want to install the manual files?', 'dirpath', $rootdir . '/man');
  881.   db_add_answer('MANDIR', $answer);
  882.   undef %patch;
  883.   $patch{'%LIBDIR%'} = db_get_answer('LIBDIR');
  884.   install_dir('./man', $answer, \%patch);
  885.  
  886.   $answer = get_persistent_answer('In which directory do you want to install the documentation files?', 'DOCDIR', 'dirpath', '/usr/doc/vmware');
  887.   undef %patch;
  888.   install_dir('./doc', $answer, \%patch);
  889.  
  890.   # Install the startup script (and make the old installer aware of this one)
  891.   $initdir = '/sbin/init.d';
  892.   if (check_answer_initdirpath($initdir, 'default') eq '') {
  893.     $initdir = '/etc/rc.d';
  894.     if (check_answer_initdirpath($initdir, 'default') eq '') {
  895.       $initdir = '/etc';
  896.       if (check_answer_initdirpath($initdir, 'default') eq '') {
  897.     $initdir = '';
  898.       }
  899.     }
  900.   }
  901.   $answer = get_persistent_answer('What is the directory under which the init scripts reside (it should contain init.d/, and from rc0.d/ to rc6.d/)?', 'INITDIR', 'initdirpath', $initdir);
  902.   undef %patch;
  903.   install_file($cStartupFileName, $answer . '/init.d/vmware', \%patch, 1);
  904. }
  905.  
  906. # Install a tar package or upgrade an already installed tar package
  907. sub install_or_upgrade {
  908.   print wrap('Installing the content of the package.' . "\n\n", 0);
  909.   install_content();
  910.   print wrap('The installation of VMware ' . vmware_version() . ' for Linux completed successfully. You can decide to remove this software from your system at any time by invoking the following command: "' . db_get_answer('BINDIR') . '/' . $cUninstallerFileName . '".' . "\n\n", 0);
  911. }
  912.  
  913. # Uninstall a tar package
  914. sub uninstall {
  915.   my $startup;
  916.   my $file;
  917.   my $dir;
  918.  
  919.   if (system(shell_string(db_get_answer('INITDIR') . '/init.d/vmware') . ' stop')) {
  920.     error('Unable to stop VMware' . "'" . 's services.' . "\n\n");
  921.   }
  922.   print "\n";
  923.  
  924.   # Remove all files
  925.   foreach $file (keys %gDBFile) {
  926.     uninstall_file($file);
  927.   }
  928.  
  929.   # Remove all directories
  930.   # We sort them by decreasing order of their length, to ensure that we will
  931.   # remove the inner ones before the outer ones
  932.   foreach $dir (sort {length($b) <=> length($a)} keys %gDBDir) {
  933.     rmdir($dir) or warn 'Refused to remove ' . $dir . ': the directory is not empty.' . "\n\n";
  934.   }
  935. }
  936.  
  937. # Display a usage error message for the install program and exit
  938. sub install_usage {
  939.   print STDERR wrap('VMware ' . vmware_version() . ' for Linux installer' . "\n" . 'Usage: ' . $0 . ' [[-][-]d[efault]]' . "\n" . '    default: Automatically answer questions with the proposed answer.' . "\n\n", 0);
  940.   exit 1;
  941. }
  942.  
  943. # Program entry point
  944. sub main {
  945.   my $kind;
  946.  
  947.   if (not is_root()) {
  948.     error('Please re-run this script as the super user.' . "\n\n");
  949.   }
  950.  
  951.   # Force the path to reduce the risk of using "modified" external helpers
  952.   # If the user has a special system setup, he will will prompted for the
  953.   # proper location anyway
  954.   $ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
  955.  
  956.   $gOption{'default'} = 0;
  957.   initialize_external_helpers();
  958.  
  959.   if (internal_basename($0) eq $cInstallerFileName) {
  960.     my $answer;
  961.  
  962.     if ($#ARGV > -1) {
  963.       if ($#ARGV > 0) {
  964.     install_usage();
  965.       }
  966.  
  967.       # There is only one argument
  968.       if (lc($ARGV[0]) !~ /^(-)?(-)?d(efault)?/) {
  969.     install_usage();
  970.       }
  971.  
  972.       $gOption{'default'} = 1;
  973.     }
  974.  
  975.     if (-e $cInstallDBFileName) {
  976.       print wrap('A previous installation of VMware has been detected.' . "\n\n", 0);
  977.  
  978.       #
  979.       # Convert the previous installer database to our format and backup it
  980.       # Uninstall the previous installation
  981.       #
  982.  
  983.       if (-x $cInstallerObjectFileName) {
  984.     $kind = direct_command(shell_string($cInstallerObjectFileName) . ' kind');
  985.     chop($kind);
  986.  
  987.     print wrap('The previous installation was made by the ' . $kind . ' installer.' . "\n\n", 0);
  988.  
  989.     # Here, you typically put cases for older installer where
  990.     # a database format upgrade is needed. For the moment, the
  991.     # only older installer that we know is the old installer, which
  992.     # is special cased.
  993.  
  994.     # Here go cases for newer installers we know nothing about.
  995.     # Consequently, they know about our format. Make them
  996.     # downgrade their installation database to our format
  997.     system(shell_string($cInstallerObjectFileName) . ' convertdb tar ' . shell_string($cInstallDBBackupFileName));
  998.  
  999.         # Uninstall the previous installation
  1000.         system(shell_string($cInstallerObjectFileName) . ' uninstall');
  1001.         # Beware, beyond this point, $cInstallerObjectFileName does not exist
  1002.         # anymore.
  1003.       } else {
  1004.  
  1005.         #
  1006.         # Special case the old installer, because it didn't know about
  1007.         # the installer.sh mechanism
  1008.         #
  1009.  
  1010.         print wrap('The previous installation was made by the old installer.' . "\n\n", 0);
  1011.         print wrap('Converting the old installer database format to the tar installer database format.' . "\n\n", 0);
  1012.         system(shell_string($gHelper{'sed'}) . ' -e ' . shell_string('/^answer SHARED_.* /d') . ' -e ' . shell_string('s/^answer BUILDR_driver /answer BUILDR_vmmon /') . ' ' . shell_string($cInstallDBFileName) . ' > ' . shell_string($cInstallDBFileName . 'tmp'));
  1013.         rename($cInstallDBFileName . 'tmp', $cInstallDBFileName);
  1014.     system(shell_string($gHelper{'tar'}) . ' -czopf ' . shell_string($cInstallDBBackupFileName) . ' ' . shell_string($cInstallDBFileName) . ' 2> /dev/null');
  1015.  
  1016.     print wrap('Uninstalling the old installation of VMware.' . "\n\n", 0);
  1017.     if (system(shell_string($cOldInstaller) . ' uninstall')) {
  1018.       unlink($cInstallDBBackupFileName);
  1019.       error('Failure' . "\n\n");
  1020.     }
  1021.       }
  1022.  
  1023.       # Restore the database suitable for our installer
  1024.       system(shell_string($gHelper{'tar'}) . ' -C / -xzopf ' . shell_string($cInstallDBBackupFileName));
  1025.       unlink($cInstallDBBackupFileName);
  1026.  
  1027.       db_load();
  1028.     }
  1029.     db_reset();
  1030.     install_or_upgrade();
  1031.  
  1032.     # Reset these answers in case we have installed new versions of these
  1033.     # documents
  1034.     db_remove_answer('EULA_AGREED');
  1035.     db_remove_answer('ISC_COPYRIGHT_SEEN');
  1036.  
  1037.     $answer = get_persistent_answer('Before running VMware for the first time, you need to configure it for your running kernel by invoking the following command: "' . db_get_answer('BINDIR') . '/vmware-config.pl". Do you want this script to invoke the command for you now?', 'RUN_CONFIGURATOR', 'yesno', 'yes');
  1038.     db_save();
  1039.     if ($answer eq 'yes') {
  1040.       system(shell_string(db_get_answer('BINDIR') . '/vmware-config.pl'));
  1041.     } else {
  1042.       print wrap('Enjoy,' . "\n\n" . '    --the VMware team' . "\n\n", 0);
  1043.     }
  1044.  
  1045.     exit 0;
  1046.   }
  1047.   if (internal_basename($0) eq $cUninstallerFileName) {
  1048.     if (not (-e $cInstallDBFileName)) {
  1049.       error('Unable to find the tar installer database file (' . $cInstallDBFileName . ')' . "\n\n");
  1050.     }
  1051.     db_load();
  1052.  
  1053.     db_append();
  1054.     uninstall();
  1055.     db_save();
  1056.     print wrap('The removal of VMware ' . vmware_version() . ' for Linux completed successfully. Thank you for having tried this software.' . "\n\n", 0);
  1057.  
  1058.     exit 0;
  1059.   }
  1060.   error('This script must be named ' . $cInstallerFileName . ' or ' . $cUninstallerFileName . '.' . "\n\n");
  1061. }
  1062.  
  1063. main();
  1064.