jennnnnn

vmware-install.real.pl

Dec 15th, 2022
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 207.34 KB | None | 0 0
  1. #!/system/bin/perl -w
  2. # If your copy of perl is not in /usr/bin, please adjust the line above.
  3. #
  4. # Copyright (c) 1998-2016 VMware, Inc. All rights reserved.
  5. #
  6. # Tar package manager for VMware
  7.  
  8. use strict;
  9. use IO::Handle qw( ); # For autoflush
  10. STDOUT->autoflush(1);
  11.  
  12. # Use Config module to update VMware host-wide configuration file
  13. # BEGINNING_OF_CONFIG_DOT_PM
  14. # END_OF_CONFIG_DOT_PM
  15.  
  16. # BEGINNING_OF_UTIL_DOT_PL
  17. #!/usr/bin/perl
  18.  
  19. use strict;
  20. no warnings 'once'; # Warns about use of Config::Config in config.pl
  21.  
  22. my $have_thinprint='yes';
  23. my $have_vgauth='yes';
  24. my $have_caf='no';
  25. my $have_grabbitmqproxy='no';
  26.  
  27. # A list of known open-vm-tools packages
  28. #
  29. my @cOpenVMToolsRPMPackages = ("vmware-kmp-debug",
  30. "vmware-kmp-default",
  31. "vmware-kmp-pae",
  32. "vmware-kmp-trace",
  33. "vmware-guest-kmp-debug",
  34. "vmware-guest-kmp-default",
  35. "vmware-guest-kmp-desktop",
  36. "vmware-guest-kmp-pae",
  37. "open-vm-tools-gui",
  38. "open-vm-tools",
  39. "libvmtools-devel",
  40. "libvmtools0");
  41.  
  42. my @cOpenVMToolsDEBPackages = (
  43. "open-vm-dkms",
  44. "open-vm-source",
  45. "open-vm-toolbox",
  46. "open-vm-tools",
  47. "open-vm-tools-dbg",
  48. );
  49.  
  50. # Moved out of config.pl to support $gOption in spacechk_answer
  51. my %gOption;
  52. # Moved from various scripts that include util.pl
  53. my %gHelper;
  54.  
  55. #
  56. # All the known modules that the config.pl script needs to
  57. # know about. Modules in this list are searched for when
  58. # we check for non-vmware modules on the system.
  59. #
  60. my @cKernelModules = ('vmblock', 'vmhgfs', 'vmmemctl',
  61. 'vmxnet', 'vmci', 'vsock',
  62. 'vmsync', 'pvscsi', 'vmxnet3',
  63. 'vmwsvga');
  64.  
  65. #
  66. # This list simply defined what modules need to be included
  67. # in the system ramdisk when we rebuild it.
  68. #
  69. my %cRamdiskKernelModules = (vmxnet3 => 'yes',
  70. pvscsi => 'yes',
  71. vmxnet => 'yes');
  72. #
  73. # This defines module dependencies. It is a temporary solution
  74. # until we eventually move over to using the modules.xml file
  75. # to get our dependency information.
  76. #
  77. my %cKernelModuleDeps = (vsock => ('vmci'),
  78. vmhgfs => ('vmci'));
  79.  
  80. #
  81. # Module PCI ID and alias definitions.
  82. #
  83. my %cKernelModuleAliases = (
  84. # PCI IDs first
  85. 'pci:v000015ADd000007C0' => 'pvscsi',
  86. 'pci:v000015ADd00000740' => 'vmci',
  87. 'pci:v000015ADd000007B0' => 'vmxnet3',
  88. 'pci:v000015ADd00000720' => 'vmxnet',
  89. # Arbitrary aliases next
  90. 'vmware_vsock' => 'vsock',
  91. 'vmware_vmsync' => 'vmsync',
  92. 'vmware_vmmemctl' => 'vmmemctl',
  93. 'vmware_vmhgfs' => 'vmhgfs',
  94. 'vmware_vmblock' => 'vmblock',
  95. 'vmware_balloon' => 'vmmemctl',
  96. 'vmw_pvscsi' => 'pvscsi',
  97. );
  98.  
  99. #
  100. # Upstream module names and their corresponding internal module names.
  101. #
  102. my %cUpstrKernelModNames = (
  103. 'vmw_balloon' => 'vmmemctl',
  104. 'vmw_pvscsi' => 'pvscsi',
  105. 'vmw_vmxnet3' => 'vmxnet3',
  106. 'vmware_balloon' => 'vmmemctl',
  107. 'vmxnet3' => 'vmxnet3',
  108. );
  109.  
  110. #
  111. # Table mapping vmware_product() strings to applicable services script or
  112. # Upstart job name.
  113. #
  114.  
  115. my %cProductServiceTable = (
  116. 'nvdk' => 'nvdk',
  117. 'player' => 'vmware',
  118. 'tools-for-freebsd' => 'vmware-tools.sh',
  119. 'tools-for-linux' => 'vmware-tools',
  120. 'tools-for-solaris' => 'vmware-tools',
  121. 'vix-disklib' => 'vmware-vix-disklib',
  122. 'ws' => 'vmware',
  123. '@@VCLI_PRODUCT@@' => '@@VCLI_PRODUCT_PATH_NAME@@',
  124. );
  125.  
  126. my %cToolsLinuxServices;
  127. if ($have_thinprint eq 'yes') {
  128. %cToolsLinuxServices = (
  129. 'services' => 'vmware-tools',
  130. 'thinprint' => 'vmware-tools-thinprint',
  131. );
  132. } else {
  133. %cToolsLinuxServices = (
  134. 'services' => 'vmware-tools',
  135. );
  136. }
  137.  
  138. my %cToolsSolarisServices = (
  139. 'services' => 'vmware-tools',
  140. );
  141.  
  142. my %cToolsFreeBSDServices = (
  143. 'services' => 'vmware-tools.sh',
  144. );
  145.  
  146. #
  147. # Hashes to track vmware modules.
  148. #
  149. my %gNonVmwareModules = ();
  150. my %gVmwareInstalledModules = ();
  151. my %gVmwareRunningModules = ();
  152.  
  153. my $cTerminalLineSize = 79;
  154.  
  155. # Flags
  156. my $cFlagTimestamp = 0x1;
  157. my $cFlagConfig = 0x2;
  158. my $cFlagDirectoryMark = 0x4;
  159. my $cFlagUserModified = 0x8;
  160. my $cFlagFailureOK = 0x10;
  161.  
  162. # See vmware_service_issue_command
  163. my $cServiceCommandDirect = 0;
  164. my $cServiceCommandSystem = 1;
  165.  
  166. # Strings for Block Appends.
  167. my $cMarkerBegin = "# Beginning of the block added by the VMware software - DO NOT EDIT\n";
  168. my $cMarkerEnd = "# End of the block added by the VMware software\n";
  169. my $cDBAppendString = 'APPENDED_FILES';
  170.  
  171. # util.pl Globals
  172. my %gSystem;
  173.  
  174. # Needed to access $Config{...}, the Perl system configuration information.
  175. require Config;
  176.  
  177. # Tell if the user is the super user
  178. sub is_root {
  179. return $> == 0;
  180. }
  181.  
  182. # Use the Perl system configuration information to make a good guess about
  183. # the bit-itude of our platform. If we're running on Solaris we don't have
  184. # to guess and can just ask isainfo(1) how many bits userland is directly.
  185. sub is64BitUserLand {
  186. if (vmware_product() eq 'tools-for-solaris') {
  187. if (direct_command(shell_string($gHelper{'isainfo'}) . ' -b') =~ /64/) {
  188. return 1;
  189. } else {
  190. return 0;
  191. }
  192. }
  193. if ($Config::Config{archname} =~ /^(x86_64|amd64)-/) {
  194. return 1;
  195. } else {
  196. return 0;
  197. }
  198. }
  199.  
  200. # Return whether or not this is a hosted desktop product.
  201. sub isDesktopProduct {
  202. return vmware_product() eq "ws" || vmware_product() eq "player";
  203. }
  204.  
  205. sub isToolsProduct {
  206. return vmware_product() =~ /tools-for-/;
  207. }
  208.  
  209. # Call to specify lib suffix, mainly for FreeBSD tools where multiple versions
  210. # of the tools are packaged up in 32bit and 64bit instances. So rather than
  211. # simply lib or bin, there is lib32-6 or bin64-53, where -6 refers to FreeBSD
  212. # version 6.0 and 53 to FreeBSD 5.3.
  213. sub getFreeBSDLibSuffix {
  214. return getFreeBSDSuffix();
  215. }
  216.  
  217. # Call to specify lib suffix, mainly for FreeBSD tools where multiple versions
  218. # of the tools are packaged up in 32bit and 64bit instances. So rather than
  219. # simply lib or bin, there is lib32-6 or bin64-53, where -6 refers to FreeBSD
  220. # version 6.0 and 53 to FreeBSD 5.3.
  221. sub getFreeBSDBinSuffix {
  222. return getFreeBSDSuffix();
  223. }
  224.  
  225. # Call to specify lib suffix, mainly for FreeBSD tools where multiple versions
  226. # of the tools are packaged up in 32bit and 64bit instances. In the case of
  227. # sbin, a lib compatiblity between 5.0 and older systems appeared. Rather
  228. # than sbin32, which exists normally for 5.0 and older systems, there needs
  229. # to be a specific sbin: sbin32-5. There is no 64bit set.
  230. sub getFreeBSDSbinSuffix {
  231. my $suffix = '';
  232. my $release = `uname -r | cut -f1 -d-`;
  233. chomp($release);
  234. if (vmware_product() eq 'tools-for-freebsd' && $release == 5.0) {
  235. $suffix = '-5';
  236. } else {
  237. $suffix = getFreeBSDSuffix();
  238. }
  239. return $suffix;
  240. }
  241.  
  242. sub getFreeBSDSuffix {
  243. my $suffix = '';
  244.  
  245. # On FreeBSD, we ship different builds of binaries for different releases.
  246. #
  247. # For FreeBSD 6.0 and higher (which shipped new versions of libc) we use the
  248. # binaries located in the -6 directories.
  249. #
  250. # For releases between 5.3 and 6.0 (which were the first to ship with 64-bit
  251. # userland support) we use binaries from the -53 directories.
  252. #
  253. # For FreeBSD 5.0, we use binaries from the sbin32-5 directory.
  254. #
  255. # Otherwise, we just use the normal bin and sbin directories, which will
  256. # contain binaries predominantly built against 3.2.
  257. if (vmware_product() eq 'tools-for-freebsd') {
  258. my $release = `uname -r | cut -f1 -d-`;
  259. # Tools lowest supported FreeBSD version is now 6.1. Since the lowest
  260. # modules we ship are for 6.3, we will just use these instead. They are
  261. # suppoed to be binary compatible (hopefully).
  262. if ($release >= 6.0) {
  263. $suffix = '-63';
  264. } elsif ($release >= 5.3) {
  265. $suffix = '-53';
  266. } elsif ($release >= 5.0) {
  267. # sbin dir is a special case here and is handled within getFreeBSDSbinSuffix().
  268. $suffix = '';
  269. }
  270. }
  271.  
  272. return $suffix;
  273. }
  274.  
  275. # Determine what version of FreeBSD we're on and convert that to
  276. # install package values.
  277. sub getFreeBSDVersion {
  278. my $system_version = direct_command("sysctl kern.osrelease");
  279. if ($system_version =~ /: *([0-9]+\.[0-9]+)-/) {
  280. return "$1";
  281. }
  282.  
  283. # If we get here, we were unable to parse kern.osrelease
  284. return '';
  285. }
  286.  
  287. # Determine whether SELinux is enabled.
  288. sub is_selinux_enabled {
  289. if (-x "/usr/sbin/selinuxenabled") {
  290. my $rv = system("/usr/sbin/selinuxenabled");
  291. return ($rv eq 0);
  292. } else {
  293. return 0;
  294. }
  295. }
  296.  
  297. # Wordwrap system: append some content to the output
  298. sub append_output {
  299. my $output = shift;
  300. my $pos = shift;
  301. my $append = shift;
  302.  
  303. $output .= $append;
  304. $pos += length($append);
  305. if ($pos >= $cTerminalLineSize) {
  306. $output .= "\n";
  307. $pos = 0;
  308. }
  309.  
  310. return ($output, $pos);
  311. }
  312.  
  313. # Wordwrap system: deal with the next character
  314. sub wrap_one_char {
  315. my $output = shift;
  316. my $pos = shift;
  317. my $word = shift;
  318. my $char = shift;
  319. my $reserved = shift;
  320. my $length;
  321.  
  322. if (not (($char eq "\n") || ($char eq ' ') || ($char eq ''))) {
  323. $word .= $char;
  324.  
  325. return ($output, $pos, $word);
  326. }
  327.  
  328. # We found a separator. Process the last word
  329.  
  330. $length = length($word) + $reserved;
  331. if (($pos + $length) > $cTerminalLineSize) {
  332. # The last word doesn't fit in the end of the line. Break the line before
  333. # it
  334. $output .= "\n";
  335. $pos = 0;
  336. }
  337. ($output, $pos) = append_output($output, $pos, $word);
  338. $word = '';
  339.  
  340. if ($char eq "\n") {
  341. $output .= "\n";
  342. $pos = 0;
  343. } elsif ($char eq ' ') {
  344. if ($pos) {
  345. ($output, $pos) = append_output($output, $pos, ' ');
  346. }
  347. }
  348.  
  349. return ($output, $pos, $word);
  350. }
  351.  
  352. # Wordwrap system: word-wrap a string plus some reserved trailing space
  353. sub wrap {
  354. my $input = shift;
  355. my $reserved = shift;
  356. my $output;
  357. my $pos;
  358. my $word;
  359. my $i;
  360.  
  361. if (!defined($reserved)) {
  362. $reserved = 0;
  363. }
  364.  
  365. $output = '';
  366. $pos = 0;
  367. $word = '';
  368. for ($i = 0; $i < length($input); $i++) {
  369. ($output, $pos, $word) = wrap_one_char($output, $pos, $word,
  370. substr($input, $i, 1), 0);
  371. }
  372. # Use an artifical last '' separator to process the last word
  373. ($output, $pos, $word) = wrap_one_char($output, $pos, $word, '', $reserved);
  374.  
  375. return $output;
  376. }
  377.  
  378.  
  379. #
  380. # send_rpc_failed_msgs
  381. #
  382. # A place that gets called when the configurator/installer bails out.
  383. # this ensures that the all necessary RPC end messages are sent.
  384. #
  385. sub send_rpc_failed_msgs {
  386. send_rpc("toolinstall.installerActive 0");
  387. send_rpc('toolinstall.end 0');
  388. }
  389.  
  390.  
  391. # Print an error message and exit
  392. sub error {
  393. my $msg = shift;
  394.  
  395. # Ensure you send the terminating RPC message before you
  396. # unmount the CD.
  397. my $rpcresult = send_rpc('toolinstall.is_image_inserted');
  398. chomp($rpcresult);
  399.  
  400. # Send terminating RPC messages
  401. send_rpc_failed_msgs();
  402.  
  403. print STDERR wrap($msg . 'Execution aborted.' . "\n\n", 0);
  404.  
  405. # Now unmount the CD.
  406. if ("$rpcresult" =~ /1/) {
  407. eject_tools_install_cd_if_mounted();
  408. }
  409.  
  410. exit 1;
  411. }
  412.  
  413. # Convert a string to its equivalent shell representation
  414. sub shell_string {
  415. my $single_quoted = shift;
  416.  
  417. $single_quoted =~ s/'/'"'"'/g;
  418. # This comment is a fix for emacs's broken syntax-highlighting code
  419. return '\'' . $single_quoted . '\'';
  420. }
  421.  
  422. # Send an arbitrary RPC command to the VMX
  423. sub send_rpc {
  424. my $command = shift;
  425. my $rpctoolSuffix;
  426. my $rpctoolBinary = '';
  427. my $libDir;
  428. my @rpcResultLines;
  429.  
  430.  
  431. if (vmware_product() eq 'tools-for-solaris') {
  432. $rpctoolSuffix = is64BitUserLand() ? '/sbin/amd64' : '/sbin/i86';
  433. } else {
  434. $rpctoolSuffix = is64BitUserLand() ? '/sbin64' : '/sbin32';
  435. }
  436.  
  437. $rpctoolSuffix .= getFreeBSDSbinSuffix() . '/vmware-rpctool';
  438.  
  439. # We don't yet know if vmware-rpctool was copied into place.
  440. # Let's first try getting the location from the DB.
  441. $libDir = db_get_answer_if_exists('LIBDIR');
  442. if (defined($libDir)) {
  443. $rpctoolBinary = $libDir . $rpctoolSuffix;
  444. }
  445. if (not (-x "$rpctoolBinary")) {
  446. # The DB didn't help. But no matter, we can
  447. # extract a path to the untarred tarball installer from our
  448. # current location. With that info, we can invoke the
  449. # rpc tool directly out of the staging area. Woot!
  450. $rpctoolBinary = "./lib" . $rpctoolSuffix;
  451. }
  452.  
  453. # If we found the binary, send the RPC.
  454. if (-x "$rpctoolBinary") {
  455. open (RPCRESULT, shell_string($rpctoolBinary) . " " .
  456. shell_string($command) . ' 2> /dev/null |');
  457.  
  458. @rpcResultLines = <RPCRESULT>;
  459. close RPCRESULT;
  460. return (join("\n", @rpcResultLines));
  461. } else {
  462. # Return something so we don't get any undef errors.
  463. return '';
  464. }
  465. }
  466.  
  467. # chmod() that reports errors
  468. sub safe_chmod {
  469. my $mode = shift;
  470. my $file = shift;
  471.  
  472. if (chmod($mode, $file) != 1) {
  473. error('Unable to change the access rights of the file ' . $file . '.'
  474. . "\n\n");
  475. }
  476. }
  477.  
  478. # Create a temporary directory
  479. #
  480. # They are a lot of small utility programs to create temporary files in a
  481. # secure way, but none of them is standard. So I wrote this
  482. sub make_tmp_dir {
  483. my $prefix = shift;
  484. my $tmp;
  485. my $serial;
  486. my $loop;
  487.  
  488. $tmp = defined($ENV{'TMPDIR'}) ? $ENV{'TMPDIR'} : '/tmp';
  489.  
  490. # Don't overwrite existing user data
  491. # -> Create a directory with a name that didn't exist before
  492. #
  493. # This may never succeed (if we are racing with a malicious process), but at
  494. # least it is secure
  495. $serial = 0;
  496. for (;;) {
  497. # Check the validity of the temporary directory. We do this in the loop
  498. # because it can change over time
  499. if (not (-d $tmp)) {
  500. error('"' . $tmp . '" is not a directory.' . "\n\n");
  501. }
  502. if (not ((-w $tmp) && (-x $tmp))) {
  503. error('"' . $tmp . '" should be writable and executable.' . "\n\n");
  504. }
  505.  
  506. # Be secure
  507. # -> Don't give write access to other users (so that they can not use this
  508. # directory to launch a symlink attack)
  509. if (mkdir($tmp . '/' . $prefix . $serial, 0755)) {
  510. last;
  511. }
  512.  
  513. $serial++;
  514. if ($serial % 200 == 0) {
  515. print STDERR 'Warning: The "' . $tmp . '" directory may be under attack.' . "\n\n";
  516. }
  517. }
  518.  
  519. return $tmp . '/' . $prefix . $serial;
  520. }
  521.  
  522.  
  523. # Call restorecon on the supplied file if selinux is enabled
  524. sub restorecon {
  525. my $file = shift;
  526.  
  527. if (is_selinux_enabled()) {
  528. # we suppress warnings from restorecon. bug #1008386:
  529. system("/sbin/restorecon 2>/dev/null " . $file);
  530. # Return a 1, restorecon was called.
  531. return 1;
  532. }
  533.  
  534. # If it is not enabled, return a -1, restorecon was NOT called.
  535. return -1;
  536. }
  537.  
  538. # Append a clearly delimited block to an unstructured text file
  539. # Result:
  540. # 1 on success
  541. # -1 on failure
  542. sub block_append {
  543. my $file = shift;
  544. my $begin = shift;
  545. my $block = shift;
  546. my $end = shift;
  547.  
  548. if (not open(BLOCK, '>>' . $file)) {
  549. return -1;
  550. }
  551.  
  552. print BLOCK $begin . $block . $end;
  553.  
  554. if (not close(BLOCK)) {
  555. # Even if close fails, make sure to call restorecon.
  556. restorecon($file);
  557. return -1;
  558. }
  559.  
  560. # Call restorecon to set SELinux policy for this file.
  561. restorecon($file);
  562. return 1;
  563. }
  564.  
  565. # Append a clearly delimited block to an unstructured text file
  566. # and add this file to an "answer" entry in the locations db
  567. #
  568. # Result:
  569. # 1 on success
  570. # -1 on failure
  571. sub block_append_with_db_answer_entry {
  572. my $file = shift;
  573. my $block = shift;
  574.  
  575. return -1 if (block_append($file, $cMarkerBegin, $block, $cMarkerEnd) < 0);
  576.  
  577. # get the list of already-appended files
  578. my $list = db_get_answer_if_exists($cDBAppendString);
  579.  
  580. # No need to check if there's anything in the list because
  581. # db_add_answer removes the existing answer with the same name
  582. if ($list) {
  583. $list = join(':', $list, $file);
  584. } else {
  585. $list = $file;
  586. }
  587. db_add_answer($cDBAppendString, $list);
  588.  
  589. return 1;
  590. }
  591.  
  592.  
  593. # Insert a clearly delimited block to an unstructured text file
  594. #
  595. # Uses a regexp to find a particular spot in the file and adds
  596. # the block at the first regexp match.
  597. #
  598. # Result:
  599. # 1 on success
  600. # 0 on no regexp match (nothing added)
  601. # -1 on failure
  602. sub block_insert {
  603. my $file = shift;
  604. my $regexp = shift;
  605. my $begin = shift;
  606. my $block = shift;
  607. my $end = shift;
  608. my $line_added = 0;
  609. my $tmp_dir = make_tmp_dir('vmware-block-insert');
  610. my $tmp_file = $tmp_dir . '/tmp_file';
  611.  
  612. if (not open(BLOCK_IN, '<' . $file) or
  613. not open(BLOCK_OUT, '>' . $tmp_file)) {
  614. return -1;
  615. }
  616.  
  617. foreach my $line (<BLOCK_IN>) {
  618. if ($line =~ /($regexp)/ and not $line_added) {
  619. print BLOCK_OUT $begin . $block . $end;
  620. $line_added = 1;
  621. }
  622. print BLOCK_OUT $line;
  623. }
  624.  
  625. if (not close(BLOCK_IN) or not close(BLOCK_OUT)) {
  626. return -1;
  627. }
  628.  
  629. if (not system(shell_string($gHelper{'mv'}) . " $tmp_file $file")) {
  630. return -1;
  631. }
  632.  
  633. remove_tmp_dir($tmp_dir);
  634.  
  635. # Call restorecon to set SELinux policy for this file.
  636. restorecon($file);
  637.  
  638. # Our return status is 1 if successful, 0 if nothing was added.
  639. return $line_added
  640. }
  641.  
  642.  
  643. # Test if specified file contains line matching regular expression
  644. # Result:
  645. # undef on failure
  646. # first matching line on success
  647. sub block_match {
  648. my $file = shift;
  649. my $block = shift;
  650. my $line = undef;
  651.  
  652. if (open(BLOCK, '<' . $file)) {
  653. while (defined($line = <BLOCK>)) {
  654. chomp $line;
  655. last if ($line =~ /$block/);
  656. }
  657. close(BLOCK);
  658. }
  659. return defined($line);
  660. }
  661.  
  662.  
  663. # Remove all clearly delimited blocks from an unstructured text file
  664. # Result:
  665. # >= 0 number of blocks removed on success
  666. # -1 on failure
  667. sub block_remove {
  668. my $src = shift;
  669. my $dst = shift;
  670. my $begin = shift;
  671. my $end = shift;
  672. my $count;
  673. my $state;
  674.  
  675. if (not open(SRC, '<' . $src)) {
  676. return -1;
  677. }
  678.  
  679. if (not open(DST, '>' . $dst)) {
  680. close(SRC);
  681. return -1;
  682. }
  683.  
  684. $count = 0;
  685. $state = 'outside';
  686. while (<SRC>) {
  687. if ($state eq 'outside') {
  688. if ($_ eq $begin) {
  689. $state = 'inside';
  690. $count++;
  691. } else {
  692. print DST $_;
  693. }
  694. } elsif ($state eq 'inside') {
  695. if ($_ eq $end) {
  696. $state = 'outside';
  697. }
  698. }
  699. }
  700.  
  701. if (not close(DST)) {
  702. close(SRC);
  703. # Even if close fails, make sure to call restorecon on $dst.
  704. restorecon($dst);
  705. return -1;
  706. }
  707.  
  708. # $dst file has been modified, call restorecon to set the
  709. # SELinux policy for it.
  710. restorecon($dst);
  711.  
  712. if (not close(SRC)) {
  713. return -1;
  714. }
  715.  
  716. return $count;
  717. }
  718.  
  719. # Similar to block_remove(). Find the delimited text, bracketed by $begin and $end,
  720. # and filter it out as the file is written out to a tmp file. Typicaly, block_remove()
  721. # is used in the pattern: create tmp dir, create tmp file, block_remove(), mv file,
  722. # remove tmp dir. This encapsulates the pattern.
  723. sub block_restore {
  724. my $src_file = shift;
  725. my $begin_marker = shift;
  726. my $end_marker = shift;
  727. my $tmp_dir = make_tmp_dir('vmware-block-restore');
  728. my $tmp_file = $tmp_dir . '/tmp_file';
  729. my $rv;
  730. my @sb;
  731.  
  732. @sb = stat($src_file);
  733.  
  734. $rv = block_remove($src_file, $tmp_file, $begin_marker, $end_marker);
  735. if ($rv >= 0) {
  736. system(shell_string($gHelper{'mv'}) . ' ' . $tmp_file . ' ' . $src_file);
  737. safe_chmod($sb[2], $src_file);
  738. }
  739. remove_tmp_dir($tmp_dir);
  740.  
  741. # Call restorecon on the source file.
  742. restorecon($src_file);
  743.  
  744. return $rv;
  745. }
  746.  
  747.  
  748. # Remove leading and trailing whitespaces
  749. sub remove_whitespaces {
  750. my $string = shift;
  751.  
  752. $string =~ s/^\s*//;
  753. $string =~ s/\s*$//;
  754. return $string;
  755. }
  756.  
  757. # Ask a question to the user and propose an optional default value
  758. # Use this when you don't care about the validity of the answer
  759. sub query {
  760. my $message = shift;
  761. my $defaultreply = shift;
  762. my $reserved = shift;
  763. my $reply;
  764. my $default_value = $defaultreply eq '' ? '' : ' [' . $defaultreply . ']';
  765. my $terse = 'no';
  766.  
  767. # Allow the script to limit output in terse mode. Usually dictated by
  768. # vix in a nested install and the '--default' option.
  769. if (db_get_answer_if_exists('TERSE')) {
  770. $terse = db_get_answer('TERSE');
  771. if ($terse eq 'yes') {
  772. $reply = remove_whitespaces($defaultreply);
  773. return $reply;
  774. }
  775. }
  776.  
  777. # Reserve some room for the reply
  778. print wrap($message . $default_value, 1 + $reserved);
  779.  
  780. # This is what the 1 is for
  781. print ' ';
  782.  
  783. if ($gOption{'default'} == 1) {
  784. # Simulate the enter key
  785. print "\n";
  786. $reply = '';
  787. } else {
  788. $reply = <STDIN>;
  789. $reply = '' unless defined($reply);
  790. chomp($reply);
  791. }
  792.  
  793. print "\n";
  794. $reply = remove_whitespaces($reply);
  795. if ($reply eq '') {
  796. $reply = $defaultreply;
  797. }
  798. return $reply;
  799. }
  800.  
  801. # Execute the command passed as an argument
  802. # _without_ interpolating variables (Perl does it by default)
  803. sub direct_command {
  804. return `$_[0]`;
  805. }
  806.  
  807. # If there is a pid for this process, consider it running.
  808. sub check_is_running {
  809. my $proc_name = shift;
  810. my $rv = system(shell_string($gHelper{'pidof'}) . " " . $proc_name . " > /dev/null");
  811. return $rv eq 0;
  812. }
  813.  
  814.  
  815. # OS-independent method of unloading a kernel module by name
  816. # Returns true (non-zero) if the operation succeeded, false otherwise.
  817. sub kmod_unload {
  818. my $modname = shift; # IN: Module name
  819. my $doRecursive = shift; # IN: Whether to also try loading modules that
  820. # become unused as a result of unloading $modname
  821.  
  822. if (defined($gHelper{'modprobe'})
  823. && defined($doRecursive) && $doRecursive) { # Linux (with $doRecursive)
  824. return !system(shell_string($gHelper{'modprobe'}) . ' -r ' . shell_string($modname)
  825. . ' >/dev/null 2>&1');
  826. } elsif (defined($gHelper{'rmmod'})) { # Linux (otherwise)
  827. return !system(shell_string($gHelper{'rmmod'}) . ' ' . shell_string($modname)
  828. . ' >/dev/null 2>&1');
  829. } elsif (defined($gHelper{'kldunload'})) { # FreeBSD
  830. return !system(shell_string($gHelper{'kldunload'}) . ' ' . shell_string($modname)
  831. . ' >/dev/null 2>&1');
  832. } elsif (defined($gHelper{'modunload'})) { # Solaris
  833. # Solaris won't let us unload by module name, so we have to find the ID from modinfo
  834. my $aline;
  835. my @lines = split('\n', direct_command(shell_string($gHelper{'modinfo'})));
  836.  
  837. foreach $aline (@lines) {
  838. chomp($aline);
  839. my($amodid, $dummy2, $dummy3, $dummy4, $dummy5, $amodname) = split(/\s+/, $aline);
  840.  
  841. if ($modname eq $amodname) {
  842. return !system(shell_string($gHelper{'modunload'}) . ' -i ' . $amodid
  843. . ' >/dev/null 2>&1');
  844. }
  845. }
  846.  
  847. return 0; # Failure - module not found
  848. }
  849.  
  850. return 0; # Failure
  851. }
  852.  
  853. # Emulate a simplified ls program for directories
  854. sub internal_ls {
  855. my $dir = shift;
  856. my @fn;
  857.  
  858. opendir(LS, $dir) or return ();
  859. @fn = grep(!/^\.\.?$/, readdir(LS));
  860. closedir(LS);
  861.  
  862. return @fn;
  863. }
  864.  
  865.  
  866. # Emulate a simplified dirname program
  867. sub internal_dirname {
  868. my $path = shift;
  869. my $pos;
  870.  
  871. $path = dir_remove_trailing_slashes($path);
  872.  
  873. $pos = rindex($path, '/');
  874. if ($pos == -1) {
  875. # No slash
  876. return '.';
  877. }
  878.  
  879. if ($pos == 0) {
  880. # The only slash is at the beginning
  881. return '/';
  882. }
  883.  
  884. return substr($path, 0, $pos);
  885. }
  886.  
  887. #
  888. # unconfigure_autostart_legacy --
  889. #
  890. # Remove VMware-added blocks relating to vmware-user autostart from
  891. # pre-XDG resource files, scripts, etc.
  892. #
  893. # Results:
  894. # OpenSuSE: Revert xinitrc.common.
  895. # Debian/Ubuntu: Remove script from Xsession.d.
  896. # xdm: Revert xdm-config(s).
  897. # gdm: None. (gdm mechanism used install_symlink, so that will be
  898. # cleaned up separately.)
  899. #
  900. # Side effects:
  901. # None.
  902. #
  903.  
  904. sub unconfigure_autostart_legacy {
  905. my $markerBegin = shift; # IN: block begin marker
  906. my $markerEnd = shift; # IN: block end marker
  907.  
  908. if (!defined($markerBegin) || !defined($markerEnd)) {
  909. return;
  910. }
  911.  
  912. my $chompedMarkerBegin = $markerBegin; # block_match requires chomped markers
  913. chomp($chompedMarkerBegin);
  914.  
  915. #
  916. # OpenSuSE (xinitrc.common)
  917. #
  918. my $xinitrcCommon = '/etc/X11/xinit/xinitrc.common';
  919. if (-f $xinitrcCommon && block_match($xinitrcCommon, $chompedMarkerBegin)) {
  920. block_restore($xinitrcCommon, $markerBegin, $markerEnd);
  921. }
  922.  
  923. #
  924. # Debian (Xsession.d) - We forgot to simply call db_add_file() after
  925. # creating this one.
  926. #
  927. my $dotdScript = '/etc/X11/Xsession.d/99-vmware_vmware-user';
  928. if (-f $dotdScript && !db_file_in($dotdScript)) {
  929. unlink($dotdScript);
  930. }
  931.  
  932. #
  933. # xdm
  934. #
  935. my @xdmcfgs = ("/etc/X11/xdm/xdm-config");
  936. my $x11Base = db_get_answer_if_exists('X11DIR');
  937. if (defined($x11Base)) {
  938. push(@xdmcfgs, "$x11Base/lib/X11/xdm/xdm-config");
  939. }
  940. foreach (@xdmcfgs) {
  941. if (-f $_ && block_match($_, "!$chompedMarkerBegin")) {
  942. block_restore($_, "!$markerBegin", "!$markerEnd");
  943. }
  944. }
  945. }
  946.  
  947. # Check a mountpoint to see if it hosts the guest tools install iso.
  948. sub check_mountpoint_for_tools {
  949. my $mountpoint = shift;
  950. my $foundit = 0;
  951.  
  952. if (vmware_product() eq 'tools-for-solaris') {
  953. if ($mountpoint =~ /vmwaretools$/ ||
  954. $mountpoint =~ /\/media\/VMware Tools$/) {
  955. $foundit = 1;
  956. }
  957. } elsif (opendir CDROMDIR, $mountpoint) {
  958. my @dircontents = readdir CDROMDIR;
  959. foreach my $entry ( @dircontents ) {
  960. if (vmware_product() eq 'tools-for-linux') {
  961. if ($entry =~ /VMwareTools-.*\.tar\.gz$/) {
  962. $foundit = 1;
  963. }
  964. } elsif (vmware_product() eq 'tools-for-freebsd') {
  965. if ($entry =~ /vmware-freebsd-tools\.tar\.gz$/) {
  966. $foundit = 1;
  967. }
  968. }
  969. }
  970. closedir(CDROMDIR);
  971. }
  972. return $foundit;
  973. }
  974.  
  975. # Try to eject the guest tools install cd so the user doesn't have to manually.
  976. sub eject_tools_install_cd_if_mounted {
  977. # TODO: Add comments to the other code which generates the filenames
  978. # and volumeids which this code is now dependent upon.
  979. my @candidate_mounts;
  980. my $device;
  981. my $mountpoint;
  982. my $fstype;
  983. my $rest;
  984. my $eject_cmd = '';
  985. my $eject_failed = 0;
  986. my $eject_really_failed = 0;
  987.  
  988. # For each architecture, first collect a list of mounted cdroms.
  989. if (vmware_product() eq 'tools-for-linux') {
  990. $eject_cmd = internal_which('eject');
  991. if (open(MOUNTS, '</proc/mounts')) {
  992. while (<MOUNTS>) {
  993. ($device, $mountpoint, $fstype, $rest) = split;
  994. # note: /proc/mounts replaces spaces with \040
  995. $device =~ s/\\040/\ /g;
  996. $mountpoint =~ s/\\040/\ /g;
  997. if ($fstype eq "iso9660" && $device !~ /loop/ ) {
  998. push(@candidate_mounts, "${device}::::${mountpoint}");
  999. }
  1000. }
  1001. close(MOUNTS);
  1002. }
  1003. } elsif (vmware_product() eq 'tools-for-freebsd' and
  1004. -x internal_which('mount')) {
  1005. $eject_cmd = internal_which('cdcontrol') . " eject";
  1006. my @mountlines = split('\n', direct_command(internal_which('mount')));
  1007. foreach my $mountline (@mountlines) {
  1008. chomp($mountline);
  1009. if ($mountline =~ /^(.+)\ on\ (.+)\ \(([0-9a-zA-Z]+),/) {
  1010. $device = $1;
  1011. $mountpoint = $2;
  1012. $fstype = $3;
  1013.  
  1014. # If the device begins with /dev/md it will most likely
  1015. # be the equivalent of a loopback mount in linux.
  1016. if ($fstype eq "cd9660" && $device !~ /^\/dev\/md/) {
  1017. push(@candidate_mounts, "${device}::::${mountpoint}");
  1018. }
  1019. }
  1020. }
  1021. } elsif (vmware_product() eq 'tools-for-solaris') {
  1022. $eject_cmd = internal_which('eject');
  1023. # If this fails, don't bother trying to unmount, or error.
  1024. if (open(MNTTAB, '</etc/mnttab')) {
  1025. while (<MNTTAB>) {
  1026. ($device, $rest) = split("\t", $_);
  1027. # I don't think there are actually ever comments in /etc/mnttab.
  1028. next if $device =~ /^#/;
  1029. if ($device =~ /vmwaretools$/ ||
  1030. $rest =~ /\/media\/VMware Tools$/) {
  1031. $mountpoint = $rest;
  1032. $mountpoint =~ s/(.*)\s+hsfs.*/$1/;
  1033. push(@candidate_mounts, "${device}::::${mountpoint}");
  1034. }
  1035. }
  1036. close(MNTTAB);
  1037. }
  1038. }
  1039.  
  1040. # For each mounted cdrom, check if it's vmware guest tools installer,
  1041. # and if so, try to eject it, then verify.
  1042. foreach my $candidate_mount (@candidate_mounts) {
  1043. ($device, $mountpoint) = split('::::',$candidate_mount);
  1044. if (check_mountpoint_for_tools($mountpoint)) {
  1045. print wrap("Found VMware Tools CDROM mounted at " .
  1046. "${mountpoint}. Ejecting device $device ...\n");
  1047.  
  1048. # Freebsd doesn't auto unmount along with eject.
  1049. if (vmware_product() eq 'tools-for-freebsd' and
  1050. -x internal_which('umount')) {
  1051. # If this fails, the eject will fail, and the user will see
  1052. # the appropriate output.
  1053. direct_command(internal_which('umount') .
  1054. ' "' . $device . '"');
  1055. }
  1056. my @output = ();
  1057. if ($eject_cmd ne '') {
  1058. open(CMDOUTPUT, "$eject_cmd $device 2>&1 |");
  1059. @output = <CMDOUTPUT>;
  1060. close(CMDOUTPUT);
  1061. $eject_failed = $?;
  1062. } else {
  1063. $eject_failed = 1;
  1064. }
  1065.  
  1066. # For unknown reasons, eject can succeed, but return error, so
  1067. # double check that it really failed before showing the output to
  1068. # the user. For more details see bug170327.
  1069. if ($eject_failed && check_mountpoint_for_tools($mountpoint)) {
  1070. foreach my $outputline (@output) {
  1071. print wrap ($outputline, 0);
  1072. }
  1073.  
  1074. # $eject_really_failed ensures this message is not printed
  1075. # multiple times.
  1076. if (not $eject_really_failed) {
  1077. if ($eject_cmd eq '') {
  1078. print wrap ("No eject (or equivilant) command could be " .
  1079. "located.\n");
  1080. }
  1081. print wrap ("Eject Failed: If possible manually eject the " .
  1082. "Tools installer from the guest cdrom mounted " .
  1083. "at $mountpoint before canceling tools install " .
  1084. "on the host.\n", 0);
  1085.  
  1086. $eject_really_failed = 1;
  1087. }
  1088. }
  1089. }
  1090. }
  1091. }
  1092.  
  1093.  
  1094. # Compares variable length version strings against one another.
  1095. # Returns 1 if the first version is greater, -1 if the second
  1096. # version is greater, or 0 if they are equal.
  1097. sub dot_version_compare {
  1098. my $str1 = shift;
  1099. my $str2 = shift;
  1100.  
  1101. if ("$str1" eq '' or "$str2" eq '') {
  1102. if ("$str1" eq '' and "$str2" eq '') {
  1103. return 0;
  1104. } else {
  1105. return (("$str1" eq '') ? -1 : 1);
  1106. }
  1107. }
  1108.  
  1109. if ("$str1" =~ /[^0-9\.]+/ or "$str2" =~ /[^0-9\.]+/) {
  1110. error("Bad character detected in dot_version_compare.\n");
  1111. }
  1112.  
  1113. my @arr1 = split(/\./, "$str1");
  1114. my @arr2 = split(/\./, "$str2");
  1115. my $indx = 0;
  1116. while(1) {
  1117. if (!defined $arr1[$indx] and !defined $arr2[$indx]) {
  1118. return 0;
  1119. }
  1120.  
  1121. $arr1[$indx] = 0 if not defined $arr1[$indx];
  1122. $arr2[$indx] = 0 if not defined $arr2[$indx];
  1123.  
  1124. if ($arr1[$indx] != $arr2[$indx]) {
  1125. return (($arr1[$indx] > $arr2[$indx]) ? 1 : -1);
  1126. }
  1127. $indx++;
  1128. }
  1129. error("NOT REACHED IN DOT_VERSION_COMPARE\n");
  1130. }
  1131.  
  1132.  
  1133. # Returns the tuple ($halScript, $halName) if the system
  1134. # has scripts to control HAL.
  1135. #
  1136. sub get_hal_script_name {
  1137. my $initDir = shell_string(db_get_answer('INITSCRIPTSDIR'));
  1138. $initDir =~ s/\'//g; # Remove quotes
  1139.  
  1140. my @halguesses = ("haldaemon", "hal");
  1141. my $halScript = undef;
  1142. my $halName = undef;
  1143.  
  1144. # Attempt to find the init script for the HAL service.
  1145. # It should be one of the names in our list of guesses.
  1146. foreach my $hname (@halguesses) {
  1147. if (-f "$initDir/$hname") {
  1148. $halScript = "$initDir/$hname";
  1149. $halName = "$hname";
  1150. }
  1151. }
  1152.  
  1153. if (vmware_product() eq 'tools-for-solaris') {
  1154. # In Solaris 11, use svcadm to handle HAL.
  1155. # XXX: clean this up on main.
  1156. my $svcadmBin = internal_which('svcadm');
  1157. if (system("$svcadmBin refresh hal >/dev/null 2>&1") eq 0) {
  1158. $halScript = 'svcadm';
  1159. $halName = 'hal';
  1160. }
  1161. }
  1162.  
  1163. return ($halScript, $halName);
  1164. }
  1165.  
  1166. sub restart_hal {
  1167. my $servicePath = internal_which("service");
  1168. my $halScript = undef;
  1169. my $halName = undef;
  1170.  
  1171. ($halScript, $halName) = get_hal_script_name();
  1172.  
  1173. # Hald does time stamp based cache obsolescence check, and it won't
  1174. # reload new fdi if it has cache file with future timestamp.
  1175. # Let's cleanup the cache file before restarting hald to get around
  1176. # this problem.
  1177. unlink('/var/cache/hald/fdi-cache');
  1178.  
  1179. if ($halScript eq 'svcadm') {
  1180. # Solaris svcadm.
  1181. my $svcadmBin = internal_which('svcadm');
  1182. system("$svcadmBin restart hal");
  1183. } elsif (-d '/etc/init' and $servicePath ne '' and defined($halName)) {
  1184. # Upstart case.
  1185. system("$servicePath $halName restart");
  1186. } elsif (defined($halScript)) {
  1187. # Traditional init script restart case.
  1188. system($halScript . ' restart');
  1189. } else {
  1190. print "Could not locate hal daemon init script.\n";
  1191. }
  1192. }
  1193.  
  1194.  
  1195. ##
  1196. # locate_upstart_jobinfo
  1197. #
  1198. # Determine whether Upstart is supported, and if so, return the path in which
  1199. # Upstart jobs should be installed and any job file suffix.
  1200. #
  1201. # @retval ($path, $suffix) Path containing Upstart jobs, job suffix (ex: .conf).
  1202. # @retval () Upstart unsupported or unable to determine job path.
  1203. #
  1204.  
  1205. sub locate_upstart_jobinfo() {
  1206. my $initctl = internal_which('initctl');
  1207. my $retval;
  1208.  
  1209. # bug #1423141
  1210. delete $ENV{'UPSTART_SESSION'};
  1211.  
  1212. if ($have_thinprint eq 'yes') {
  1213. # we cannot use upstart unless cups also uses upstart, otherwise we
  1214. # cannot make sure that tp starts after cups.
  1215. if ( glob(db_get_answer('INITDIR') . '/rc2.d/' . 'S??cups*' ) and (not -e '/etc/init/cups.conf') ) {
  1216. return ();
  1217. }
  1218. }
  1219. # Don't bother checking directories unless initctl is available and
  1220. # indicates that Upstart is active.
  1221. if ($initctl ne '' and ( -x $initctl )) {
  1222. my $initctl_version_string = direct_command(shell_string($initctl) . " version 2> /dev/null");
  1223. if (($initctl_version_string =~ /upstart ([\d\.]+)/) and
  1224. # XXX Fix dot_version_compare to support a comparison like 0.6.5 to 0.6.
  1225. (dot_version_compare($1, "0.6.0") >= 0)) {
  1226. my $jobPath = "/etc/init";
  1227. if ( -d $jobPath ) {
  1228. my $suffix = "";
  1229.  
  1230. foreach my $testSuffix (".conf") {
  1231. if (glob ("$jobPath/*$testSuffix")) {
  1232. $suffix = $testSuffix;
  1233. last;
  1234. }
  1235. }
  1236.  
  1237. return ($jobPath, $suffix);
  1238. }
  1239. }
  1240. }
  1241.  
  1242. return ();
  1243. }
  1244.  
  1245.  
  1246. ##
  1247. # vmware_service_basename
  1248. #
  1249. # Simple product name -> service script map accessor. (See
  1250. # $cProductServiceTable.)
  1251. #
  1252. # @return Service script basename on valid product, undef otherwise.
  1253. #
  1254. sub vmware_service_basename {
  1255. return $cProductServiceTable{vmware_product()};
  1256. }
  1257.  
  1258.  
  1259. ##
  1260. # vmware_service_path
  1261. #
  1262. # @return Valid service script's path relative to INITSCRIPTSDIR unless
  1263. # vmware_product() has no such script.
  1264. #
  1265.  
  1266. sub vmware_service_path {
  1267. my $basename = vmware_service_basename();
  1268.  
  1269. return $basename
  1270. ? join('/', db_get_answer('INITSCRIPTSDIR'), $basename)
  1271. : undef;
  1272. }
  1273.  
  1274. ##
  1275. # vmware_service_issue_command1
  1276. #
  1277. # Executes a VMware services script, determined by locations database contents
  1278. # and product type, with a single command parameter.
  1279. #
  1280. # @param[in] $useSystem If true, uses system(). Else uses direct_command().
  1281. # @param[in] $service the name of the service
  1282. # @param[in] @commands List of commands passed to services script or initctl
  1283. # (ex: start, stop, status vm).
  1284. #
  1285. # @returns Return value from system() or direct_command().
  1286. #
  1287.  
  1288. sub vmware_service_issue_command1 {
  1289. my $useSystem = shift;
  1290. my $service = shift;
  1291. my @argv;
  1292. my @escapedArgv;
  1293. my $cmd;
  1294.  
  1295. # Upstart/initctl case.
  1296. if (db_get_answer_if_exists('UPSTARTJOB')) {
  1297. my $initctl = internal_which('initctl');
  1298.  
  1299. error("ASSERT: Failed to determine my service name.\n") unless defined $service;
  1300.  
  1301. @argv = ($initctl, @_, $service);
  1302.  
  1303. # Legacy SYSV style.
  1304. } else {
  1305. @argv = (join('/', db_get_answer('INITSCRIPTSDIR'), $service), @_);
  1306. }
  1307.  
  1308. # Escape parameters, then join by a single space.
  1309. foreach (@argv) {
  1310. push(@escapedArgv, shell_string($_));
  1311. }
  1312. $cmd = join(' ', @escapedArgv);
  1313.  
  1314. # bug #1423141
  1315. delete $ENV{'UPSTART_SESSION'};
  1316.  
  1317. return $useSystem ? system($cmd) : direct_command($cmd);
  1318. }
  1319.  
  1320. ##
  1321. # vmware_service_issue_command
  1322. #
  1323. # Executes a VMware services script, determined by locations database contents
  1324. # and product type, with a single command parameter.
  1325. #
  1326. # @param[in] $useSystem If true, uses system(). Else uses direct_command().
  1327. # @param[in] @commands List of commands passed to services script or initctl
  1328. # (ex: start, stop, status vm).
  1329. #
  1330. # @returns Return value from system() or direct_command().
  1331. #
  1332.  
  1333. sub vmware_service_issue_command {
  1334. my $useSystem = shift;
  1335. my @argv = @_;
  1336. my $service = vmware_service_basename();
  1337.  
  1338. return vmware_service_issue_command1($useSystem, $service, @argv);
  1339. }
  1340.  
  1341.  
  1342.  
  1343. sub vmware_services_table()
  1344. {
  1345. my $product = vmware_product();
  1346.  
  1347. if ($product eq 'tools-for-linux') {
  1348. return \%cToolsLinuxServices;
  1349. } elsif ($product eq 'tools-for-freebsd') {
  1350. return \%cToolsFreeBSDServices;
  1351. } elsif ($product eq 'tools-for-solaris') {
  1352. return \%cToolsSolarisServices;
  1353. }
  1354.  
  1355. error("$product not implemented in vmware_services_table()\n.");
  1356. }
  1357.  
  1358.  
  1359. ##
  1360. # removeDuplicateEntries
  1361. #
  1362. # Removes duplicate entries from a given string and delimeter
  1363. # @param - string to cleanse
  1364. # @param - the delimeter
  1365. # @returns - String without duplicate entries.
  1366. #
  1367. sub removeDuplicateEntries {
  1368. my $string = shift;
  1369. my $delim = shift;
  1370. my $newStr = '';
  1371.  
  1372. if (not defined $string or not defined $delim) {
  1373. error("Missing parameters in removeDuplicateEntries\n.");
  1374. }
  1375.  
  1376. foreach my $subStr (split($delim, $string)) {
  1377. if ($newStr !~ /(^|$delim)$subStr($delim|$)/ and $subStr ne '') {
  1378. if ($newStr ne '') {
  1379. $newStr = join($delim, $newStr, $subStr);
  1380. } else {
  1381. $newStr = $subStr;
  1382. }
  1383. }
  1384. }
  1385.  
  1386. return $newStr;
  1387. }
  1388.  
  1389.  
  1390. ##
  1391. # internalMv
  1392. #
  1393. # mv command for Perl that works across file system boundaries. The rename
  1394. # function may not work across FS boundaries and I don't want to introduce
  1395. # a dependency on File::Copy (at least not with this installer/configurator).
  1396. #
  1397. sub internalMv {
  1398. my $src = shift;
  1399. my $dst = shift;
  1400. return system("mv $src $dst");
  1401. }
  1402.  
  1403.  
  1404. ##
  1405. # addTextToKVEntryInFile
  1406. #
  1407. # Despite the long and confusing function name, this function is very
  1408. # useful. If you have a key value entry in a file, this function will
  1409. # allow you to add an entry to it based on a special regular expression.
  1410. # This regular expression must capture the pre-text, the values, and any
  1411. # post text by using regex back references.
  1412. # @param - Path to file
  1413. # @param - The regular expression. See example below...
  1414. # @param - The delimeter between values
  1415. # @param - The new entry
  1416. # @returns - 1 if the file was modified, 0 otherwise.
  1417. #
  1418. # For example, if I have
  1419. # foo = 'bar,baz';
  1420. # I can add 'biz' to the values by calling this function with the proper
  1421. # regex. A regex for this would look like '^(foo = ')(\.*)(;)$'. The
  1422. # delimeter is ',' and the entry would be 'biz'. The result should look
  1423. # like
  1424. # foo = 'bar,baz,biz';
  1425. #
  1426. # NOTE1: This function will only add to the first KV pair found.
  1427. #
  1428. sub addTextToKVEntryInFile {
  1429. my $file = shift;
  1430. my $regex = shift;
  1431. my $delim = shift;
  1432. my $entry = shift;
  1433. my $modified = 0;
  1434. my $firstPart;
  1435. my $origValues;
  1436. my $newValues;
  1437. my $lastPart;
  1438.  
  1439. $regex = qr/$regex/;
  1440.  
  1441. if (not open(INFILE, "<$file")) {
  1442. error("addTextToKVEntryInFile: File $file not found\n");
  1443. }
  1444.  
  1445. my $tmpDir = make_tmp_dir('vmware-file-mod');
  1446. my $tmpFile = join('/', $tmpDir, 'new-file');
  1447. if (not open(OUTFILE, ">$tmpFile")) {
  1448. error("addTextToKVEntryInFile: Failed to open output file\n");
  1449. }
  1450.  
  1451. foreach my $line (<INFILE>) {
  1452. if ($line =~ $regex and not $modified) {
  1453. # We have a match. $1 and $2 have to be deifined; $3 is optional
  1454. if (not defined $1 or not defined $2) {
  1455. error("addTextToKVEntryInFile: Bad regex.\n");
  1456. }
  1457. $firstPart = $1;
  1458. $origValues = $2;
  1459. $lastPart = ((defined $3) ? $3 : '');
  1460. chomp $firstPart;
  1461. chomp $origValues;
  1462. chomp $lastPart;
  1463.  
  1464. # Modify the origValues and remove duplicates
  1465. # Handle white space as well.
  1466. if ($origValues =~ /^\s*$/) {
  1467. $newValues = $entry;
  1468. } else {
  1469. $newValues = join($delim, $origValues, $entry);
  1470. $newValues = removeDuplicateEntries($newValues, $delim);
  1471. }
  1472. print OUTFILE join('', $firstPart, $newValues, $lastPart, "\n");
  1473.  
  1474. $modified = 1;
  1475. } else {
  1476. print OUTFILE $line;
  1477. }
  1478. }
  1479.  
  1480. close(INFILE);
  1481. close(OUTFILE);
  1482.  
  1483. return 0 unless (internalMv($tmpFile, $file) eq 0);
  1484. remove_tmp_dir($tmpDir);
  1485.  
  1486. # Our return status is 1 if successful, 0 if nothing was added.
  1487. return $modified;
  1488. }
  1489.  
  1490. # work around "panic: end_shift" (bug #1027773) for old ( <= 5.008) perl versions
  1491. sub safely_matches {
  1492. my $line = shift;
  1493. my $regex = shift;
  1494. my $b;
  1495. my @result;
  1496.  
  1497. if ($] <= 5.008) {
  1498. use bytes;
  1499. $b = ($line =~ $regex);
  1500. return ($b, $1, $2, $3);
  1501. } else {
  1502. $b = ($line =~ $regex);
  1503. return ($b, $1, $2, $3);
  1504. }
  1505. }
  1506.  
  1507. ##
  1508. # removeTextInKVEntryInFile
  1509. #
  1510. # Does exactly the opposite of addTextToKVEntryFile. It will remove
  1511. # all instances of the text entry in the first KV pair that it finds.
  1512. # @param - Path to file
  1513. # @param - The regular expression. See example above...
  1514. # @param - The delimeter between values
  1515. # @param - The entry to remove
  1516. # @returns - 1 if the file was modified, 0 otherwise.
  1517. #
  1518. # NOTE1: This function will only remove from the first KV pair found.
  1519. #
  1520. sub removeTextInKVEntryInFile {
  1521. my $file = shift;
  1522. my $regex = shift;
  1523. my $delim = shift;
  1524. my $entry = shift;
  1525. my $modified = 0;
  1526. my $firstPart;
  1527. my $origValues;
  1528. my $newValues = '';
  1529. my $lastPart;
  1530.  
  1531. $regex = qr/$regex/;
  1532.  
  1533. if (not open(INFILE, "<$file")) {
  1534. error("removeTextInKVEntryInFile: File $file not found\n");
  1535. }
  1536.  
  1537. my $tmpDir = make_tmp_dir('vmware-file-mod');
  1538. my $tmpFile = join('/', $tmpDir, 'new-file');
  1539. if (not open(OUTFILE, ">$tmpFile")) {
  1540. error("removeTextInKVEntryInFile: Failed to open output file $tmpFile\n");
  1541. }
  1542.  
  1543. foreach my $line (<INFILE>) {
  1544. my @res;
  1545. @res = safely_matches($line, $regex);
  1546. if ($res[0] and not $modified) {
  1547. # We have a match. $res[1] and $res[2] have to be defined; $res[3] is optional
  1548. if (not defined $res[1] or not defined $res[2]) {
  1549. error("removeTextInKVEntryInFile: Bad regex.\n");
  1550. }
  1551. $firstPart = $res[1];
  1552. $origValues = $res[2];
  1553. $lastPart = ((defined $res[3]) ? $res[3] : '');
  1554. chomp $firstPart;
  1555. chomp $origValues;
  1556. chomp $lastPart;
  1557.  
  1558. # Modify the origValues and remove duplicates
  1559. # If $origValues is just whitespace, no need to modify $newValues.
  1560. if ($origValues !~ /^\s*$/) {
  1561. foreach my $existingEntry (split($delim, $origValues)) {
  1562. if ($existingEntry ne $entry) {
  1563. if ($newValues eq '') {
  1564. $newValues = $existingEntry; # avoid adding unnecessary whitespace
  1565. } else {
  1566. $newValues = join($delim, $newValues, $existingEntry);
  1567. }
  1568. }
  1569. }
  1570. }
  1571. print OUTFILE join('', $firstPart, $newValues, $lastPart, "\n");
  1572.  
  1573. $modified = 1;
  1574. } else {
  1575. print OUTFILE $line;
  1576. }
  1577. }
  1578.  
  1579. close(INFILE);
  1580. close(OUTFILE);
  1581.  
  1582. return 0 unless (internalMv($tmpFile, $file));
  1583. remove_tmp_dir($tmpDir);
  1584.  
  1585. # Our return status is 1 if successful, 0 if nothing was added.
  1586. return $modified;
  1587. }
  1588.  
  1589.  
  1590. # Parse and return key/value pairs in /etc/os-release,
  1591. # which is only available in recent Linux distributions.
  1592. # http://www.freedesktop.org/software/systemd/man/os-release.html
  1593. sub identify_linux_variant {
  1594. my %propRef;
  1595.  
  1596. if (open(FH, '</etc/os-release')) {
  1597. while (<FH>) {
  1598. chomp;
  1599. my @parts = split(/\s*=\s*/, $_, 2);
  1600. if (@parts) {
  1601. $parts[1] =~ s/^"?(.*?)"?$/$1/;
  1602. $propRef{$parts[0]} = $parts[1];
  1603. }
  1604. }
  1605. }
  1606. close(FH);
  1607.  
  1608. return %propRef;
  1609. }
  1610.  
  1611. # Build a Linux kernel integer version
  1612. sub kernel_version_integer {
  1613. my $version = shift;
  1614. my $patchLevel = shift;
  1615. my $subLevel = shift;
  1616.  
  1617. return $version * 65536 + $patchLevel * 256 + $subLevel;
  1618. }
  1619.  
  1620. #
  1621. # getKernRel
  1622. #
  1623. # Returns the release of the kernel in question. Defaults to the
  1624. # running kernel unless the user has set the --kernel-version option.
  1625. #
  1626. sub getKernRel {
  1627. if (defined($gOption{'kernel_version'}) and
  1628. $gOption{'kernel_version'} ne '') {
  1629. return $gOption{'kernel_version'};
  1630. } else {
  1631. if (not defined($gSystem{'uts_release'})) {
  1632. $gSystem{'uts_release'} = direct_command(shell_string(internal_which('uname')) . ' -r');
  1633. }
  1634. return $gSystem{'uts_release'};
  1635. }
  1636. }
  1637.  
  1638. #
  1639. # returns the release of the kernel in question like getKernRel()
  1640. # but as an integer (useful for comparisons)
  1641. #
  1642.  
  1643. sub getKernRelInteger {
  1644. my ($version, $patchLevel, $subLevel) = split(/\./, getKernRel());
  1645. ($subLevel) = split(/[^0-9]/, $subLevel);
  1646. return kernel_version_integer($version, $patchLevel, $subLevel);
  1647. }
  1648.  
  1649. # END_OF_UTIL_DOT_PL
  1650.  
  1651. # Needed for WIFSIGNALED and WTERMSIG
  1652. use POSIX;
  1653. use Config;
  1654.  
  1655. # Constants
  1656. my $cInstallerFileName = 'vmware-install.pl';
  1657. my $cInstallerFileNameReal = 'vmware-install.real.pl';
  1658. my $cModuleUpdaterFileName = 'install.pl';
  1659. my $cInstallerDir = './installer';
  1660. my $cStartupFileName = $cInstallerDir . '/services.sh';
  1661. my $cStartupFileNameThinPrint = $cInstallerDir . '/thinprint.sh';
  1662. my $cRegistryDir = '/etc/vmware';
  1663. my $cInstallerMainDB = $cRegistryDir . '/locations';
  1664. my $cInstallerObject = $cRegistryDir . '/installer.sh';
  1665. my $cConfFlag = $cRegistryDir . '/not_configured';
  1666. my $dspMarkerFile = '/usr/lib/vmware-tools/dsp';
  1667. # Constant defined as the smallest vmnet that is allowed
  1668. my $gMinVmnet = '0';
  1669. # Linux doesn't allow more than 7 characters in the names of network
  1670. # interfaces. We prefix host only interfaces with 'vmnet' leaving us only 2
  1671. # characters.
  1672. # Constant defined as the largest vmnet that is allowed
  1673. my $gMaxVmnet = '99';
  1674.  
  1675. my $open_vm_compat = 0;
  1676.  
  1677. my $cChkconfigInfo = <<END;
  1678. # Basic support for IRIX style chkconfig
  1679. # chkconfig: 2345 03 99
  1680. # description: Manages the services needed to run VMware software
  1681. END
  1682.  
  1683. # cups in RHEL 5.6 has
  1684. # chkconfig: 2345 56 10
  1685. # so we make sure to start thinprint after cups (and stop before
  1686. # cups)
  1687. # see bug #777311
  1688. my $cChkconfigInfoThinPrint = <<END;
  1689. # Basic support for IRIX style chkconfig
  1690. # chkconfig: 2345 57 43
  1691. # description: Manages the services needed to run VMware software
  1692. END
  1693.  
  1694. my $cLSBInitInfoTempl = <<END;
  1695. ### BEGIN INIT INFO
  1696. # Provides: vmware-tools
  1697. # Required-Start: \$local_fs
  1698. # Required-Stop: \$local_fs
  1699. # X-Start-Before: \$network
  1700. # X-Stop-After: \$network
  1701. # Default-Start: __DEFAULT_START__
  1702. # Default-Stop: __DEFAULT_STOP__
  1703. # Short-Description: VMware Tools service
  1704. # Description: Manages the services needed to run VMware Tools
  1705. ### END INIT INFO
  1706. END
  1707.  
  1708. my $cLSBInitInfoTPTempl= <<END;
  1709. ### BEGIN INIT INFO
  1710. # Provides: vmware-tools-thinprint
  1711. # Required-Start: __CUPS__
  1712. # Required-Stop: __CUPS__
  1713. # Default-Start: __DEFAULT_START__
  1714. # Default-Stop: __DEFAULT_STOP__
  1715. # Short-Description: VMware Tools thinprint
  1716. # Description: The VMware Thinprint service enables guests VMs to seamlessly use printers on the host
  1717. ### END INIT INFO
  1718. END
  1719.  
  1720. # MANIFEST file and hash for installing ACE VMs
  1721. my $cManifestFilename = 'MANIFEST';
  1722. my %gManifest;
  1723. my $gACEVMUpdate = 0;
  1724. my $gHostVmplDir = "/etc/vmware/vmware-ace";
  1725. my $gPlayerBundle = '';
  1726.  
  1727. # Has the uninstaller been installed?
  1728. my $gIsUninstallerInstalled;
  1729.  
  1730. # Hash of multi architecture supporting products
  1731. my %multi_arch_products;
  1732.  
  1733. # BEGINNING OF THE SECOND LIBRARY FUNCTIONS
  1734. # Global variables
  1735. my $gRegistryDir;
  1736. my $gFirstCreatedDir = undef;
  1737. my $gStateDir;
  1738. my $gInstallerMainDB;
  1739. my $gInstallerObject;
  1740. my $gConfFlag;
  1741. my $gUninstallerFileName;
  1742. my $gConfigurator;
  1743. my $gConfig;
  1744. my $gConfigFile;
  1745.  
  1746. my %gDBAnswer;
  1747. my %gDBFile;
  1748. my %gDBDir;
  1749. my %gDBLink;
  1750. my %gDBMove;
  1751.  
  1752. # list of files that are config failes users may modify
  1753. my %gDBUserModified;
  1754. my %gDBConfig;
  1755.  
  1756. #
  1757. # db_clear
  1758. #
  1759. # Unsets all variables modified in the db_load process
  1760. #
  1761. sub db_clear {
  1762. undef %gDBAnswer;
  1763. undef %gDBFile;
  1764. undef %gDBDir;
  1765. undef %gDBLink;
  1766. undef %gDBMove;
  1767. undef %gDBConfig;
  1768. undef %gDBUserModified;
  1769. }
  1770.  
  1771. #
  1772. # db_load
  1773. #
  1774. # Reads in the database file specified in $gInstallerMainDB and loads the values
  1775. # into the 7 variables mentioned below.
  1776. #
  1777. sub db_load {
  1778. db_clear();
  1779. open(INSTALLDB, '<' . $gInstallerMainDB)
  1780. or error('Unable to open the installer database '
  1781. . $gInstallerMainDB . ' in read-mode.' . "\n\n");
  1782. while (<INSTALLDB>) {
  1783. chomp;
  1784. if (/^answer (\S+) (.+)$/) {
  1785. $gDBAnswer{$1} = $2;
  1786. } elsif (/^answer (\S+)/) {
  1787. $gDBAnswer{$1} = '';
  1788. } elsif (/^remove_answer (\S+)/) {
  1789. delete $gDBAnswer{$1};
  1790. } elsif (/^file (.+) (\d+)$/) {
  1791. $gDBFile{$1} = $2;
  1792. } elsif (/^file (.+)$/) {
  1793. $gDBFile{$1} = 0;
  1794. } elsif (/^remove_file (.+)$/) {
  1795. delete $gDBFile{$1};
  1796. } elsif (/^directory (.+)$/) {
  1797. $gDBDir{$1} = '';
  1798. } elsif (/^remove_directory (.+)$/) {
  1799. delete $gDBDir{$1};
  1800. } elsif (/^link (\S+) (\S+)/) {
  1801. $gDBLink{$2} = $1;
  1802. } elsif (/^move (\S+) (\S+)/) {
  1803. $gDBMove{$2} = $1;
  1804. } elsif (/^config (\S+)/) {
  1805. $gDBConfig{$1} = 'config';
  1806. } elsif (/^modified (\S+)/) {
  1807. $gDBUserModified{$1} = 'modified';
  1808. }
  1809. }
  1810. close(INSTALLDB);
  1811. }
  1812.  
  1813. # Open the database on disk in append mode
  1814. sub db_append {
  1815. if (not open(INSTALLDB, '>>' . $gInstallerMainDB)) {
  1816. error('Unable to open the installer database ' . $gInstallerMainDB . ' in append-mode.' . "\n\n");
  1817. }
  1818. # Force a flush after every write operation.
  1819. # See 'Programming Perl', p. 110
  1820. select((select(INSTALLDB), $| = 1)[0]);
  1821. }
  1822.  
  1823. # Add a file to the tar installer database
  1824. # flags:
  1825. # 0x1 write time stamp
  1826. sub db_add_file {
  1827. my $file = shift;
  1828. my $flags = shift;
  1829.  
  1830. if ($flags & 0x1) {
  1831. my @statbuf;
  1832.  
  1833. @statbuf = stat($file);
  1834. if (not (defined($statbuf[9]))) {
  1835. error('Unable to get the last modification timestamp of the destination file ' . $file . '.' . "\n\n");
  1836. }
  1837.  
  1838. $gDBFile{$file} = $statbuf[9];
  1839. print INSTALLDB 'file ' . $file . ' ' . $statbuf[9] . "\n";
  1840. } else {
  1841. $gDBFile{$file} = 0;
  1842. print INSTALLDB 'file ' . $file . "\n";
  1843. }
  1844. }
  1845.  
  1846. # Remove a file from the tar installer database
  1847. sub db_remove_file {
  1848. my $file = shift;
  1849.  
  1850. print INSTALLDB 'remove_file ' . $file . "\n";
  1851. delete $gDBFile{$file};
  1852. }
  1853.  
  1854. # Remove a directory from the tar installer database
  1855. sub db_remove_dir {
  1856. my $dir = shift;
  1857.  
  1858. print INSTALLDB 'remove_directory ' . $dir . "\n";
  1859. delete $gDBDir{$dir};
  1860. }
  1861.  
  1862. # Determine if a file belongs to the tar installer database
  1863. sub db_file_in {
  1864. my $file = shift;
  1865.  
  1866. return defined($gDBFile{$file});
  1867. }
  1868.  
  1869. # Determine if a directory belongs to the tar installer database
  1870. sub db_dir_in {
  1871. my $dir = shift;
  1872.  
  1873. return defined($gDBDir{$dir});
  1874. }
  1875.  
  1876. # Return the timestamp of an installed file
  1877. sub db_file_ts {
  1878. my $file = shift;
  1879.  
  1880. return $gDBFile{$file};
  1881. }
  1882.  
  1883. # Add a directory to the tar installer database
  1884. sub db_add_dir {
  1885. my $dir = shift;
  1886.  
  1887. $gDBDir{$dir} = '';
  1888. print INSTALLDB 'directory ' . $dir . "\n";
  1889. }
  1890.  
  1891. # Remove an answer from the tar installer database
  1892. sub db_remove_answer {
  1893. my $id = shift;
  1894.  
  1895. if (defined($gDBAnswer{$id})) {
  1896. print INSTALLDB 'remove_answer ' . $id . "\n";
  1897. delete $gDBAnswer{$id};
  1898. }
  1899. }
  1900.  
  1901. # Add an answer to the tar installer database
  1902. sub db_add_answer {
  1903. my $id = shift;
  1904. my $value = shift;
  1905.  
  1906. db_remove_answer($id);
  1907. $gDBAnswer{$id} = $value;
  1908. print INSTALLDB 'answer ' . $id . ' ' . $value . "\n";
  1909. }
  1910.  
  1911. # Retrieve an answer that must be present in the database
  1912. sub db_get_answer {
  1913. my $id = shift;
  1914.  
  1915. if (not defined($gDBAnswer{$id})) {
  1916. error('Unable to find the answer ' . $id . ' in the installer database ('
  1917. . $gInstallerMainDB . '). You may want to re-install '
  1918. . vmware_product_name() . "." . "\n\n");
  1919. }
  1920.  
  1921. return $gDBAnswer{$id};
  1922. }
  1923.  
  1924. # Retrieves an answer if it exists in the database, else returns undef;
  1925. sub db_get_answer_if_exists {
  1926. my $id = shift;
  1927. if (not defined($gDBAnswer{$id})) {
  1928. return undef;
  1929. }
  1930. if ($gDBAnswer{$id} eq '') {
  1931. return undef;
  1932. }
  1933. return $gDBAnswer{$id};
  1934. }
  1935.  
  1936. # Save the tar installer database
  1937. sub db_save {
  1938. close(INSTALLDB);
  1939. }
  1940.  
  1941. # END OF THE SECOND LIBRARY FUNCTIONS
  1942.  
  1943. # BEGINNING OF THE LIBRARY FUNCTIONS
  1944. # Global variables
  1945. my %gAnswerSize;
  1946. my %gCheckAnswerFct;
  1947.  
  1948. # Contrary to a popular belief, 'which' is not always a shell builtin command.
  1949. # So we can not trust it to determine the location of other binaries.
  1950. # Moreover, SuSE 6.1's 'which' is unable to handle program names beginning with
  1951. # a '/'...
  1952. #
  1953. # Return value is the complete path if found, or '' if not found
  1954. sub internal_which {
  1955. my $bin = shift;
  1956.  
  1957. if (substr($bin, 0, 1) eq '/') {
  1958. # Absolute name
  1959. if ((-f $bin) && (-x $bin)) {
  1960. return $bin;
  1961. }
  1962. } else {
  1963. # Relative name
  1964. my @paths;
  1965. my $path;
  1966.  
  1967. if (index($bin, '/') == -1) {
  1968. # There is no other '/' in the name
  1969. @paths = split(':', $ENV{'PATH'});
  1970. foreach $path (@paths) {
  1971. my $fullbin;
  1972.  
  1973. $fullbin = $path . '/' . $bin;
  1974. if ((-f $fullbin) && (-x $fullbin)) {
  1975. return $fullbin;
  1976. }
  1977. }
  1978. }
  1979. }
  1980.  
  1981. return '';
  1982. }
  1983.  
  1984. # Check the validity of an answer whose type is yesno
  1985. # Return a clean answer if valid, or ''
  1986. sub check_answer_binpath {
  1987. my $answer = shift;
  1988. my $source = shift;
  1989.  
  1990. my $fullpath = internal_which($answer);
  1991. if (not ("$fullpath" eq '')) {
  1992. return $fullpath;
  1993. }
  1994.  
  1995. if ($source eq 'user') {
  1996. print wrap('The answer "' . $answer . '" is invalid. It must be the complete name of a binary file.' . "\n\n", 0);
  1997. }
  1998. return '';
  1999. }
  2000. $gAnswerSize{'binpath'} = 20;
  2001. $gCheckAnswerFct{'binpath'} = \&check_answer_binpath;
  2002.  
  2003. # Prompts the user if a binary is not found
  2004. # Return value is:
  2005. # '': the binary has not been found
  2006. # the binary name if it has been found
  2007. sub DoesBinaryExist_Prompt {
  2008. my $bin = shift;
  2009. my $answer;
  2010.  
  2011. $answer = check_answer_binpath($bin, 'default');
  2012. if (not ($answer eq '')) {
  2013. return $answer;
  2014. }
  2015.  
  2016. 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') {
  2017. return '';
  2018. }
  2019.  
  2020. return get_answer('What is the location of the "' . $bin . '" program on your machine?', 'binpath', '');
  2021. }
  2022.  
  2023. # Install a file permission
  2024. sub install_permission {
  2025. my $src = shift;
  2026. my $dst = shift;
  2027. my @statbuf;
  2028. my $mode;
  2029. @statbuf = stat($src);
  2030. if (not (defined($statbuf[2]))) {
  2031. error('Unable to get the access rights of source file "' . $src . '".' . "\n\n");
  2032. }
  2033.  
  2034. $mode = $statbuf[2] & 07777;
  2035. safe_chmod($mode, $dst);
  2036. }
  2037.  
  2038. # Emulate a simplified sed program
  2039. # Return 1 if success, 0 if failure
  2040. # XXX as a side effect, if the string being replaced is '', remove
  2041. # the entire line. Remove this, once we have better "block handling" of
  2042. # our config data in config files.
  2043. sub internal_sed {
  2044. my $src = shift;
  2045. my $dst = shift;
  2046. my $append = shift;
  2047. my $patchRef = shift;
  2048. my @patchKeys;
  2049.  
  2050. if (not open(SRC, '<' . $src)) {
  2051. return 0;
  2052. }
  2053. if (not open(DST, (($append == 1) ? '>>' : '>') . $dst)) {
  2054. return 0;
  2055. }
  2056.  
  2057. @patchKeys = keys(%$patchRef);
  2058. if ($#patchKeys == -1) {
  2059. while(defined($_ = <SRC>)) {
  2060. print DST $_;
  2061. }
  2062. } else {
  2063. while(defined($_ = <SRC>)) {
  2064. my $patchKey;
  2065. my $del = 0;
  2066.  
  2067. foreach $patchKey (@patchKeys) {
  2068. if (s/$patchKey/$$patchRef{$patchKey}/g) {
  2069. if ($_ eq "\n") {
  2070. $del = 1;
  2071. }
  2072. }
  2073. }
  2074. next if ($del);
  2075. print DST $_;
  2076. }
  2077. }
  2078.  
  2079. close(SRC);
  2080. close(DST);
  2081. return 1;
  2082. }
  2083.  
  2084. # Check if a file name exists
  2085. sub file_name_exist {
  2086. my $file = shift;
  2087.  
  2088. # Note: We must test for -l before, because if an existing symlink points to
  2089. # a non-existing file, -e will be false
  2090. return ((-l $file) || (-e $file))
  2091. }
  2092.  
  2093. # Check if a file name already exists and prompt the user
  2094. # Return 0 if the file can be written safely, 1 otherwise
  2095. sub file_check_exist {
  2096. my $file = shift;
  2097. my $default_overwrite = 'yes';
  2098. if (@_ >= 1) {
  2099. $default_overwrite = shift;
  2100. }
  2101.  
  2102. if (not file_name_exist($file)) {
  2103. return 0;
  2104. }
  2105.  
  2106. my $lib_dir = $Config{'archlib'} || $ENV{'PERL5LIB'} || $ENV{'PERLLIB'} ;
  2107. my $share_dir = $Config{'installprivlib'} || $ENV{'PERLSHARE'} ;
  2108.  
  2109. # do not overwrite perl module files
  2110. if($file =~ m/$lib_dir|$share_dir/) {
  2111. return 1;
  2112. }
  2113.  
  2114.  
  2115. # The default must make sure that the product will be correctly installed
  2116. # We give the user the choice so that a sysadmin can perform a normal
  2117. # install on a NFS server and then answer 'no' NFS clients
  2118. return (get_answer('The file ' . $file . ' that this program was about to '
  2119. . 'install already exists. Overwrite?',
  2120. 'yesno', $default_overwrite) eq 'yes') ? 0 : 1;
  2121. }
  2122.  
  2123. # Install one file
  2124. # flags are forwarded to db_add_file()
  2125. sub install_file {
  2126. my $src = shift;
  2127. my $dst = shift;
  2128. my $patchRef = shift;
  2129. my $flags = shift;
  2130. my $default_overwrite = 'yes';
  2131. if (@_ >= 1) {
  2132. $default_overwrite = shift;
  2133. }
  2134.  
  2135. uninstall_file($dst);
  2136. # because any modified config file is not removed but left in place,
  2137. # it will already exist and coveniently avoid processing here. It's
  2138. # not added to the db so it will not be uninstalled next time.
  2139. if (file_check_exist($dst, $default_overwrite)) {
  2140. return;
  2141. }
  2142. # The file could be a symlink to another location. Remove it
  2143. unlink($dst);
  2144. if (not internal_sed($src, $dst, 0, $patchRef)) {
  2145. error('Unable to copy the source file ' . $src . ' to the destination file ' . $dst . '.' . "\n\n");
  2146. }
  2147. db_add_file($dst, $flags);
  2148. install_permission($src, $dst);
  2149. }
  2150.  
  2151. # mkdir() that reports errors
  2152. sub safe_mkdir {
  2153. my $file = shift;
  2154.  
  2155. if (mkdir($file, 0000) == 0) {
  2156. error('Unable to create the directory ' . $file . '.' . "\n\n");
  2157. }
  2158. }
  2159.  
  2160. # Remove trailing slashes in a dir path
  2161. sub dir_remove_trailing_slashes {
  2162. my $path = shift;
  2163.  
  2164. for(;;) {
  2165. my $len;
  2166. my $pos;
  2167.  
  2168. $len = length($path);
  2169. if ($len < 2) {
  2170. # Could be '/' or any other character. Ok.
  2171. return $path;
  2172. }
  2173.  
  2174. $pos = rindex($path, '/');
  2175. if ($pos != $len - 1) {
  2176. # No trailing slash
  2177. return $path;
  2178. }
  2179.  
  2180. # Remove the trailing slash
  2181. $path = substr($path, 0, $len - 1)
  2182. }
  2183. }
  2184.  
  2185.  
  2186. # Create a hierarchy of directories with permission 0755
  2187. # flags:
  2188. # 0x1 write this directory creation in the installer database
  2189. # Return 1 if the directory existed before
  2190. sub create_dir {
  2191. my $dir = shift;
  2192. my $flags = shift;
  2193.  
  2194. if (-d $dir) {
  2195. return 1;
  2196. }
  2197.  
  2198. if (index($dir, '/') != -1) {
  2199. create_dir(internal_dirname($dir), $flags);
  2200. }
  2201. safe_mkdir($dir);
  2202. if ($flags & 0x1) {
  2203. db_add_dir($dir);
  2204. }
  2205. safe_chmod(0755, $dir);
  2206. return 0;
  2207. }
  2208.  
  2209. # Get a valid non-persistent answer to a question
  2210. # Use this when the answer shouldn't be stored in the database
  2211. sub get_answer {
  2212. my $msg = shift;
  2213. my $type = shift;
  2214. my $default = shift;
  2215. my $answer;
  2216.  
  2217. if (not defined($gAnswerSize{$type})) {
  2218. die 'get_answer(): type ' . $type . ' not implemented :(' . "\n\n";
  2219. }
  2220. for (;;) {
  2221. $answer = check_answer(query($msg, $default, $gAnswerSize{$type}), $type, 'user');
  2222. if (not ($answer eq '')) {
  2223. return $answer;
  2224. }
  2225. if ($gOption{'default'} == 1) {
  2226. error('Invalid default answer!' . "\n");
  2227. }
  2228. }
  2229. }
  2230.  
  2231. # Get a valid persistent answer to a question
  2232. # Use this when you want an answer to be stored in the database
  2233. sub get_persistent_answer {
  2234. my $msg = shift;
  2235. my $id = shift;
  2236. my $type = shift;
  2237. my $default = shift;
  2238. my $isdefault = shift;
  2239. my $answer;
  2240.  
  2241. if (defined($gDBAnswer{$id}) && !defined($isdefault) ) {
  2242. # There is a previous answer in the database
  2243. $answer = check_answer($gDBAnswer{$id}, $type, 'db');
  2244. if (not ($answer eq '')) {
  2245. # The previous answer is valid. Make it the default value
  2246. $default = $answer;
  2247. }
  2248. }
  2249.  
  2250. $answer = get_answer($msg, $type, $default);
  2251. db_add_answer($id, $answer);
  2252. return $answer;
  2253. }
  2254.  
  2255. # Find a suitable backup name and backup a file
  2256. sub backup_file {
  2257. my $file = shift;
  2258. my $i;
  2259.  
  2260. for ($i = 0; $i < 100; $i++) {
  2261. if (not file_name_exist($file . '.old.' . $i)) {
  2262. my %patch;
  2263.  
  2264. undef %patch;
  2265. if (internal_sed($file, $file . '.old.' . $i, 0, \%patch)) {
  2266. print wrap('File ' . $file . ' is backed up to ' . $file .
  2267. '.old.' . $i . '.' . "\n\n", 0);
  2268. } else {
  2269. print STDERR wrap('Unable to backup the file ' . $file .
  2270. ' to ' . $file . '.old.' . $i .'.' . "\n\n", 0);
  2271. }
  2272. return;
  2273. }
  2274. }
  2275.  
  2276. print STDERR wrap('Unable to backup the file ' . $file .
  2277. '. You have too many backups files. They are files of the form ' .
  2278. $file . '.old.N, where N is a number. Please delete some of them.' . "\n\n", 0);
  2279. }
  2280.  
  2281. # Uninstall a file previously installed by us
  2282. sub uninstall_file {
  2283. my $file = shift;
  2284.  
  2285. if (not db_file_in($file)) {
  2286. # Not installed by this program
  2287. return;
  2288. }
  2289.  
  2290. if (file_name_exist($file)) {
  2291. # If this file is a config file and already exists or is modified,
  2292. # leave it in place to save the users' modifications.
  2293. if (defined($gDBConfig{$file}) && defined($gDBUserModified{$file})) {
  2294. db_remove_file($file);
  2295. return;
  2296. }
  2297. if (db_file_ts($file)) {
  2298. my @statbuf;
  2299.  
  2300. @statbuf = stat($file);
  2301. if (defined($statbuf[9])) {
  2302. if (db_file_ts($file) != $statbuf[9]) {
  2303. # Modified since this program installed it
  2304. if (defined($gDBConfig{$file})) {
  2305. # Because config files need to survive the install and uninstall
  2306. # process.
  2307. $gDBUserModified{$file} = 'modified';
  2308. db_remove_file($file);
  2309. return;
  2310. } else {
  2311. backup_file($file);
  2312. }
  2313. }
  2314. } else {
  2315. print STDERR wrap('Unable to get the last modification timestamp of '
  2316. . 'the file ' . $file . '.' . "\n\n", 0);
  2317. }
  2318. }
  2319.  
  2320. if (not unlink($file)) {
  2321. error('Unable to remove the file "' . $file . '".' . "\n");
  2322. } else {
  2323. db_remove_file($file);
  2324. }
  2325.  
  2326. } else {
  2327. print wrap('This program previously created the file ' . $file . ', and '
  2328. . 'was about to remove it. Somebody else apparently did it '
  2329. . 'already.' . "\n\n", 0);
  2330. db_remove_file($file);
  2331. }
  2332. }
  2333.  
  2334. # Uninstall a directory previously installed by us
  2335. sub uninstall_dir {
  2336. my $dir = shift;
  2337. my $force = shift;
  2338.  
  2339. if (not db_dir_in($dir)) {
  2340. # Not installed by this program
  2341. return;
  2342. }
  2343.  
  2344. if (-d $dir) {
  2345. if ($force eq '1') {
  2346. system(shell_string($gHelper{'rm'}) . ' -rf ' . shell_string($dir));
  2347. } elsif (not rmdir($dir)) {
  2348. print wrap('This program previously created the directory ' . $dir
  2349. . ', and was about to remove it. Since there are files in '
  2350. . 'that directory that this program did not create, it will '
  2351. . 'not be removed.' . "\n\n", 0);
  2352. if ( defined($ENV{'VMWARE_DEBUG'})
  2353. && ($ENV{'VMWARE_DEBUG'} eq 'yes')) {
  2354. system('ls -AlR ' . shell_string($dir));
  2355. }
  2356. }
  2357. } else {
  2358. print wrap('This program previously created the directory ' . $dir
  2359. . ', and was about to remove it. Somebody else apparently did '
  2360. . 'it already.' . "\n\n", 0);
  2361. }
  2362.  
  2363. db_remove_dir($dir);
  2364. }
  2365.  
  2366. # Return the version of VMware
  2367. sub vmware_version {
  2368. my $buildNr;
  2369.  
  2370. $buildNr = '10.0.12 build-4448491';
  2371. return remove_whitespaces($buildNr);
  2372. }
  2373.  
  2374. # Check the validity of an answer whose type is yesno
  2375. # Return a clean answer if valid, or ''
  2376. sub check_answer_yesno {
  2377. my $answer = shift;
  2378. my $source = shift;
  2379.  
  2380. if (lc($answer) =~ /^y(es)?$/) {
  2381. return 'yes';
  2382. }
  2383.  
  2384. if (lc($answer) =~ /^n(o)?$/) {
  2385. return 'no';
  2386. }
  2387.  
  2388. if ($source eq 'user') {
  2389. print wrap('The answer "' . $answer . '" is invalid. It must be one of "y" or "n".' . "\n\n", 0);
  2390. }
  2391. return '';
  2392. }
  2393. $gAnswerSize{'yesno'} = 3;
  2394. $gCheckAnswerFct{'yesno'} = \&check_answer_yesno;
  2395.  
  2396. # Check the validity of an answer based on its type
  2397. # Return a clean answer if valid, or ''
  2398. sub check_answer {
  2399. my $answer = shift;
  2400. my $type = shift;
  2401. my $source = shift;
  2402.  
  2403. if (not defined($gCheckAnswerFct{$type})) {
  2404. die 'check_answer(): type ' . $type . ' not implemented :(' . "\n\n";
  2405. }
  2406. return &{$gCheckAnswerFct{$type}}($answer, $source);
  2407. }
  2408.  
  2409. # END OF THE LIBRARY FUNCTIONS
  2410.  
  2411. # Emulate a simplified basename program
  2412. sub internal_basename {
  2413. return substr($_[0], rindex($_[0], '/') + 1);
  2414. }
  2415.  
  2416. # Set the name of the main /etc/vmware* directory.
  2417. sub initialize_globals {
  2418. my $dirname = shift;
  2419.  
  2420. if (vmware_product() eq 'api') {
  2421. $gRegistryDir = '/etc/vmware-api';
  2422. $gUninstallerFileName = 'vmware-uninstall-api.pl';
  2423. $gConfigurator = 'vmware-config-api.pl';
  2424. } elsif (vmware_product() eq 'tools-for-linux' ||
  2425. vmware_product() eq 'tools-for-freebsd' ||
  2426. vmware_product() eq 'tools-for-solaris') {
  2427. $gRegistryDir = '/etc/vmware-tools';
  2428. $gUninstallerFileName = 'vmware-uninstall-tools.pl';
  2429. $gConfigurator = 'vmware-config-tools.pl';
  2430. } elsif (vmware_product() eq 'vix') {
  2431. $gRegistryDir = '/etc/vmware-vix';
  2432. $gUninstallerFileName = 'vmware-uninstall-vix.pl';
  2433. $gConfigurator = 'vmware-config-vix.pl';
  2434. $gConfigFile = '/etc/vmware/config';
  2435. } elsif (vmware_product() eq 'vix-disklib') {
  2436. $gRegistryDir = '/etc/vmware-vix-disklib';
  2437. $gUninstallerFileName = 'vmware-uninstall-vix-disklib.pl';
  2438. $gConfigurator = 'vmware-config-vix-disklib.pl';
  2439. } elsif (vmware_product() eq 'nvdk') {
  2440. $gRegistryDir = '/etc/vmware-nvdk';
  2441. $gUninstallerFileName = 'vmware-uninstall-nvdk.pl';
  2442. $gConfigurator = 'vmware-config-nvdk.pl';
  2443. } else {
  2444. $gRegistryDir = '/etc/vmware';
  2445. $gUninstallerFileName = 'vmware-uninstall.pl';
  2446. $gConfigurator = 'vmware-config.pl';
  2447. }
  2448. $gStateDir = $gRegistryDir . '/state';
  2449. $gInstallerMainDB = $gRegistryDir . '/locations';
  2450. $gInstallerObject = $gRegistryDir . '/installer.sh';
  2451. $gConfFlag = $gRegistryDir . '/not_configured';
  2452.  
  2453. $gOption{'default'} = 0;
  2454. $gOption{'regenerate-cert'} = 0;
  2455. $gOption{'preserve-guest-proxy-data'} = 0;
  2456. $gOption{'force-install'} = 0;
  2457. $gOption{'upgrade'} = 0;
  2458. $gOption{'ws-upgrade'} = 0;
  2459. $gOption{'eula_agreed'} = 0;
  2460. $gOption{'create_shortcuts'} = 1;
  2461.  
  2462. if (defined $gConfigFile) {
  2463. load_config();
  2464. }
  2465. }
  2466.  
  2467. sub load_config() {
  2468. $gConfig = new VMware::Config;
  2469. $gConfig->readin($gConfigFile);
  2470. }
  2471.  
  2472. # Set up the location of external helpers
  2473. sub initialize_external_helpers {
  2474. my $program;
  2475. my @programList;
  2476.  
  2477. if (not defined($gHelper{'more'})) {
  2478. $gHelper{'more'} = '';
  2479. if (defined($ENV{'PAGER'})) {
  2480. my @tokens;
  2481.  
  2482. # The environment variable sometimes contains the pager name _followed by
  2483. # a few command line options_.
  2484. #
  2485. # Isolate the program name (we are certain it does not contain a
  2486. # whitespace) before dealing with it.
  2487. @tokens = split(' ', $ENV{'PAGER'});
  2488. $tokens[0] = DoesBinaryExist_Prompt($tokens[0]);
  2489. if (not ($tokens[0] eq '')) {
  2490. # Whichever PAGER the user has, we want them to have the same
  2491. # behavior, that is automatically exit the first time it reaches
  2492. # end-of-file.
  2493. # This is the behavior of `more', regardless of the command line
  2494. # options. If `less' is used, however, the option '-E' should be
  2495. # specified (see bug 254808).
  2496. if ($tokens[0] eq internal_which('less')) {
  2497. push(@tokens,'-E');
  2498. }
  2499. $gHelper{'more'} = join(' ', @tokens); # This is _already_ a shell string
  2500. }
  2501. }
  2502. if ($gHelper{'more'} eq '') {
  2503. $gHelper{'more'} = DoesBinaryExist_Prompt('more');
  2504. if ($gHelper{'more'} eq '') {
  2505. error('Unable to continue.' . "\n\n");
  2506. }
  2507. $gHelper{'more'} = shell_string($gHelper{'more'}); # Save it as a shell string
  2508. }
  2509. }
  2510.  
  2511. if (vmware_product() eq 'tools-for-linux') {
  2512. @programList = ('tar', 'sed', 'rm', 'lsmod', 'umount', 'mv',
  2513. 'uname', 'mount', 'du', 'df', 'depmod', 'pidof',
  2514. 'modprobe', 'rmmod', 'grep');
  2515. } elsif (vmware_product() eq 'tools-for-freebsd') {
  2516. @programList = ('tar', 'sed', 'rm', 'kldstat', 'umount',
  2517. 'mv', 'uname', 'mount', 'du', 'df', 'kldload', 'kldunload');
  2518. } elsif (vmware_product() eq 'tools-for-solaris') {
  2519. @programList = ('tar', 'sed', 'rm', 'add_drv', 'rem_drv',
  2520. 'modload', 'modunload', 'umount', 'mv', 'uname',
  2521. 'mount', 'cat', 'update_drv', 'grep', 'gunzip',
  2522. 'gzip', 'du', 'df', 'isainfo');
  2523. } elsif (vmware_product() eq 'vix') {
  2524. @programList = ('tar', 'sed', 'rm', 'mv', 'ps', 'du', 'df', 'cp');
  2525. } elsif (vmware_product() eq 'vix-disklib') {
  2526. @programList = ('tar', 'sed', 'rm', 'rm', 'mv', 'ps', 'du', 'df', 'ldd');
  2527. } elsif (vmware_product() eq 'nvdk') {
  2528. @programList = ('tar', 'sed', 'rm', 'rm', 'mv', 'ps', 'du', 'df', 'ldd');
  2529. } else {
  2530. @programList = ('tar', 'sed', 'rm', 'killall', 'lsmod', 'umount', 'mv',
  2531. 'uname', 'mount', 'du', 'df', 'depmod', 'pidof');
  2532. }
  2533.  
  2534. foreach $program (@programList) {
  2535. if (not defined($gHelper{$program})) {
  2536. $gHelper{$program} = DoesBinaryExist_Prompt($program);
  2537. if ($gHelper{$program} eq '') {
  2538. error('Unable to continue.' . "\n\n");
  2539. }
  2540. }
  2541. }
  2542.  
  2543. # Used for removing links that were not added as files to the database.
  2544. $gHelper{'insserv'} = internal_which('insserv');
  2545. $gHelper{'chkconfig'} = internal_which('chkconfig');
  2546. $gHelper{'update-rc.d'} = internal_which('update-rc.d');
  2547. }
  2548.  
  2549. # Check the validity of an answer whose type is dirpath
  2550. # Return a clean answer if valid, or ''
  2551. sub check_answer_dirpath {
  2552. my $answer = shift;
  2553. my $source = shift;
  2554.  
  2555. $answer = dir_remove_trailing_slashes($answer);
  2556.  
  2557. if (substr($answer, 0, 1) ne '/') {
  2558. print wrap('The path "' . $answer . '" is a relative path. Please enter '
  2559. . 'an absolute path.' . "\n\n", 0);
  2560. return '';
  2561. }
  2562.  
  2563. if (-d $answer) {
  2564. # The path is an existing directory
  2565. return $answer;
  2566. }
  2567.  
  2568. # The path is not a directory
  2569. if (file_name_exist($answer)) {
  2570. if ($source eq 'user') {
  2571. print wrap('The path "' . $answer . '" exists, but is not a directory.'
  2572. . "\n\n", 0);
  2573. }
  2574. return '';
  2575. }
  2576.  
  2577. # The path does not exist
  2578. if ($source eq 'user') {
  2579. return (get_answer('The path "' . $answer . '" does not exist currently. '
  2580. . 'This program is going to create it, including needed '
  2581. . 'parent directories. Is this what you want?',
  2582. 'yesno', 'yes') eq 'yes') ? $answer : '';
  2583. } else {
  2584. return $answer;
  2585. }
  2586. }
  2587. $gAnswerSize{'dirpath'} = 20;
  2588. $gCheckAnswerFct{'dirpath'} = \&check_answer_dirpath;
  2589.  
  2590. # Check the validity of an answer whose type is existdirpath
  2591. # Return a clean answer if valid, or ''
  2592. sub check_answer_existdirpath {
  2593. my $answer = shift;
  2594. my $source = shift;
  2595.  
  2596. $answer = dir_remove_trailing_slashes($answer);
  2597.  
  2598. if (substr($answer, 0, 1) ne '/') {
  2599. print wrap('The path "' . $answer . '" is a relative path. Please enter '
  2600. . 'an absolute path.' . "\n\n", 0);
  2601. return '';
  2602. }
  2603.  
  2604. if (-d $answer) {
  2605. # The path is an existing directory
  2606. return $answer;
  2607. }
  2608.  
  2609. # The path is not a directory
  2610. if (file_name_exist($answer)) {
  2611. if ($source eq 'user') {
  2612. print wrap('The path "' . $answer . '" exists, but is not a directory.'
  2613. . "\n\n", 0);
  2614. }
  2615. } else {
  2616. if ($source eq 'user') {
  2617. print wrap('The path "' . $answer . '" is not an existing directory.'
  2618. . "\n\n", 0);
  2619. }
  2620. }
  2621. return '';
  2622. }
  2623. $gAnswerSize{'existdirpath'} = 20;
  2624. $gCheckAnswerFct{'existdirpath'} = \&check_answer_existdirpath;
  2625.  
  2626. # Check the validity of an answer whose type is initdirpath
  2627. # Return a clean answer if valid, or ''
  2628. sub check_answer_initdirpath {
  2629. my $answer = shift;
  2630. my $source = shift;
  2631. my $testdir;
  2632. my @rcDirList;
  2633.  
  2634. $answer = dir_remove_trailing_slashes($answer);
  2635.  
  2636. if (not (-d $answer)) {
  2637. if ($source eq 'user') {
  2638. print wrap('The path "' . $answer . '" is not an existing directory.' . "\n\n", 0);
  2639. }
  2640. return '';
  2641. }
  2642.  
  2643. if (vmware_product() eq 'tools-for-solaris') {
  2644. @rcDirList = ('rc0.d', 'rc1.d', 'rc2.d', 'rc3.d');
  2645. } else {
  2646. @rcDirList = ('rc0.d', 'rc1.d', 'rc2.d', 'rc3.d', 'rc4.d', 'rc5.d', 'rc6.d');
  2647. }
  2648.  
  2649. foreach $testdir (@rcDirList) {
  2650. if (not (-d $answer . '/' . $testdir)) {
  2651. if ($source eq 'user') {
  2652. print wrap('The path "' . $answer . '" is a directory which does not contain a ' .
  2653. $testdir . ' directory.' . "\n\n", 0);
  2654. }
  2655. return '';
  2656. }
  2657. }
  2658.  
  2659. return $answer;
  2660. }
  2661. $gAnswerSize{'initdirpath'} = 15;
  2662. $gCheckAnswerFct{'initdirpath'} = \&check_answer_initdirpath;
  2663.  
  2664. # Check the validity of an answer whose type is initscriptsdirpath
  2665. # Return a clean answer if valid, or ''
  2666. sub check_answer_initscriptsdirpath {
  2667. my $answer = shift;
  2668. my $source = shift;
  2669.  
  2670. $answer = dir_remove_trailing_slashes($answer);
  2671.  
  2672. if (not (-d $answer)) {
  2673. if ($source eq 'user') {
  2674. print wrap('The path "' . $answer . '" is not an existing directory.' . "\n\n", 0);
  2675. }
  2676. return '';
  2677. }
  2678.  
  2679. return $answer;
  2680. }
  2681. $gAnswerSize{'initscriptsdirpath'} = 15;
  2682. $gCheckAnswerFct{'initscriptsdirpath'} = \&check_answer_initscriptsdirpath;
  2683.  
  2684. # Check the validity of an answer whose type is authdport
  2685. # Return a clean answer if valid, or ''
  2686. sub check_answer_authdport {
  2687. my $answer = shift;
  2688. my $source = shift;
  2689.  
  2690. if (($answer =~ /^\d+$/) && ($answer > 0) && ($answer < 65536)) {
  2691. return $answer;
  2692. }
  2693. if ($source eq 'user') {
  2694. print wrap('The answer '. $answer . ' is invalid. Please enter a valid '
  2695. . 'port number in the range 1 to 65535.' . "\n\n", 0);
  2696. }
  2697. return '';
  2698. }
  2699.  
  2700. $gAnswerSize{'authdport'} = 5;
  2701. $gCheckAnswerFct{'authdport'} = \&check_answer_authdport;
  2702.  
  2703. # Check the validity of an answer whose type is username
  2704. # Return a clean answer if valid, or ''
  2705. sub check_answer_username {
  2706. my $answer = shift;
  2707. my $source = shift;
  2708.  
  2709. my ($name, $passwd, $uid, $gid) = getpwnam($answer);
  2710. if (!defined $name) {
  2711. print wrap('The answer '. $answer . ' is invalid. Please enter a valid '
  2712. . 'user on this system.' . "\n\n", 0);
  2713. return '';
  2714. }
  2715. return $answer;
  2716. }
  2717.  
  2718. $gAnswerSize{'username'} = 8;
  2719. $gCheckAnswerFct{'username'} = \&check_answer_username;
  2720.  
  2721. # Install one symbolic link
  2722. sub install_symlink {
  2723. my $to = shift;
  2724. my $name = shift;
  2725. my $default_overwrite = 'yes';
  2726. if (@_ >= 1) {
  2727. $default_overwrite = shift;
  2728. }
  2729.  
  2730. uninstall_file($name);
  2731. if (file_check_exist($name, $default_overwrite)) {
  2732. return;
  2733. }
  2734. # The file could be a symlink to another location. Remove it
  2735. unlink($name);
  2736. if (not symlink($to, $name)) {
  2737. error('Unable to create symbolic link "' . $name . '" pointing to file "'
  2738. . $to . '".' . "\n\n");
  2739. }
  2740. db_add_file($name, 0);
  2741. }
  2742.  
  2743. # Install one directory (recursively)
  2744. # flags are forwarded to install_file calls and recursive install_dir calls
  2745. sub install_dir {
  2746. my $src_dir = shift;
  2747. my $dst_dir = shift;
  2748. my $patchRef = shift;
  2749. my $flags = shift;
  2750. my $is_suid_dir = 0;
  2751. my %blackhash = ();
  2752. if (@_ >= 1) {
  2753. $is_suid_dir = shift;
  2754. }
  2755. if (@_ >= 1) {
  2756. %blackhash = map { $_ => 1 } @_;
  2757. }
  2758. my $file;
  2759. my $dir_existed = create_dir($dst_dir, $flags);
  2760.  
  2761. if ($dir_existed) {
  2762. my @statbuf;
  2763.  
  2764. @statbuf = stat($dst_dir);
  2765. if (not (defined($statbuf[2]))) {
  2766. error('Unable to get the access rights of destination directory "' . $dst_dir . '".' . "\n\n");
  2767. }
  2768.  
  2769. # Was bug 15880
  2770. if ( ($statbuf[2] & 0555) != 0555
  2771. && get_answer('Current access permissions on directory "' . $dst_dir
  2772. . '" will prevent some users from using '
  2773. . vmware_product_name()
  2774. . '. Do you want to set those permissions properly?',
  2775. 'yesno', 'yes') eq 'yes') {
  2776. safe_chmod(($statbuf[2] & 07777) | 0555, $dst_dir);
  2777. }
  2778. } else {
  2779. install_permission($src_dir, $dst_dir);
  2780. }
  2781.  
  2782. if ($is_suid_dir)
  2783. {
  2784. # Here is where we check (if necessary) for file ownership in this folder to actually "work"
  2785. # This is due to the fact that if the destdir is on a squash_root nfs mount, things fail miserably
  2786. my $tmpfilenam = $dst_dir . '/' . 'vmware_temp_'.$$;
  2787. if (not open(TESTFILE, '>' . $tmpfilenam)) {
  2788. error('Unable to write into ' . $dst_dir . "\n\n");
  2789. }
  2790. print TESTFILE 'garbage';
  2791. close(TESTFILE);
  2792. safe_chmod(04755, $tmpfilenam);
  2793. my @statbuf;
  2794. @statbuf = stat($tmpfilenam);
  2795. if ($statbuf[4]!=0 or ($statbuf[2] & 07000)!=04000) {
  2796. if (! $dir_existed)
  2797. {
  2798. # Remove the directory if we had to create it.
  2799. # XXX This could leave a dangling hierarhcy
  2800. # but that is a more complicated issue.
  2801. rmdir($dst_dir);
  2802. }
  2803. # Ask the user what to do, default to 'no'(abort install) to avoid infinite loop on --default.
  2804. my $answer = get_answer('The installer was unable to set-uid to root on files in ' . $dst_dir . '. Would you like ' .
  2805. 'to select a different directory? If you select no, the install will be aborted.','yesno','no');
  2806. if ($answer eq 'no')
  2807. {
  2808. # We have to clean up the ugliness before we abort.
  2809. uninstall();
  2810. error ('User aborted install.');
  2811. }
  2812. return 1;
  2813. }
  2814. unlink($tmpfilenam);
  2815. }
  2816.  
  2817. foreach $file (internal_ls($src_dir)) {
  2818. my $src_loc = $src_dir . '/' . $file;
  2819. my $dst_loc = $dst_dir . '/' . $file;
  2820.  
  2821. if (not $blackhash{$src_loc}) {
  2822. if (-l $src_loc) {
  2823. install_symlink(readlink($src_loc), $dst_loc);
  2824. } elsif (-d $src_loc) {
  2825. install_dir($src_loc, $dst_loc, $patchRef, $flags);
  2826. } else {
  2827. install_file($src_loc, $dst_loc, $patchRef, $flags);
  2828. }
  2829. }
  2830. }
  2831. return 0;
  2832. }
  2833.  
  2834. # Display the end-user license agreement
  2835. sub show_EULA {
  2836. if ((not defined($gDBAnswer{'EULA_AGREED'}))
  2837. || (db_get_answer('EULA_AGREED') eq 'no')) {
  2838. query('You must read and accept the ' . vmware_product_name()
  2839. . ' End User License Agreement to continue.'
  2840. . "\n" . 'Press enter to display it.', '', 0);
  2841.  
  2842. open(EULA, './doc/EULA') ||
  2843. error("$0: can't open EULA file: $!\n");
  2844.  
  2845. my $origRecordSeparator = $/;
  2846. undef $/;
  2847.  
  2848. my $eula = <EULA>;
  2849. close(EULA);
  2850.  
  2851. $/ = $origRecordSeparator;
  2852.  
  2853. $eula =~ s/(.{50,76})\s/$1\n/g;
  2854.  
  2855. # Trap the PIPE signal to avoid broken pipe errors on RHEL4 U4.
  2856. local $SIG{PIPE} = sub {};
  2857.  
  2858. open(PAGER, '| ' . $gHelper{'more'}) ||
  2859. error("$0: can't open $gHelper{'more'}: $!\n");
  2860. print PAGER $eula . "\n";
  2861. close(PAGER);
  2862.  
  2863. print "\n";
  2864.  
  2865. # Make sure there is no default answer here
  2866. if (get_answer('Do you accept? (yes/no)', 'yesno', '') eq 'no') {
  2867. print wrap('Please try again when you are ready to accept.' . "\n\n", 0);
  2868. uninstall_file($gInstallerMainDB);
  2869. exit 1;
  2870. }
  2871. print wrap('Thank you.' . "\n\n", 0);
  2872. }
  2873. }
  2874.  
  2875. # XXX This code is mostly duplicated from the main server installer.
  2876. sub build_perl_api {
  2877. my $control;
  2878. my $build_dir;
  2879. my $program;
  2880. my $cTmpDirPrefix = 'api-config';
  2881.  
  2882. foreach $program ('tar', 'perl', 'make', 'touch') {
  2883. if (not defined($gHelper{$program})) {
  2884. $gHelper{$program} = DoesBinaryExist_Prompt($program);
  2885. if ($gHelper{$program} eq '') {
  2886. error('Unable to continue.' . "\n\n");
  2887. }
  2888. }
  2889. }
  2890.  
  2891. print wrap('Installing the VMware VmPerl Scripting API.' . "\n", 0);
  2892.  
  2893. $control = './control.tar';
  2894. if (not (file_name_exist($control))) {
  2895. error('Unable to find the VMware VmPerl Scripting API. '
  2896. . 'You may want to re-install ' . vmware_product_name()
  2897. . '.' . "\n\n");
  2898. }
  2899.  
  2900. $build_dir = make_tmp_dir($cTmpDirPrefix);
  2901.  
  2902. if (system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($build_dir) . ' -xopf ' .
  2903. shell_string($control))) {
  2904. print wrap('Unable to untar the "' . $control . '" file in the "' . $build_dir .
  2905. '" directory.' . "\n\n", 0);
  2906. error('');
  2907. }
  2908.  
  2909. if (system('cd ' . shell_string($build_dir . '/control-only') . ' && ' .
  2910. shell_string($gHelper{'perl'}) . ' Makefile.PL > make.log 2>&1')) {
  2911. print wrap('Unable to create the VMware VmPerl Scripting API makefile.' . "\n\n", 0);
  2912.  
  2913. # Look for the header files needed to build the Perl module. If we don't
  2914. # find them, suggest to the user how they can install the files.
  2915. if (open(PERLINC, shell_string($gHelper{'perl'}) . ' -MExtUtils::Embed ' .
  2916. '-e perl_inc |')) {
  2917. my $inc = <PERLINC>;
  2918. close(PERLINC);
  2919. $inc =~ s/\s*-I//;
  2920. if (not file_name_exist($inc . '/perl.h')) {
  2921. print wrap('Could not find necessary components to build the '
  2922. . 'VMware VmPerl Scripting API. Look in your Linux '
  2923. . 'distribution to see if there is a perl-devel package. '
  2924. . 'Install that package if it exists and then re-run this '
  2925. . 'installation program.' . "\n\n", 0);
  2926. }
  2927. }
  2928. return(perl_config_fail($build_dir));
  2929. }
  2930.  
  2931. print wrap("\n", 0);
  2932. print wrap('Building the VMware VmPerl Scripting API.' . "\n\n", 0);
  2933.  
  2934. # Make sure we have a compiler available
  2935. if (get_cc() eq '') {
  2936. print wrap('Unable to install the VMware VmPerl Scripting API.', 0);
  2937. print wrap('A C compiler is required to install the API.' . "\n\n", 0);
  2938. remove_tmp_dir($build_dir);
  2939. return;
  2940. }
  2941.  
  2942. # We touch all our files in case the system clock is set to the past. Make will get confused and
  2943. # delete our shipped .o file(s).
  2944. # More code duplication from pkg_mgr.pl (really, really bad)
  2945. system(shell_string($gHelper{'touch'}) . ' '
  2946. . shell_string($build_dir . '/control-only') . '/* >>'
  2947. . shell_string($build_dir . '/control-only') . '/make.log 2>&1');
  2948.  
  2949. if (system(shell_string($gHelper{'make'}) . ' -C '
  2950. . shell_string($build_dir . '/control-only') . ' '
  2951. . shell_string('CC=' . $gHelper{'gcc'}) . ' '
  2952. . ' >>' . shell_string($build_dir . '/control-only') . '/make.log 2>&1')) {
  2953. print wrap('Unable to compile the VMware VmPerl Scripting API.' . "\n\n", 0);
  2954. return(perl_config_fail($build_dir));
  2955. }
  2956.  
  2957. print wrap("Installing the VMware VmPerl Scripting API.\n\n", 0);
  2958.  
  2959.  
  2960. # XXX This is deeply broken: we let a third party tool install a file without
  2961. # adding it to our installer database. This file will never get
  2962. # uninstalled by our uninstaller
  2963. if (system(shell_string($gHelper{'make'}) . ' -C '
  2964. . shell_string($build_dir . '/control-only') . ' '
  2965. . shell_string('CC=' . $gHelper{'gcc'}) . ' '
  2966. . ' install >>' . shell_string($build_dir . '/control-only')
  2967. . '/make.log 2>&1')) {
  2968. print wrap('Unable to install the VMware VmPerl Scripting API.' . "\n\n", 0);
  2969. return(perl_config_fail($build_dir));
  2970. }
  2971.  
  2972. print wrap('The installation of the VMware VmPerl Scripting API succeeded.' . "\n\n", 0);
  2973. remove_tmp_dir($build_dir);
  2974. }
  2975.  
  2976. # XXX Mostly duplicated from the main server installer.
  2977. # Common error message when we can't compile or install our perl modules
  2978. sub perl_config_fail {
  2979. my $dir = shift;
  2980.  
  2981. print wrap('********' . "\n". 'The VMware VmPerl Scripting API was not '
  2982. . 'installed. Errors encountered during compilation and '
  2983. . 'installation of the module can be found here: ' . $dir
  2984. . "\n\n" . 'You will not be able to use the "vmware-cmd" '
  2985. . 'program.' . "\n\n" . 'Errors can be found in the log file: '
  2986. . shell_string($dir . '/control-only/make.log')
  2987. . "\n" . '********' . "\n\n", 0);
  2988. error('');
  2989. }
  2990.  
  2991. # XXX Duplicated in config.pl.
  2992. sub solaris_os_version {
  2993. my $solVersion = direct_command(shell_string($gHelper{'uname'}) . ' -r');
  2994. chomp($solVersion);
  2995. my ($major, $minor) = split /\./, $solVersion;
  2996. return ($major, $minor);
  2997. }
  2998.  
  2999. # Configures gtk. Returns 1 on success, 0 on failure.
  3000. sub configure_gtk2 {
  3001. if (vmware_product() eq 'tools-for-linux') {
  3002. # Setup the environment to match what configure-gtk expects,
  3003. # as too the wrappers for vmware-user and vmware-toolbox.
  3004. my $is64BitUserland = is64BitUserLand();
  3005. my $libdir = db_get_answer('LIBDIR');
  3006. my $libbindir = $libdir . ($is64BitUserland ? '/bin64' : '/bin32');
  3007. my $libsbindir = $libdir . ($is64BitUserland ? '/sbin64' : '/sbin32');
  3008. my $liblibdir = $libdir . ($is64BitUserland ? '/lib64' : '/lib32');
  3009. # Generic spots for the vmware-user/toolbox wrapper
  3010. # to access so it won't need to know lib32, etc.
  3011. install_symlink($liblibdir, $libdir . "/lib");
  3012. install_symlink($libbindir, $libdir . "/bin");
  3013. install_symlink($libsbindir, $libdir . "/sbin");
  3014. install_symlink($liblibdir . "/libconf", $libdir . "/libconf");
  3015.  
  3016. # Uses generic configure-gtk.sh.
  3017. } elsif (vmware_product() eq 'tools-for-solaris') {
  3018. my $is64BitUserland = is64BitUserLand();
  3019. my $libdir = db_get_answer('LIBDIR');
  3020. my $libbindir = sprintf "%s/bin/%s", $libdir, ($is64BitUserland ? '/amd64' :
  3021. '/i86');
  3022. my $liblibdir = $libdir . ($is64BitUserland ? '/lib/amd64' : '/lib/i86');
  3023.  
  3024. install_symlink($liblibdir . "/libconf", $libdir . "/libconf");
  3025.  
  3026. my ($major, $minor) = solaris_os_version();
  3027. return system($minor == 11 ? '/bin/bash' : '/usr/bin/bash',
  3028. sprintf '%s/configure-gtk.sh', $libbindir) == 0;
  3029. }
  3030.  
  3031. return system(sprintf "%s/bin/configure-gtk.sh", db_get_answer("LIBDIR")) == 0;
  3032. }
  3033.  
  3034. # Check available space when asking the user for destination directory.
  3035. sub spacechk_answer {
  3036. my $msg = shift;
  3037. my $type = shift;
  3038. my $default = shift;
  3039. my $srcDir = shift;
  3040. my $id = shift;
  3041. my $ifdefault = shift;
  3042. my $answer;
  3043. my $space = -1;
  3044.  
  3045. while ($space < 0) {
  3046.  
  3047. if (!defined($id)) {
  3048. $answer = get_answer($msg, $type, $default);
  3049. } else {
  3050. if (!defined($ifdefault)) {
  3051. $answer = get_persistent_answer($msg, $id, $type, $default);
  3052. } else {
  3053. $answer = get_persistent_answer($msg, $id, $type, $default, $ifdefault);
  3054. }
  3055. }
  3056.  
  3057. # XXX check $answer for a null value which can happen with the get_answer
  3058. # in config.pl but not with the get_answer in pkg_mgr.pl. Moving these
  3059. # (get_answer, get_persistent_answer) routines into util.pl eventually.
  3060. if ($answer && ($space = check_disk_space($srcDir, $answer)) < 0) {
  3061. my $lmsg;
  3062. $lmsg = 'There is insufficient disk space available in ' . $answer
  3063. . '. Please make at least an additional ' . -$space
  3064. . 'KB available';
  3065. if ($gOption{'default'} == 1) {
  3066. error($lmsg . ".\n");
  3067. }
  3068. print wrap($lmsg . " or choose another directory.\n", 0);
  3069. }
  3070. }
  3071. return $answer;
  3072. }
  3073.  
  3074. # Handle the installation and configuration of vmware's perl module
  3075. sub install_perl_api {
  3076. my $rootdir;
  3077. my $answer;
  3078. my $mandir;
  3079. my $docdir;
  3080. my %patch;
  3081.  
  3082. undef %patch;
  3083. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  3084.  
  3085. $rootdir = '/usr';
  3086.  
  3087. $answer = spacechk_answer('In which directory do you want to install '
  3088. . 'the executable files?', 'dirpath',
  3089. $rootdir . '/bin', './bin', 'BINDIR');
  3090. undef %patch;
  3091. install_dir('./bin', $answer, \%patch, 0x1);
  3092. $gIsUninstallerInstalled = 1;
  3093.  
  3094. $rootdir = internal_dirname($answer);
  3095. # Don't display a double slash (was bug 14109)
  3096. if ($rootdir eq '/') {
  3097. $rootdir = '';
  3098. }
  3099.  
  3100. # We don't use default answers here because once the user has
  3101. # selected the root directory, we can give him better default answers than
  3102. # his/her previous answers but we do want to make sure the directory
  3103. # chosen has enough space to hold the data.
  3104.  
  3105. $answer = spacechk_answer('In which directory do you want to install '
  3106. . 'the library files?', 'dirpath',
  3107. $rootdir . '/lib/vmware-api', './lib');
  3108. db_add_answer('LIBDIR', $answer);
  3109. undef %patch;
  3110. install_dir('./lib', $answer, \%patch, 0x1);
  3111.  
  3112. $docdir = $rootdir . '/share/doc';
  3113. if (not (-d $docdir)) {
  3114. $docdir = $rootdir . '/doc';
  3115. }
  3116. $answer = spacechk_answer('In which directory do you want to install the '
  3117. . 'documentation files?', 'dirpath',
  3118. $docdir . '/vmware-api', './doc');
  3119. db_add_answer('DOCDIR', $answer);
  3120. undef %patch;
  3121. install_dir('./doc', $answer, \%patch, 0x1);
  3122.  
  3123. build_perl_api();
  3124. }
  3125.  
  3126.  
  3127. sub prelink_fix {
  3128. my $source = "/etc/vmware-tools/vmware-tools-prelink.conf";
  3129. my $dest = '/etc/prelink.conf.d/vmware-tools-prelink.conf';
  3130. my $prelink_file = '/etc/prelink.conf';
  3131. my $libdir = db_get_answer_if_exists('LIBDIR');
  3132. my %patch;
  3133.  
  3134. if (defined($libdir)) {
  3135. %patch = ('@@LIBDIR@@' => $libdir);
  3136. } else {
  3137. error ("LIBDIR must be defined before prelink_fix is called.\n");
  3138. }
  3139.  
  3140. if (-d internal_dirname($dest)) {
  3141. install_file($source, $dest, \%patch, 1);
  3142. } elsif (-f $prelink_file) {
  3143. # Readin our prelink file, do the appropreiate substitutions, and
  3144. # block insert it into the prelink.conf file.
  3145.  
  3146. my $key;
  3147. my $value;
  3148. my $line;
  3149. my $to_append = '';
  3150.  
  3151. if (not open(FH, $source)) {
  3152. error("Could not open $source\n");
  3153. }
  3154.  
  3155. foreach $line (<FH>) {
  3156. chomp ($line);
  3157. while (($key, $value) = each %patch) {
  3158. $line =~ s/$key/$value/g;
  3159. }
  3160. $to_append .= $line . "\n";
  3161. }
  3162.  
  3163. close FH;
  3164.  
  3165. if (block_insert($prelink_file, '^ *-b', $cMarkerBegin,
  3166. $to_append, $cMarkerEnd) == 1) {
  3167. db_add_answer('PRELINK_CONFED', $prelink_file);
  3168. }
  3169. }
  3170. }
  3171.  
  3172. sub prelink_restore {
  3173. my $prelink_file = db_get_answer_if_exists('PRELINK_CONFED');
  3174.  
  3175. if (defined $prelink_file) {
  3176. block_restore($prelink_file, $cMarkerBegin, $cMarkerEnd);
  3177. }
  3178. }
  3179.  
  3180.  
  3181. sub generate_initscript_patch {
  3182. my $lsbInitInfo = shift;
  3183. my $chkconfigInfo = shift;
  3184. my %patch = ();
  3185.  
  3186. my $init_style = db_get_answer_if_exists('INIT_STYLE');
  3187.  
  3188. # We need to check whether or not the system has either insserv, or chkconfig,
  3189. # or neither. Depending on what we find, we will modify the patch variable
  3190. # so that our startup script has only the info it needs. This gets us around
  3191. # the issue where RedHat tries (unsuccessfully) to use LSB info to determine where
  3192. # our scripts need to start/stop.
  3193.  
  3194. if ($init_style eq 'update-rc.d') {
  3195. %patch = ('##VMWARE_INIT_INFO##' => "$lsbInitInfo");
  3196. } elsif ($init_style eq 'lsb') {
  3197. %patch = ('##VMWARE_INIT_INFO##' => "$lsbInitInfo");
  3198. } elsif ($init_style eq 'chkconfig') {
  3199. %patch = ('##VMWARE_INIT_INFO##' => "$chkconfigInfo");
  3200. } elsif ($init_style eq 'custom') {
  3201. %patch = ('##VMWARE_INIT_INFO##' => "$chkconfigInfo\n\n$lsbInitInfo");
  3202. }
  3203. return \%patch;
  3204. }
  3205.  
  3206. sub install_content_tools_etc_openvmcompat {
  3207. my @files = (
  3208. 'vmware-tools-libraries.conf',
  3209. 'manifest.txt.shipped',
  3210. 'vmware-tools-prelink.conf',
  3211. 'installer.sh',
  3212. 'not_configured'
  3213. );
  3214. my $f;
  3215.  
  3216. if($have_thinprint eq 'yes') {
  3217. push @files, 'tpvmlp.conf';
  3218. }
  3219.  
  3220. foreach $f (@files) {
  3221. install_file('./etc/' . $f, $gRegistryDir . '/' . $f, undef, 0);
  3222. }
  3223. }
  3224.  
  3225. sub install_content_vgauth {
  3226. my $rootdir = shift;
  3227. my %patch;
  3228.  
  3229. if(vmware_product() ne 'tools-for-linux') {
  3230. return;
  3231. }
  3232.  
  3233. my $vgauth_dir = $rootdir . '/lib/vmware-vgauth';
  3234.  
  3235. install_dir('./vgauth', $vgauth_dir, undef, 0x1);
  3236. %patch = ('@@VGAUTHSCHEMADIR@@' => "$vgauth_dir/schemas");
  3237. install_file("$cInstallerDir/vgauth.conf", '/etc/vmware-tools/vgauth.conf', \%patch, 0x01);
  3238. }
  3239.  
  3240. # Install the necessary conf file and directories
  3241. # for 'grabbitmqproxy' plugin in 'VMware Tools'.
  3242. sub install_content_guestproxy {
  3243. my $rootdir = shift;
  3244.  
  3245. if(vmware_product() ne 'tools-for-linux') {
  3246. return;
  3247. }
  3248.  
  3249. my $guestproxy_ssl_conf = $gRegistryDir . "/guestproxy-ssl.conf";
  3250.  
  3251. install_file("$cInstallerDir/guestproxy-ssl.conf",
  3252. $guestproxy_ssl_conf, undef, 0x01);
  3253. }
  3254.  
  3255. # Uninstall proxy data files and directories for
  3256. # the 'grabbitmqproxy' plugin in 'VMware Tools'.
  3257. sub uninstall_content_guestproxy {
  3258.  
  3259. if(vmware_product() ne 'tools-for-linux') {
  3260. return;
  3261. }
  3262.  
  3263. if ($gOption{'upgrade'} == 0 && $gOption{'preserve-guest-proxy-data'} == 0) {
  3264.  
  3265. my $bindir = db_get_answer('BINDIR');
  3266. my $certToolPath = $bindir . '/vmware-guestproxycerttool';
  3267.  
  3268. if (system(shell_string($certToolPath) . ' -e')) {
  3269. print wrap("Failed to remove guest proxy data, error: " . $? . "\n");
  3270. }
  3271. }
  3272. }
  3273.  
  3274. # Install files for caf
  3275. sub install_content_caf {
  3276. my $rootdir = shift;
  3277. my $libdir = db_get_answer('LIBDIR');
  3278. my $caf_lib_dir;
  3279. my $caf_etc_dir = '/etc/vmware-caf';
  3280. my $caf_var_dir;
  3281. my %patch;
  3282. my $f;
  3283.  
  3284. if(vmware_product() ne 'tools-for-linux') {
  3285. return;
  3286. }
  3287.  
  3288. $caf_lib_dir = spacechk_answer('In which directory do you want to install '
  3289. . 'the common agent library files?', 'dirpath', $rootdir
  3290. . '/lib', './lib');
  3291. db_add_answer('CAFLIBDIR', $caf_lib_dir);
  3292.  
  3293. $caf_var_dir = spacechk_answer('In which directory do you want to install '
  3294. . 'the common agent transient files?', 'dirpath',
  3295. '/var/lib', './lib');
  3296. db_add_answer('CAFVARDIR', $caf_var_dir);
  3297.  
  3298. create_dir($caf_lib_dir . '/vmware-caf', 1);
  3299. install_dir('./caf/usr/lib/vmware-caf', $caf_lib_dir . '/vmware-caf', \%patch, 1);
  3300. install_dir('./caf/etc/vmware-caf', $caf_etc_dir, \%patch, 0x1);
  3301. create_dir($caf_var_dir . '/vmware-caf', 1);
  3302. install_dir('./caf/var/lib/vmware-caf', $caf_var_dir . '/vmware-caf', \%patch, 1);
  3303.  
  3304. foreach $f ('CommAmqpListener', 'ManagementAgentHost') {
  3305. create_dir($libdir . '/lib64/lib' . $f . '.so', 1);
  3306. install_file('./caf/usr/lib/vmware-caf/pme/lib/lib' . $f . '.so',
  3307. $libdir . '/lib64/lib' . $f . '.so/lib' . $f . '.so',
  3308. \%patch, 1);
  3309. }
  3310. }
  3311.  
  3312. # Recurse sub directory, and remove all files that are not in db.
  3313. # We cannot just remove the whole sub directory, or we will get
  3314. # complains later for files that are in the db, creating unnecessary noise.
  3315. # Code shamelessly taken from http://www.perlmonks.org/?node_id=136482 and
  3316. # adjusted.
  3317. sub uninstall_content_caf_process_files {
  3318. my $path = shift;
  3319. opendir (DIR, $path) or return ();
  3320.  
  3321. my @files =
  3322. map { $path . '/' . $_ }
  3323. grep { !/^\.{1,2}$/ }
  3324. readdir (DIR);
  3325.  
  3326. closedir (DIR);
  3327.  
  3328. for (@files) {
  3329. if (-d $_) {
  3330. uninstall_content_caf_process_files ($_);
  3331. if (not db_file_in($_)) {
  3332. rmdir($_);
  3333. }
  3334. } else {
  3335. if (not db_file_in($_)) {
  3336. unlink($_);
  3337. }
  3338. }
  3339. }
  3340. }
  3341.  
  3342. # unstall files for caf
  3343. sub uninstall_content_caf {
  3344. my $rootdir = shift;
  3345. my $caf_var_dir = db_get_answer('CAFVARDIR');
  3346.  
  3347. uninstall_content_caf_process_files($caf_var_dir . '/vmware-caf');
  3348. }
  3349.  
  3350.  
  3351.  
  3352. # Install the content of the tools tar package
  3353. sub install_content_tools {
  3354. my $rootdir;
  3355. my $answer;
  3356. my %patch;
  3357. my $mandir;
  3358. my $docdir;
  3359. my @upstartJobInfo;
  3360.  
  3361. if ($open_vm_compat) {
  3362. install_content_tools_etc_openvmcompat();
  3363. } else {
  3364. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  3365. }
  3366.  
  3367. if (defined($gOption{'prefix'})) {
  3368. $rootdir = $gOption{'prefix'};
  3369. } elsif (vmware_product() eq 'tools-for-freebsd') {
  3370. $rootdir = '/usr/local';
  3371. } elsif (vmware_product() eq 'tools-for-solaris') {
  3372. $rootdir = '/usr';
  3373. } else {
  3374. $rootdir = '/usr';
  3375. }
  3376. $answer = spacechk_answer('In which directory do you want to '
  3377. . 'install the binary files?', 'dirpath',
  3378. $rootdir . '/bin', './bin', 'BINDIR');
  3379. undef %patch;
  3380. if ($open_vm_compat) {
  3381. # vm-support is owned by open-vm-tools, don't overwrite:
  3382. install_dir('./bin', $answer, \%patch, 0x1, 0, './bin/vm-support');
  3383. } else {
  3384. install_dir('./bin', $answer, \%patch, 0x1);
  3385. }
  3386.  
  3387. $rootdir = internal_dirname($answer);
  3388. # Don't display a double slash (was bug 14109)
  3389. if ($rootdir eq '/') {
  3390. $rootdir = '';
  3391. }
  3392.  
  3393. # Finds the location of the initscripts dir
  3394. # As a side effect, sets INITSCRIPTSDIR in the locations database.
  3395. $answer = get_initscriptsdir();
  3396.  
  3397. if (vmware_product() eq 'tools-for-linux' &&
  3398. (@upstartJobInfo = locate_upstart_jobinfo())) {
  3399. my ($jobPath, $jobSuffix) = @upstartJobInfo;
  3400. my $upstartJobFile = "$jobPath/vmware-tools$jobSuffix";
  3401.  
  3402. # Step 1: Install services script in $gRegistryDir.
  3403. install_file($cStartupFileName, "$gRegistryDir/services.sh", undef, 0);
  3404. # Step 2: Install Upstart job.
  3405. install_file("$cInstallerDir/upstart-job.conf", $upstartJobFile, undef, 0);
  3406. db_add_answer('UPSTARTJOB', $upstartJobFile);
  3407.  
  3408. if($have_thinprint eq 'yes') {
  3409. my $upstartJobFileThinPrint = "$jobPath/vmware-tools-thinprint$jobSuffix";
  3410. # Step 1: Install services script in $gRegistryDir.
  3411. install_file($cStartupFileNameThinPrint, "$gRegistryDir/thinprint.sh", undef, 0);
  3412. # Step 2: Install Upstart job.
  3413. my %patch = ('##UPSTART_STARTON##' => 'start on started cups',
  3414. '##UPSTART_STOPON##' => 'stop on stopping cups');
  3415. install_file("$cInstallerDir/thinprint.conf", $upstartJobFileThinPrint, \%patch, 0);
  3416. }
  3417. } else {
  3418. db_remove_answer('UPSTARTJOB');
  3419. # install the service script.
  3420. if (vmware_product() eq 'tools-for-freebsd') {
  3421. $answer = get_answer('In which directory do you want to install the '
  3422. . 'startup script?', 'dirpath', $answer);
  3423. create_dir($answer,0);
  3424. }
  3425.  
  3426. # Figure out which style is used to update init scripts
  3427. my $insserv = internal_which('insserv');
  3428. my $chkconfig = internal_which('chkconfig');
  3429. my $update_rc_dot_d = internal_which('update-rc.d');
  3430. my $lsbInitInfo;
  3431.  
  3432. if ( "$update_rc_dot_d" ne "") {
  3433. db_add_answer('INIT_STYLE', 'update-rc.d');
  3434. } elsif ( "$insserv" ne "") {
  3435. db_add_answer('INIT_STYLE', 'lsb');
  3436. } elsif ("$chkconfig" ne '') {
  3437. db_add_answer('INIT_STYLE', 'chkconfig');
  3438. } else {
  3439. db_add_answer('INIT_STYLE', 'custom');
  3440. }
  3441.  
  3442. $lsbInitInfo = $cLSBInitInfoTempl;
  3443. if ( "$update_rc_dot_d" ne "") {
  3444. # Ubuntu's update-rc.d insists that the values in the header
  3445. # match those in its arguments, and we need to start early:
  3446. $lsbInitInfo =~ s/__DEFAULT_START__/S/g;
  3447. $lsbInitInfo =~ s/__DEFAULT_STOP__/0 6/g;
  3448. } elsif ( -e '/etc/SuSE-release' ) {
  3449. # we don't want tools to run in runlevel 4 in SuSE (bug #933899)
  3450. $lsbInitInfo =~ s/__DEFAULT_START__/2 3 5/g;
  3451. $lsbInitInfo =~ s/__DEFAULT_STOP__/0 1 6/g;
  3452. } else {
  3453. $lsbInitInfo =~ s/__DEFAULT_START__/2 3 4 5/g;
  3454. $lsbInitInfo =~ s/__DEFAULT_STOP__/0 1 6/g;
  3455. }
  3456.  
  3457. my $patch = generate_initscript_patch($lsbInitInfo, $cChkconfigInfo);
  3458. install_file($cStartupFileName,
  3459. $answer . (vmware_product() eq 'tools-for-freebsd' ?
  3460. '/vmware-tools.sh' : '/vmware-tools'), $patch, 0x1);
  3461.  
  3462. # no thinprint for FreeBSD or Solaris:
  3463. if((vmware_product() eq 'tools-for-linux') && ($have_thinprint eq 'yes')) {
  3464.  
  3465. my $lsbInitInfoTP = $cLSBInitInfoTPTempl;
  3466. if ( -e '/etc/SuSE-release' ) {
  3467. # we don't want tools to run in runlevel 4 in SuSE (bug #933899)
  3468. $lsbInitInfoTP =~ s/__DEFAULT_START__/2 3 5/g;
  3469. $lsbInitInfoTP =~ s/__DEFAULT_STOP__/0 1 6/g;
  3470. # It's 'cupsd' (not: 'cups') for SuSE:
  3471. $lsbInitInfoTP =~ s/__CUPS__/cupsd/g;
  3472. } else {
  3473. $lsbInitInfoTP =~ s/__DEFAULT_START__/2 3 4 5/g;
  3474. $lsbInitInfoTP =~ s/__DEFAULT_STOP__/0 1 6/g;
  3475. $lsbInitInfoTP =~ s/__CUPS__/cups/g;
  3476. }
  3477.  
  3478. $patch = generate_initscript_patch($lsbInitInfoTP, $cChkconfigInfoThinPrint);
  3479. install_file($cStartupFileNameThinPrint,
  3480. $answer. '/vmware-tools-thinprint', $patch, 0x1);
  3481. }
  3482.  
  3483. # on systems using systemd, we need to call 'systemctl daemon-reload':
  3484. my $systemctl_path = internal_which('systemctl');
  3485. if ($systemctl_path ne '') {
  3486. system("$systemctl_path daemon-reload");
  3487. }
  3488.  
  3489. }
  3490.  
  3491. $gIsUninstallerInstalled = 1;
  3492.  
  3493. # We don't use get_persistent_answer() here because once the user has
  3494. # selected the root directory, we can give him better default answers than
  3495. # his/her previous answers but we do want to make sure the directory
  3496. # chosen has enough space to hold the data.
  3497.  
  3498. $answer = get_answer('In which directory do you want to install '
  3499. . 'the daemon files?', 'dirpath', $rootdir . '/sbin');
  3500. db_add_answer('SBINDIR', $answer);
  3501. undef %patch;
  3502. create_dir($answer, 0x1);
  3503.  
  3504. $answer = spacechk_answer('In which directory do you want to install '
  3505. . 'the library files?', 'dirpath', $rootdir
  3506. . '/lib/vmware-tools', './lib');
  3507. db_add_answer('LIBDIR', $answer);
  3508.  
  3509. # Now that we know the LIBDIR, we need to add a rule to /etc/prelink.conf
  3510. # to prevent it from toying with apploader or any of our apps.
  3511. #
  3512. # Note: We have no choice but to fix this here because time is a factor.
  3513. # If we don't modify the config file here, prelink could be
  3514. # invoked by cron and would modify our binaries before config.pl
  3515. # is run. Modifying the prelink.conf file here should prevent
  3516. # that from happening.
  3517. if (vmware_product() eq 'tools-for-linux') {
  3518. prelink_fix();
  3519. }
  3520.  
  3521. undef %patch;
  3522. install_dir('./lib', $answer, \%patch, 0x1);
  3523.  
  3524. if ($open_vm_compat == 0) {
  3525.  
  3526. if ($have_caf eq 'yes') {
  3527. install_content_caf($rootdir);
  3528. }
  3529. if ($have_grabbitmqproxy eq 'yes') {
  3530. install_content_guestproxy($rootdir);
  3531. }
  3532. if ($have_vgauth eq 'yes') {
  3533. install_content_vgauth($rootdir);
  3534. }
  3535. }
  3536.  
  3537. # We don't yet maintain ownership and permissions metadata for all the
  3538. # files we install. For the timebeing until vmis obsoletes this code,
  3539. # this will workaround the scenario of the install tarball being extracted
  3540. # as a user, and thus the suid bit on vmware-user-suid-wrapper being
  3541. # cleared before install.
  3542.  
  3543. # Setuid root
  3544. if (vmware_product() eq 'tools-for-freebsd') {
  3545. safe_chmod(04555, $answer . '/bin32-63/vmware-user-suid-wrapper');
  3546. safe_chmod(04555, $answer . '/bin64-63/vmware-user-suid-wrapper');
  3547. } elsif (vmware_product() eq 'tools-for-solaris') {
  3548. # note: for solaris, the amd64 version is a symlink to this i86 version
  3549. safe_chmod(04555, $answer . '/bin/i86/vmware-user-suid-wrapper');
  3550. } elsif (vmware_product() eq 'tools-for-linux') {
  3551. safe_chmod(04555, $answer . '/bin32/vmware-user-suid-wrapper');
  3552. safe_chmod(04555, $answer . '/bin64/vmware-user-suid-wrapper');
  3553. }
  3554.  
  3555. # Deal with hgfsmounter which is not suid anymore
  3556. # .. and with vmblockmounter as well.
  3557. if (vmware_product() eq 'tools-for-linux') {
  3558. safe_chmod(0555, $answer . '/sbin32/vmware-hgfsmounter');
  3559. safe_chmod(0555, $answer . '/sbin64/vmware-hgfsmounter');
  3560. } elsif (vmware_product() eq 'tools-for-solaris') {
  3561. safe_chmod(0555, $answer . '/sbin/i86/vmware-hgfsmounter');
  3562. safe_chmod(0555, $answer . '/sbin/amd64/vmware-hgfsmounter');
  3563. safe_chmod(0555, $answer . '/sbin/i86/vmware-vmblockmounter');
  3564. safe_chmod(0555, $answer . '/sbin/amd64/vmware-vmblockmounter');
  3565. } elsif (vmware_product() eq 'tools-for-freebsd') {
  3566. safe_chmod(0555, $answer . '/sbin32-63/vmware-vmblockmounter');
  3567. safe_chmod(0555, $answer . '/sbin64-63/vmware-vmblockmounter');
  3568. }
  3569.  
  3570. $docdir = $rootdir . '/share/doc';
  3571. if (not (-d $docdir)) {
  3572. $docdir = $rootdir . '/doc';
  3573. }
  3574. $answer = spacechk_answer('In which directory do you want to install the '
  3575. . 'documentation files?', 'dirpath', $docdir
  3576. . '/vmware-tools', './doc');
  3577. db_add_answer('DOCDIR', $answer);
  3578. undef %patch;
  3579. install_dir('./doc', $answer, \%patch, 0x1);
  3580.  
  3581. #
  3582. # Modify vmware-user.desktop so that the Execute variable gets
  3583. # a full path to the vmware-user binary instead of having to
  3584. # rely on the PATH var being set correctly.
  3585. #
  3586. # See bug 368867 for details. -astiegmann
  3587. #
  3588. my $execStr = 'Exec=' . db_get_answer('BINDIR') . '/vmware-user';
  3589. my $filePath = $gRegistryDir . '/vmware-user.desktop';
  3590. %patch = ('Exec=.*$' => $execStr);
  3591. internal_sed ('./etc/vmware-user.desktop', $filePath, 0, \%patch);
  3592.  
  3593. # re-add file to database so they it will not stay behind on uninstall
  3594. # see bug #745860
  3595. db_add_file($filePath, 0x1);
  3596. }
  3597.  
  3598. sub uninstall_content_legacy_tools {
  3599. my $OldInstallerDB = '/etc/vmware-tools/tools_log';
  3600. my $OldInstallerDBOld = '/etc/vmware/tools_log';
  3601. my $TmpMainDB = $gInstallerMainDB;
  3602. my $File;
  3603. my @Files;
  3604. my $MovedFile;
  3605. my $LinkedFile;
  3606. my $answer;
  3607. my $runlevel;
  3608.  
  3609. # This is necessary for old installations of the tools
  3610. # when /etc/vmware was one and unique dump for all the products
  3611. if (-e $OldInstallerDBOld) {
  3612. $OldInstallerDB = $OldInstallerDBOld;
  3613. }
  3614. if (!-e $OldInstallerDB) {
  3615. # Old tools database not found, assume that the system is clean.
  3616. return;
  3617. }
  3618. # Swap the db with the old one temporarely.
  3619. $gInstallerMainDB = $OldInstallerDB;
  3620.  
  3621. db_load();
  3622. if (not open(INSTALLDB, '>>' . $gInstallerMainDB)) {
  3623. error('Unable to open the tar installer database ' . $gInstallerMainDB
  3624. . ' in write-mode.' . "\n\n");
  3625. }
  3626.  
  3627. $answer = get_answer('An old installation of the tools is detected. '
  3628. . 'Should this installation be removed ?',
  3629. 'yesno', 'yes');
  3630. if ($answer eq 'no') {
  3631. error('');
  3632. }
  3633.  
  3634. # Stop the services
  3635. foreach $File (keys %gDBFile) {
  3636. if ($File =~ /\S+\/dualconf(\.sh)?$/) {
  3637. system(shell_string($File) . ' stop');
  3638. print "\n";
  3639. last;
  3640. }
  3641. }
  3642. # Remove the files
  3643. foreach $File (keys %gDBFile) {
  3644. if ($File !~ /\/tmp\S+/) {
  3645. uninstall_file($File);
  3646. }
  3647. }
  3648. # Remove the links
  3649. foreach $LinkedFile (keys %gDBLink) {
  3650. unlink $LinkedFile;
  3651. }
  3652. # At last, replace the original files.
  3653. foreach $MovedFile (keys %gDBMove) {
  3654. # XXX we do not have a timestamp for those files so we can't
  3655. # know if the user changed it, so I back it up.
  3656. if (-e $gDBMove{$MovedFile}) {
  3657. backup_file($gDBMove{$MovedFile});
  3658. unlink $gDBMove{$MovedFile};
  3659. }
  3660. if (-e $MovedFile) {
  3661. if ($MovedFile =~ /\S+\.org/) {
  3662. rename $MovedFile, $gDBMove{$MovedFile};
  3663. } elsif ($gDBMove{$MovedFile} =~ /\.new$/) {
  3664. # Nothing to do for /etc/rc and /etc/rc.shutdown
  3665. } else {
  3666. backup_file($MovedFile);
  3667. unlink $MovedFile;
  3668. }
  3669. }
  3670. }
  3671.  
  3672. # Clean up the broken links.
  3673. foreach $File (qw(/etc/modules.conf /etc/conf.modules /etc/XF86Config
  3674. /etc/X11/XF86Config /etc/X11/XF86Config-4)) {
  3675. if ((-l $File) && (-e ($File . '.org'))) {
  3676. unlink $File;
  3677. rename $File . '.org', $File;
  3678. }
  3679. }
  3680.  
  3681. get_initscriptsdir();
  3682. $Files[0] = db_get_answer('INITSCRIPTSDIR') . '/vmmemctl';
  3683. foreach $runlevel ('0', '1', '2', '3', '4', '5', '6', 'S', 's') {
  3684. push @Files, db_get_answer('INITDIR') . '/rc' . $runlevel
  3685. . '.d/S99vmmemctl';
  3686. }
  3687. # Cleanup the files that aren't mentionned in the install database.
  3688. foreach $File (@Files) {
  3689. if (file_name_exist($File)) {
  3690. unlink $File;
  3691. }
  3692. }
  3693.  
  3694. db_save();
  3695. unlink $gInstallerMainDB;
  3696.  
  3697. if (direct_command('LANG=C ' .
  3698. shell_string(vmware_product() eq 'tools-for-freebsd' ?
  3699. $gHelper{'kldstat'} : $gHelper{'lsmod'})) =~
  3700. /vmmemctl/) {
  3701. print wrap('The uninstallation of legacy tools completed. '
  3702. . 'Please restart this virtual machine to ensure that '
  3703. . 'all the loaded components are removed from the memory and '
  3704. . 'run this installer again to continue with the upgrade.'
  3705. . "\n\n", 0);
  3706. exit 0;
  3707. }
  3708. # Restore the original database file name in case we don't have
  3709. # to reboot because of the loaded vmmemctl.
  3710. $gInstallerMainDB = $TmpMainDB;
  3711. }
  3712.  
  3713. #BEGIN UNINSTALLER SECTION
  3714. # Uninstaller section for old style MUI installer: Most of this code is
  3715. # directly copied over from the old installer
  3716. my %gConfData;
  3717.  
  3718. # END UNINSTALLER SECTION
  3719. # Install the content of the tar package
  3720. sub install_content {
  3721. my $rootdir;
  3722. my $answer;
  3723. my %patch;
  3724. my $mandir;
  3725. my $docdir;
  3726. my $initdir;
  3727. my $libdir;
  3728. my $initscriptsdir;
  3729.  
  3730. undef %patch;
  3731. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  3732.  
  3733. $rootdir = '/usr';
  3734.  
  3735. my $redo = 1;
  3736. while ($redo) {
  3737. $answer = spacechk_answer('In which directory do you want '
  3738. . 'to install the binary files?', 'dirpath',
  3739. $rootdir . '/bin', './bin', 'BINDIR');
  3740. undef %patch;
  3741. $redo=install_dir('./bin', $answer, \%patch, 0x1, 1);
  3742. }
  3743.  
  3744. get_initscriptsdir();
  3745. $initscriptsdir = db_get_answer('INITSCRIPTSDIR');
  3746.  
  3747. #
  3748. # Install the startup script (and make the old installer aware of this one)
  3749. #
  3750. undef %patch;
  3751. install_file($cStartupFileName, $initscriptsdir . '/vmware', \%patch, 0x1);
  3752.  
  3753. $gIsUninstallerInstalled = 1;
  3754.  
  3755. # Setuid root
  3756. safe_chmod(04555, $answer . '/vmware-ping');
  3757.  
  3758. $rootdir = internal_dirname($answer);
  3759. # Don't display a double slash (was bug 14109)
  3760. if ($rootdir eq '/') {
  3761. $rootdir = '';
  3762. }
  3763.  
  3764. # We don't use get_persistent_answer() here because once the user has
  3765. # selected the root directory, we can give him better default answers than
  3766. # his/her previous answers. Even though this is asking for a directory,
  3767. # the actual source of the files is within the source ./lib so the
  3768. # spacechk_answer() below handles it.
  3769. if (vmware_product() eq 'ws') {
  3770. $redo=1;
  3771. while($redo) {
  3772. $answer = get_answer('In which directory do you want to install '
  3773. . 'the daemon files?', 'dirpath', $rootdir . '/sbin');
  3774. db_add_answer('SBINDIR', $answer);
  3775. undef %patch;
  3776. $redo=install_dir('./sbin', $answer, \%patch, 0x1, 1);
  3777. }
  3778. # Setuid root
  3779. safe_chmod(04555, $answer . '/vmware-authd');
  3780. }
  3781.  
  3782. $redo=1;
  3783. while ($redo) {
  3784. $answer = spacechk_answer('In which directory do you want to install '
  3785. . 'the library files?', 'dirpath',
  3786. $rootdir . '/lib/vmware', './lib');
  3787. db_add_answer('LIBDIR', $answer);
  3788. $libdir = $answer;
  3789. undef %patch;
  3790. $redo=install_dir('./lib', $answer, \%patch, 0x1, 1);
  3791. }
  3792. # Setuid root
  3793. safe_chmod(04555, $answer . '/bin/vmware-vmx');
  3794. safe_chmod(04555, $answer . '/bin/vmware-vmx-debug');
  3795. safe_chmod(04555, $answer . '/bin/vmware-vmx-stats');
  3796.  
  3797. # If the product has man pages ask for the man pages location. */
  3798. if (-d './man') {
  3799. $mandir = $rootdir . '/share/man';
  3800. if (not (-d $mandir)) {
  3801. $mandir = $rootdir . '/man';
  3802. }
  3803. $answer = spacechk_answer('In which directory do you want to install '
  3804. . 'the manual files?', 'dirpath',
  3805. $mandir, './man');
  3806. db_add_answer('MANDIR', $answer);
  3807. undef %patch;
  3808. install_dir('./man', $answer, \%patch, 0x1);
  3809. }
  3810.  
  3811. $docdir = $rootdir . '/share/doc';
  3812. if (not (-d $docdir)) {
  3813. $docdir = $rootdir . '/doc';
  3814. }
  3815. $answer = spacechk_answer('In which directory do you want to install '
  3816. . 'the documentation files?', 'dirpath',
  3817. $docdir . '/vmware', './doc');
  3818. db_add_answer('DOCDIR', $answer);
  3819. undef %patch;
  3820. install_dir('./doc', $answer, \%patch, 0x1);
  3821. install_symlink(db_get_answer('DOCDIR') . '/EULA',
  3822. $libdir . '/share/EULA.txt');
  3823.  
  3824. # Don't forget the vix perl tar ball..
  3825. if (-d 'vmware-vix/api' ) {
  3826. undef %patch;
  3827. # Create the parent directory separately so install_dir() can be called on the
  3828. # specific subdir rather than any and all subdirs when passing just 'vmware-vix'.
  3829. db_add_dir($libdir . '/vmware-vix');
  3830. install_dir( './vmware-vix/api', $libdir . '/vmware-vix/api', \%patch, 0x1);
  3831. }
  3832.  
  3833. find_vix_tar();
  3834.  
  3835. if (vmware_product() eq 'ws') {
  3836. install_content_player();
  3837. }
  3838.  
  3839. if (vmware_product() eq 'ws') {
  3840. configure_vnetlib();
  3841. }
  3842. }
  3843.  
  3844. sub install_content_player {
  3845. my %patch;
  3846. install_dir('./system_etc', '/etc', \%patch, 1);
  3847. undef %patch;
  3848. install_dir('./usr', '/usr', \%patch, 1);
  3849. }
  3850.  
  3851. sub get_initscriptsdir {
  3852. my $initdir;
  3853. my $initscriptsdir;
  3854. my $answer;
  3855.  
  3856. if (vmware_product() eq 'tools-for-freebsd') {
  3857. $initdir = '/usr/local/etc/rc.d';
  3858. $initscriptsdir = '/usr/local/etc/rc.d';
  3859. db_add_answer('INITDIR', $initdir);
  3860. db_add_answer('INITSCRIPTSDIR', $initscriptsdir);
  3861. return $initscriptsdir;
  3862. }
  3863.  
  3864. # The "SuSE version >= 7.1" way
  3865. $initdir = '/etc/init.d';
  3866. if (check_answer_initdirpath($initdir, 'default') eq '') {
  3867. # The "SuSE version < 7.1" way
  3868. $initdir = '/sbin/init.d';
  3869. if (check_answer_initdirpath($initdir, 'default') eq '') {
  3870. # The "RedHat" way
  3871. $initdir = '/etc/rc.d';
  3872. if (check_answer_initdirpath($initdir, 'default') eq '') {
  3873. # The "Debian" way
  3874. $initdir = '/etc';
  3875. if (check_answer_initdirpath($initdir, 'default') eq '') {
  3876. $initdir = '';
  3877. }
  3878. }
  3879. }
  3880. }
  3881. $answer = get_persistent_answer('What is the directory that contains the init'
  3882. .' directories (rc0.d/ to rc6.d/)?'
  3883. , 'INITDIR', 'initdirpath', $initdir);
  3884.  
  3885. # The usual way
  3886. $initscriptsdir = $answer . '/init.d';
  3887. if ( $answer =~ m/init.d/ ) {
  3888. # if the string contains init.d, do not default to containing init.d,
  3889. # instead just default to the initdir as the initscripstdir
  3890. $initscriptsdir = $answer;
  3891. }
  3892.  
  3893. if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
  3894. # The "SuSE version >= 7.1" way
  3895. $initscriptsdir = $answer;
  3896. if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
  3897. $initscriptsdir = '';
  3898. }
  3899. }
  3900. $answer = get_persistent_answer('What is the directory that contains the init'
  3901. .' scripts?', 'INITSCRIPTSDIR'
  3902. , 'initscriptsdirpath', $initscriptsdir);
  3903. return $answer;
  3904. }
  3905.  
  3906. # Install a tar package or upgrade an already installed tar package
  3907. sub install_or_upgrade {
  3908. print wrap('Installing ' . vmware_product_name() . ".\n\n", 0);
  3909.  
  3910. if (vmware_product() eq 'api') {
  3911. install_perl_api();
  3912. } elsif (vmware_product() eq 'tools-for-linux' ||
  3913. vmware_product() eq 'tools-for-freebsd' ||
  3914. vmware_product() eq 'tools-for-solaris') {
  3915. install_content_tools();
  3916. } elsif (vmware_product() eq 'vix') {
  3917. install_content_vix();
  3918. } elsif (vmware_product() eq 'vix-disklib') {
  3919. install_content_vix_disklib();
  3920. } elsif (vmware_product() eq 'nvdk') {
  3921. install_content_nvdk();
  3922. } else {
  3923. install_content();
  3924. }
  3925.  
  3926. print wrap('The installation of ' . vmware_longname()
  3927. . ' completed successfully. '
  3928. . 'You can decide to remove this software from your system at any '
  3929. . 'time by invoking the following command: "'
  3930. . db_get_answer('BINDIR') . '/' . $gUninstallerFileName . '".'
  3931. . "\n\n", 0);
  3932.  
  3933. }
  3934.  
  3935. # Uninstall files and directories beginning with a given prefix
  3936. sub uninstall_prefix {
  3937. my $prefix = shift;
  3938. my $prefix_len;
  3939. my $file;
  3940. my $dir;
  3941.  
  3942. $prefix_len = length($prefix);
  3943.  
  3944. # Remove all files beginning with $prefix
  3945. foreach $file (keys %gDBFile) {
  3946. if (substr($file, 0, $prefix_len) eq $prefix) {
  3947. uninstall_file($file);
  3948. }
  3949. }
  3950.  
  3951. # Remove all directories beginning with $prefix
  3952. # We sort them by decreasing order of their length, to ensure that we will
  3953. # remove the inner ones before the outer ones
  3954. foreach $dir (sort {length($b) <=> length($a)} keys %gDBDir) {
  3955. if (substr($dir, 0, $prefix_len) eq $prefix) {
  3956. uninstall_dir($dir, '0');
  3957. }
  3958. }
  3959. }
  3960.  
  3961. # Uninstall a tar package
  3962. sub uninstall {
  3963. my $service_name = shift;
  3964. my @services;
  3965.  
  3966. if (vmware_product() eq 'tools-for-linux') {
  3967. @services = ('/vmware-tools');
  3968. if ($have_thinprint eq 'yes') {
  3969. push (@services, '/vmware-tools-thinprint');
  3970. }
  3971. } elsif (vmware_product() eq 'tools-for-freebsd') {
  3972. @services = ('/vmware-tools.sh');
  3973. } else {
  3974. @services = ($service_name);
  3975. }
  3976.  
  3977. # New school Upstart support for Linux Tools.
  3978. if (vmware_product() eq 'tools-for-linux' and
  3979. db_get_answer_if_exists('UPSTARTJOB')) {
  3980.  
  3981. foreach my $service (@services) {
  3982. my $service = (substr($service, 0, 1) eq '/')
  3983. ? substr($service, 1) : $service;
  3984. print wrap('Stopping services for ' . $service . "\n\n", 0);
  3985. vmware_service_issue_command1($cServiceCommandSystem, $service, 'stop');
  3986. }
  3987.  
  3988. # Legacy SYSV/rc support for all products.
  3989. } elsif (defined($gDBAnswer{'INITSCRIPTSDIR'})
  3990. && db_file_in(db_get_answer('INITSCRIPTSDIR') . $service_name)) {
  3991.  
  3992. if (isDesktopProduct()) {
  3993. # Check that there are no VMs active else the server will fail to stop.
  3994. print wrap("Checking for active VMs:\n", 0);
  3995. if (system(shell_string(db_get_answer('INITSCRIPTSDIR') . '/vmware') .
  3996. ' status vmcount > /dev/null 2>&1') >> 8 == 2) {
  3997. my $msg = vmware_product_name() . ' cannot quiesce. Please '
  3998. . 'suspend or power off each VM.' . "\n\n";
  3999. error($msg);
  4000. }
  4001. print wrap("There are no Active VMs.\n", 0);
  4002. }
  4003.  
  4004. print wrap('Stopping services for ' . vmware_product_name() . "\n\n", 0);
  4005.  
  4006. foreach my $service (@services) {
  4007.  
  4008. # The installation process ran far enough to create the startup script
  4009. my $status;
  4010. # Stop the services
  4011. $status = system(shell_string(db_get_answer('INITSCRIPTSDIR')
  4012. . $service) . ' stop') >> 8;
  4013. if ($status) {
  4014. if ($status == 2) {
  4015. # At least one instance of VMware is still running. We must refuse to
  4016. # uninstall
  4017. error('Unable to stop ' . vmware_product_name()
  4018. . '\'s services. Aborting the uninstallation.' . "\n\n");
  4019. }
  4020.  
  4021. # Oh well, at worst the user will have to reboot the machine... The
  4022. # uninstallation process should now go as far as possible
  4023. print STDERR wrap('Unable to stop ' . vmware_product_name()
  4024. . '\'s services.' . "\n\n", 0);
  4025. } else {
  4026. print "\n";
  4027. }
  4028.  
  4029. my $init_style = db_get_answer_if_exists('INIT_STYLE');
  4030.  
  4031. # In case service links were created the LSB way, remove them
  4032. my $unlinked = 0;
  4033. if ("$init_style" eq 'lsb') {
  4034. if ($gHelper{'insserv'} ne '') {
  4035. if (0 == system(shell_string($gHelper{'insserv'}) . ' -r '
  4036. . shell_string(db_get_answer('INITSCRIPTSDIR') . $service)
  4037. . ' >/dev/null 2>&1')) {
  4038. $unlinked = 1;
  4039. }
  4040. else {
  4041. print wrap("WARNING: The installer initially used the " .
  4042. "insserv application to setup the vmware-tools service. " .
  4043. "That application did not run successfully. " .
  4044. "Please re-install the insserv application or check your settings. " .
  4045. "This script will now attempt to manually remove the " .
  4046. "vmware-tools service.\n\n", 0);
  4047. }
  4048. }
  4049. }
  4050.  
  4051. # Use chkconfig
  4052. if (($unlinked == 0) and ($gHelper{'chkconfig'} ne '')) {
  4053. # We need to trim the leading '/' off of the service name.
  4054. my $trim_service_name = (substr($service, 0, 1) eq '/')
  4055. ? substr($service, 1) : $service;
  4056. if (0 == system(shell_string($gHelper{'chkconfig'}) . ' --del ' . $trim_service_name)) {
  4057. $unlinked = 1;
  4058. }
  4059. else {
  4060. print wrap("WARNING: The installer initially used the " .
  4061. "chkconfig application to setup the vmware-tools service. " .
  4062. "That application did not run successfully. " .
  4063. "Please re-install the chkconfig application or check your settings. " .
  4064. "This script will now attempt to manually remove the " .
  4065. "vmware-tools service.\n\n", 0);
  4066. }
  4067. }
  4068.  
  4069. # Use update-rc.d
  4070. if (($unlinked == 0) and ($gHelper{'update-rc.d'} ne '')) {
  4071. # We need to trim the leading '/' off of the service name.
  4072. my $trim_service_name = (substr($service, 0, 1) eq '/')
  4073. ? substr($service, 1) : $service;
  4074. if (0 == system(shell_string($gHelper{'update-rc.d'}) . ' -f ' . $trim_service_name .
  4075. ' remove')) {
  4076. $unlinked = 1;
  4077. }
  4078. else {
  4079. print wrap("WARNING: The installer initially used the " .
  4080. "update-rc.d application to setup the vmware-tools service. " .
  4081. "That application did not run successfully. " .
  4082. "Please re-install the update-rc.d application or check your settings. " .
  4083. "This script will now attempt to manually remove the " .
  4084. "vmware-tools service.\n\n", 0);
  4085. }
  4086. }
  4087.  
  4088. # If neither of the above worked, the links will be removed automatically
  4089. # by the installer.
  4090. }
  4091. }
  4092.  
  4093. # Check to see if this uninstall is part of an upgrade. When an upgrade occurs,
  4094. # an install ontop of a current product, the uninstall part is called with the
  4095. # upgrade option set to 1.
  4096. if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
  4097. if (vmware_product() eq 'ws') {
  4098. uninstall_vix();
  4099. }
  4100.  
  4101. if (vmware_product() eq 'ws') {
  4102. deconfigure_vnetlib();
  4103. }
  4104.  
  4105. if (vmware_product() eq 'tools-for-linux') {
  4106. if (!$open_vm_compat) {
  4107. if ($have_caf eq 'yes') {
  4108. system('/etc/vmware-caf/pme/install/preuninstall.sh');
  4109. uninstall_content_caf();
  4110. }
  4111. }
  4112. }
  4113.  
  4114. }
  4115. else {
  4116. if (vmware_product() eq 'tools-for-linux') {
  4117. if (!$open_vm_compat) {
  4118. if ($have_caf eq 'yes') {
  4119. system('/etc/vmware-caf/pme/install/preupgrade.sh');
  4120. }
  4121. }
  4122. }
  4123. }
  4124.  
  4125. my $eclipse_dir = db_get_answer_if_exists('ECLIPSEDIR');
  4126. if (defined $eclipse_dir) {
  4127. system($gHelper{'rm'} . ' -rf ' . $eclipse_dir . '/../configuration/com.vmware.bfg*');
  4128. }
  4129.  
  4130. # Let the VMX know that we're uninstalling the Tools. We need to
  4131. # do this before we remove the files, because we use guestd to
  4132. # send the RPC. But we'd like to do it as late as possible in the
  4133. # uninstall process so that we won't accidentally tell the VMX that the
  4134. # Tools are gone when they're still there.
  4135. if (!$open_vm_compat) {
  4136. if (vmware_product() eq 'tools-for-linux' ||
  4137. vmware_product() eq 'tools-for-freebsd' ||
  4138. vmware_product() eq 'tools-for-solaris') {
  4139. send_rpc('tools.set.version 0');
  4140. }
  4141. }
  4142. if ($open_vm_compat == 0 && $have_grabbitmqproxy eq 'yes') {
  4143. uninstall_content_guestproxy();
  4144. }
  4145. uninstall_prefix('');
  4146. }
  4147.  
  4148. # Configure vnetlib
  4149. sub configure_vnetlib() {
  4150. my $vnetlib = shell_string("$gDBAnswer{'BINDIR'}/vmware-networks");
  4151. my $vers;
  4152. my $ret;
  4153.  
  4154. db_add_answer('NETWORKING', 'yes');
  4155.  
  4156. # pre-vnetlib upgrade
  4157. if (!db_get_answer_if_exists('VNETLIB_CONFED') && $gOption{'ws-upgrade'}) {
  4158. print wrap("Migrating network settings... ", 0);
  4159. if (system("$vnetlib --migrate-network-settings $gInstallerMainDB") == 0) {
  4160. db_add_answer('VNETLIB_CONFED', 'yes');
  4161. return 1;
  4162. } else {
  4163. $vers = 0;
  4164. }
  4165. } elsif (db_get_answer_if_exists('VNETLIB_CONFED')) { # post-vnetlib upgrade
  4166. $vers = 1;
  4167. } else { # new install
  4168. $vers = 0;
  4169. }
  4170.  
  4171. if ($vers == 0) {
  4172. print wrap("Configuring default networks...\n\n", 0);
  4173. } elsif ($vers == 1) {
  4174. print wrap("Restoring network settings...\n\n", 0);
  4175. }
  4176.  
  4177. my $cmd = sprintf("%s --postinstall %s,%s,1 > /dev/null", $vnetlib, vmware_product(), $vers);
  4178. $ret = system($cmd);
  4179.  
  4180. if ($ret == 0) {
  4181. db_add_answer('VNETLIB_CONFED', 'yes');
  4182. }
  4183.  
  4184. return $ret == 0;
  4185. }
  4186.  
  4187. # Cleanup after vnetlib
  4188. sub deconfigure_vnetlib() {
  4189. foreach my $path ("$gRegistryDir/networking.*", "$gRegistryDir/vmnet*",
  4190. "/var/run/vmnat.*", "/var/log/vnetlib", "$gRegistryDir/networking",
  4191. "/var/run/vmnet-*") {
  4192. system(shell_string($gHelper{'rm'}) . " -rf $path");
  4193. }
  4194. }
  4195.  
  4196.  
  4197. sub install_content_vix_disklib {
  4198. my $rootdir;
  4199. my $bindir;
  4200. my $answer;
  4201. my %patch;
  4202. my $docdir;
  4203. my $libdir;
  4204. my $suffix = is64BitUserLand() ? '64' : '32';
  4205.  
  4206. my $old_default = $gOption{'default'};
  4207. $gOption{'default'} = 0;
  4208. show_EULA();
  4209. $gOption{'default'} = $old_default;
  4210.  
  4211. undef %patch;
  4212.  
  4213. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  4214.  
  4215. $rootdir = get_persistent_answer("What prefix do you want to use to install " .
  4216. vmware_product_name() . "?\n\n" . 'The prefix is the root directory where the other
  4217. folders such as man, bin, doc, lib, etc. will be placed.', 'PREFIX', 'dirpath',
  4218. '/usr');
  4219.  
  4220. # Don't display a double slash (was bug 14109)
  4221. if ($rootdir eq '/') {
  4222. $rootdir = '';
  4223. }
  4224.  
  4225. undef %patch;
  4226. $bindir = "$rootdir/lib/vmware-vix-disklib/bin";
  4227. install_dir('./bin64', $bindir . '64', \%patch, 0x1);
  4228. create_dir("$rootdir/bin", 1);
  4229. install_symlink("$bindir$suffix/vmware-vdiskmanager", "$rootdir/bin/vmware-vdiskmanager");
  4230. install_symlink("$bindir$suffix/vmware-uninstall-vix-disklib.pl",
  4231. "$rootdir/bin/vmware-uninstall-vix-disklib.pl");
  4232. db_add_answer('BINDIR', "$rootdir/bin");
  4233.  
  4234. $gIsUninstallerInstalled = 1;
  4235.  
  4236. $libdir = "$rootdir/lib/vmware-vix-disklib/lib";
  4237. undef %patch;
  4238. install_dir('./lib64', $libdir . '64', \%patch, 0x1);
  4239.  
  4240. foreach my $arch (qw(64)) {
  4241. install_symlink("$libdir$arch/libssl.so.0.9.8", "$bindir$arch/libssl.so.0.9.8");
  4242. install_symlink("$libdir$arch/libcrypto.so.0.9.8", "$bindir$arch/libcrypto.so.0.9.8");
  4243. }
  4244. db_add_answer('VIXDISKLIBDIR', $libdir);
  4245. db_add_answer('LIBDIR', $libdir);
  4246.  
  4247. undef %patch;
  4248. install_dir('./include', "$rootdir/lib/vmware-vix-disklib/include", \%patch, 0x1);
  4249.  
  4250. my $pkgdir = "$rootdir/lib/pkgconfig";
  4251. create_dir($pkgdir, 1);
  4252. foreach my $arch (qw(64)) {
  4253. my $pcfile = "$pkgdir/vix-disklib-$arch.pc";
  4254. if (open(PKGCONFIG, '>' . $pcfile)) {
  4255. db_add_file($pcfile, 0);
  4256. print PKGCONFIG "prefix=$rootdir/lib/vmware-vix-disklib\n";
  4257. print PKGCONFIG "exec_prefix=\${prefix}\n";
  4258. print PKGCONFIG "libdir=\${exec_prefix}/lib$arch\n";
  4259. print PKGCONFIG "includedir=\${prefix}/include\n";
  4260. print PKGCONFIG "Name: vix-disklib\n";
  4261. print PKGCONFIG "Description: VMware VIX DiskLib\n";
  4262. print PKGCONFIG "Version: " . vmware_version() . "\n";
  4263. print PKGCONFIG "Libs: -L\${libdir} -lvixDiskLib\n";
  4264. print PKGCONFIG "Cflags: -I\${includedir}\n";
  4265. close PKGCONFIG;
  4266. }
  4267. }
  4268.  
  4269. # Runtime
  4270. install_symlink("vmware-vix-disklib/lib$suffix/libvixDiskLib.so.5",
  4271. "$rootdir/lib/libvixDiskLib.so.5");
  4272. # Devel only
  4273. install_symlink("vix-disklib-$suffix.pc", "$pkgdir/vix-disklib.pc");
  4274. install_symlink("libvixDiskLib.so.5",
  4275. "$rootdir/lib/libvixDiskLib.so");
  4276.  
  4277. $docdir = $rootdir . '/share/doc/vmware-vix-disklib';
  4278. install_dir('./doc', $docdir, \%patch, 0x1);
  4279.  
  4280. return 1;
  4281. }
  4282.  
  4283. sub install_content_nvdk {
  4284. my $rootdir;
  4285. my $bindir;
  4286. my $answer;
  4287. my %patch;
  4288. my $docdir;
  4289. my $suffix = is64BitUserLand() ? '64' : '32';
  4290.  
  4291. my $old_default = $gOption{'default'};
  4292. $gOption{'default'} = 0;
  4293. show_EULA();
  4294. $gOption{'default'} = $old_default;
  4295.  
  4296. undef %patch;
  4297.  
  4298. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  4299.  
  4300. $rootdir = get_persistent_answer("What prefix do you want to use to install " .
  4301. vmware_product_name() . "?\n\n" . 'The prefix is the root directory where the other
  4302. folders such as man, bin, doc, lib, etc. will be placed.', 'PREFIX', 'dirpath',
  4303. '/usr');
  4304.  
  4305. # Don't display a double slash
  4306. if ($rootdir eq '/') {
  4307. $rootdir = '';
  4308. }
  4309.  
  4310. undef %patch;
  4311. $bindir = "$rootdir/lib/nvdk/bin";
  4312. install_dir('./bin', $bindir, \%patch, 0x1);
  4313. create_dir("$rootdir/bin", 1);
  4314. install_symlink("$bindir/vmware-uninstall-nvdk.pl",
  4315. "$rootdir/bin/vmware-uninstall-nvdk.pl");
  4316. db_add_answer('BINDIR', "$rootdir/bin");
  4317.  
  4318. $gIsUninstallerInstalled = 1;
  4319.  
  4320. undef %patch;
  4321. install_dir('./include', "$rootdir/lib/nvdk/include", \%patch, 0x1);
  4322.  
  4323. my $pkgdir = "$rootdir/lib/pkgconfig";
  4324. create_dir($pkgdir, 1);
  4325. my $pcfile = "$pkgdir/nvdk.pc";
  4326. if (open(PKGCONFIG, '>' . $pcfile)) {
  4327. db_add_file($pcfile, 0);
  4328. print PKGCONFIG "prefix=$rootdir/lib/nvdk\n";
  4329. print PKGCONFIG "includedir=\${prefix}/include\n";
  4330. print PKGCONFIG "Name: nvdk\n";
  4331. print PKGCONFIG "Description: VMware NAS VAAI Development Kit\n";
  4332. print PKGCONFIG "Version: " . vmware_version() . "\n";
  4333. print PKGCONFIG "Cflags: -I\${includedir}\n";
  4334. close PKGCONFIG;
  4335. }
  4336.  
  4337. $docdir = $rootdir . '/share/doc/nvdk';
  4338. install_dir('./doc', $docdir, \%patch, 0x1);
  4339.  
  4340. return 1;
  4341. }
  4342.  
  4343. # Ask the user for file locations for libs, bins, etc. Check
  4344. # to see if this build is an official one or not, and show the
  4345. # EULA if it's not an official build.
  4346. sub install_content_vix {
  4347. my $rootdir;
  4348. my $answer;
  4349. my %patch;
  4350. my $mandir;
  4351. my $docdir;
  4352. my $initdir;
  4353. my $initscriptsdir;
  4354. my $libdir;
  4355.  
  4356. undef %patch;
  4357. install_dir('./etc', $gRegistryDir, \%patch, 0x1);
  4358.  
  4359. if ('4448491' != 0) {
  4360. # suspend any '--default' option to force user interaction here. The user
  4361. # must answer the EULA question before continuing.
  4362. my $tmp = $gOption{'default'};
  4363. $gOption{'default'} = 0;
  4364. show_EULA();
  4365. $gOption{'default'} = $tmp;
  4366. }
  4367.  
  4368. if (db_get_answer_if_exists('NESTED') &&
  4369. db_get_answer('NESTED') eq 'yes' &&
  4370. $gOption{'default'} == 1) {
  4371. db_add_answer('TERSE', 'yes');
  4372. }
  4373.  
  4374. # If workstation is already installed and VIX has not already defined
  4375. # it's own BINDIR, then base the default root on the workstation BINDIR.
  4376. if (!defined(db_get_answer_if_exists('BINDIR'))) {
  4377. my $newbin;
  4378. if (-f $cInstallerMainDB) {
  4379. $newbin = alt_db_get_answer($cInstallerMainDB, 'BINDIR');
  4380. if (defined($newbin)) {
  4381. db_add_answer('BINDIR', $newbin);
  4382. }
  4383. }
  4384. }
  4385.  
  4386. $rootdir = '/usr';
  4387. $answer = $gOption{'prefix'} || spacechk_answer('In which directory do you want '
  4388. . 'to install the ' . vmware_product_name()
  4389. . ' binary files?', 'dirpath',
  4390. $rootdir . '/bin', './bin', 'BINDIR');
  4391.  
  4392. # Make sure stuff is installed in a 'bin' dir.
  4393. my $basename = internal_basename($answer);
  4394. if ($basename ne 'bin') {
  4395. $answer = $answer . '/bin';
  4396. }
  4397.  
  4398. db_add_answer('BINDIR', $answer);
  4399. undef %patch;
  4400. install_dir('./bin', $answer, \%patch, 0x1);
  4401. # We might be in a 'NESTED' install and workstation would have already
  4402. # installed vmrun. No reason to check for 'NESTED' really. If we're
  4403. # installed standalone, then the uninstall would remove vmrun. If not,
  4404. # then vmrun will already exist.
  4405. if (! file_name_exist($answer . '/vmrun')) {
  4406. my %patch;
  4407. install_file('./vmware-vix/bin/vmrun', $answer . '/vmrun', \%patch, 0x1);
  4408. }
  4409.  
  4410. $rootdir = internal_dirname($answer);
  4411. # Don't display a double slash (was bug 14109)
  4412. if ($rootdir eq '/') {
  4413. $rootdir = '';
  4414. }
  4415. $gIsUninstallerInstalled = 1;
  4416.  
  4417. $libdir = 'vmware-vix/lib';
  4418. $answer = spacechk_answer('In which directory do you want '
  4419. . 'to install the ' . vmware_product_name()
  4420. . ' library files?', 'dirpath',
  4421. $rootdir . '/lib/'. $libdir, 'vmware-vix/lib' );
  4422.  
  4423. db_add_answer('VIXLIBDIR', $answer);
  4424. db_add_answer('LIBDIR', $answer);
  4425.  
  4426. undef %patch;
  4427. install_dir($libdir, $answer, \%patch, 0x1);
  4428. my $globallibdir = is64BitUserLand() ? '/lib64' : '/lib32';
  4429. my $shared_object = 'libvixAllProducts.so';
  4430.  
  4431. if ((! -d $globallibdir) && (! -d '/usr' . $globallibdir)) {
  4432. install_symlink($answer . '/' . $shared_object, '/lib/' . $shared_object);
  4433. } else {
  4434. if (-d $globallibdir) {
  4435. install_symlink($answer . '/' . $shared_object,
  4436. $globallibdir . '/' . $shared_object);
  4437. }
  4438. if (-d '/usr' . $globallibdir) {
  4439. install_symlink($answer . '/' . $shared_object,
  4440. '/usr' . $globallibdir . '/' . $shared_object);
  4441. }
  4442. }
  4443.  
  4444. # If the product has man pages ask for the man pages location. */
  4445. if (-d './man') {
  4446. $mandir = $rootdir . '/share/man';
  4447. if (not (-d $mandir)) {
  4448. $mandir = $rootdir . '/man';
  4449. }
  4450. $answer = spacechk_answer('In which directory do you want '
  4451. . 'to install the ' . vmware_product_name()
  4452. . ' man pages?', 'dirpath',
  4453. $rootdir . '/man', 'vmware-vix/man');
  4454. db_add_answer('MANDIR', $answer);
  4455. undef %patch;
  4456. install_dir('vmware-vix/man', $answer, \%patch, 0x1);
  4457. }
  4458.  
  4459. $docdir = $rootdir . '/share/doc';
  4460. if (not (-d $docdir)) {
  4461. $docdir = $rootdir . '/doc';
  4462. }
  4463. $answer = spacechk_answer('In which directory do you want '
  4464. . 'to install the ' . vmware_product_name()
  4465. . ' document pages?', 'dirpath',
  4466. $docdir . '/vmware-vix', 'doc');
  4467.  
  4468. undef %patch;
  4469. install_dir('./doc', $answer, \%patch, 0x1);
  4470. db_add_answer('DOCDIR', $answer);
  4471. undef %patch;
  4472. install_dir('vmware-vix/include', $rootdir . '/include', \%patch, 0x1);
  4473. undef %patch;
  4474. install_dir('vmware-vix/api', db_get_answer('VIXLIBDIR') . '/api', \%patch, 0x1);
  4475.  
  4476. # tell the Vix world where to find the libs, putting the VIXLIBDIR value
  4477. # into /etc/vmware/config.
  4478. finalize_vix_install();
  4479.  
  4480. # Make sure the verbose meter is turned up.
  4481. db_remove_answer('TERSE');
  4482.  
  4483. return 1;
  4484. }
  4485.  
  4486. # Add the variable, vix.libdir, to /etc/vmware/config
  4487. # so the Vix API can figure out where its libraries
  4488. # are. If this is the standalone version, create config.
  4489. sub finalize_vix_install {
  4490. if (! -d "/etc/vmware") {
  4491. create_dir("/etc/vmware", 0x1);
  4492. }
  4493.  
  4494. my $libdir = db_get_answer_if_exists('VIXLIBDIR');
  4495.  
  4496. if (!defined($libdir)) {
  4497. error("Unable to look up VIX libdir.\n");
  4498. }
  4499.  
  4500. $gConfig->set("vix.libdir", $libdir);
  4501.  
  4502. if (!$gConfig->writeout($gConfigFile)) {
  4503. error("Unable to write VIX libdir to configuration file.\n");
  4504. }
  4505. }
  4506.  
  4507. # find the vix tar package within the workstation distribution tree and install
  4508. # it into db_get_answer('LIBDIR')/vmware-vix
  4509. sub find_vix_tar {
  4510. my %patch;
  4511. my $vixTarFile = 'vmware-vix/vmware-vix.tar.gz';
  4512. my $vixInstalledTarFile = db_get_answer('LIBDIR') . '/' . $vixTarFile;
  4513.  
  4514. # If this is a workstation tar install there will be a vix tarball:
  4515. # vmware-distrib/vmware-vix/vmware-vix.tar.gz. "Install" it into
  4516. # its final spot in the tree. If this is an rpm install, the tarball
  4517. # will already be in its final location. This is where the vmware-config
  4518. # script will look for the tar file.
  4519. if (-e $vixTarFile) {
  4520. undef %patch;
  4521. install_file($vixTarFile, $vixInstalledTarFile, \%patch, 0x1);
  4522. return 1;
  4523. }
  4524. return 0;
  4525. }
  4526.  
  4527. # Remove the text we added to the core config file in
  4528. # /etc/vmware/config. Call uninstall on the whole tree.
  4529. sub uninstall_vix {
  4530. my @statbuf;
  4531.  
  4532. # If this is not the Vix product in here, then the only thing to do is to launch
  4533. # the Vix uninstaller. When Vix comes through here, skipping this if, all of
  4534. # the normal uninstall pieces occurr.
  4535. if (vmware_product() ne 'vix') {
  4536. my $where = alt_db_get_answer('/etc/vmware-vix/locations', 'BINDIR');
  4537. if ($where) {
  4538. $where .= '/vmware-uninstall-vix.pl';
  4539. if (-f $where) {
  4540. system(shell_string($where));
  4541. }
  4542. }
  4543. return;
  4544. }
  4545.  
  4546. $gConfig->remove('vix.libdir');
  4547. if (!$gConfig->writeout($gConfigFile)) {
  4548. error("Unable to write VIX libdir to configuration file.\n");
  4549. }
  4550.  
  4551. # If we just removed the last bits from the file, statbuf[7] == size in bytes,
  4552. # then remove the file so it won't get left behind in an uninstall.
  4553. @statbuf = stat($gConfigFile);
  4554. if ( !$statbuf[7]) {
  4555. unlink ($gConfigFile);
  4556. }
  4557.  
  4558. uninstall_prefix('');
  4559.  
  4560. # check to see if $gRegistryDir is still around. If it has no files,
  4561. # remove it.
  4562. if (-d $gRegistryDir) {
  4563. if (!direct_command('find ' . $gRegistryDir . ' -type f -o -type l')) {
  4564. rmdir($gRegistryDir);
  4565. }
  4566. }
  4567.  
  4568. }
  4569.  
  4570. # Return the specific VMware product
  4571. sub vmware_product {
  4572. return 'tools-for-linux';
  4573. }
  4574.  
  4575. # this is a function instead of a macro in the off chance that product_name
  4576. # will one day contain a language-specific escape character.
  4577. sub vmware_product_name {
  4578. return 'VMware Tools';
  4579. }
  4580.  
  4581. # This function returns i386 under most circumstances, returning x86_64 when
  4582. # the product is Workstation and is the 64bit version at that.
  4583. sub vmware_product_architecture {
  4584. return '@@PRODUCT_ARCHITECTURE@@';
  4585. }
  4586.  
  4587. # Return product name and version
  4588. sub vmware_longname {
  4589. my $name = vmware_product_name() . ' ' . vmware_version();
  4590.  
  4591. if (not (vmware_product() eq 'server')) {
  4592. if (vmware_product() eq 'tools-for-solaris') {
  4593. $name .= ' for Solaris';
  4594. } elsif (vmware_product() eq 'tools-for-freebsd') {
  4595. $name .= ' for FreeBSD';
  4596. } else {
  4597. $name .= ' for Linux';
  4598. }
  4599. }
  4600.  
  4601. return $name;
  4602. }
  4603.  
  4604. # Display a usage error message for the install program and exit
  4605. sub install_usage {
  4606. print STDERR wrap(vmware_longname() . ' installer' . "\n" . 'Usage: ' . $0 . "\n"
  4607. . ' [[-][-]d[efault]]' . "\n"
  4608. . ' default: Automatically answer questions with the '
  4609. . 'proposed answer.'
  4610. . "\n"
  4611. . ' [[-][-]f[orce-install]]' . "\n"
  4612. . ' force-install: install even if open-vm-tools are available '
  4613. . 'for this distribution.'
  4614. . "\n"
  4615. . ' [[-][-]prefix=<path to install product: bin, lib, doc>]' . "\n"
  4616. . ' Put the installation at <path> instead of the default '
  4617. . "location. This implies '--default'."
  4618. . "\n"
  4619. . ' [[-][-]r[egenerate-cert]]' . "\n"
  4620. . ' Force to regenerate server key/cert files if they already exist.'
  4621. . "\n"
  4622. . ' --clobber-kernel-modules=<module1,module2,...>' . "\n"
  4623. . ' Forcefully removes any VMware related modules '
  4624. . 'installed by any other installer and installs the modules provided '
  4625. . 'by this installer. This is a comma seperated list of modules.'
  4626. . "\n\n", 0);
  4627. exit 1;
  4628. }
  4629.  
  4630. # Remove a temporary directory
  4631. sub remove_tmp_dir {
  4632. my $dir = shift;
  4633.  
  4634. if (system(shell_string($gHelper{'rm'}) . ' -rf ' . shell_string($dir))) {
  4635. error('Unable to remove the temporary directory ' . $dir . '.' . "\n\n");
  4636. };
  4637. }
  4638.  
  4639. # ARGH! More code duplication from pkg_mgr.pl
  4640. # We really need to have some kind of include system
  4641. sub get_cc {
  4642. $gHelper{'gcc'} = '';
  4643. if (defined($ENV{'CC'}) && (not ($ENV{'CC'} eq ''))) {
  4644. $gHelper{'gcc'} = internal_which($ENV{'CC'});
  4645. if ($gHelper{'gcc'} eq '') {
  4646. print wrap('Unable to find the compiler specified in the CC environnment variable: "'
  4647. . $ENV{'CC'} . '".' . "\n\n", 0);
  4648. }
  4649. }
  4650. if ($gHelper{'gcc'} eq '') {
  4651. $gHelper{'gcc'} = internal_which('gcc');
  4652. if ($gHelper{'gcc'} eq '') {
  4653. $gHelper{'gcc'} = internal_which('egcs');
  4654. if ($gHelper{'gcc'} eq '') {
  4655. $gHelper{'gcc'} = internal_which('kgcc');
  4656. if ($gHelper{'gcc'} eq '') {
  4657. $gHelper{'gcc'} = DoesBinaryExist_Prompt('gcc');
  4658. }
  4659. }
  4660. }
  4661. }
  4662. print wrap('Using compiler "' . $gHelper{'gcc'}
  4663. . '". Use environment variable CC to override.' . "\n\n", 0);
  4664. return $gHelper{'gcc'};
  4665. }
  4666.  
  4667. # These quaddot functions and compute_subnet are from config.pl and are needed
  4668. # for the tar4|rpm4 upgrade
  4669. # Converts an quad-dotted IPv4 address into a integer
  4670. sub quaddot_to_int {
  4671. my $quaddot = shift;
  4672. my @quaddot_a;
  4673. my $int;
  4674. my $i;
  4675.  
  4676. @quaddot_a = split(/\./, $quaddot);
  4677. $int = 0;
  4678. for ($i = 0; $i < 4; $i++) {
  4679. $int <<= 8;
  4680. $int |= $quaddot_a[$i];
  4681. }
  4682.  
  4683. return $int;
  4684. }
  4685.  
  4686. # Converts an integer into a quad-dotted IPv4 address
  4687. sub int_to_quaddot {
  4688. my $int = shift;
  4689. my @quaddot_a;
  4690. my $i;
  4691.  
  4692. for ($i = 3; $i >= 0; $i--) {
  4693. $quaddot_a[$i] = $int & 0xFF;
  4694. $int >>= 8;
  4695. }
  4696.  
  4697. return join('.', @quaddot_a);
  4698. }
  4699.  
  4700. # Compute the subnet address associated to a couple IP/netmask
  4701. sub compute_subnet {
  4702. my $ip = shift;
  4703. my $netmask = shift;
  4704.  
  4705. return int_to_quaddot(quaddot_to_int($ip) & quaddot_to_int($netmask));
  4706. }
  4707.  
  4708. #
  4709. # This sub fetches the installed product's binfile and returns it.
  4710. # It returns '' if there is no product, 'UNKNOWN' if a product but
  4711. # no known bin.
  4712. #
  4713. sub get_installed_product_bin {
  4714. my $binfile;
  4715.  
  4716. # If there's no database, then there isn't any
  4717. # previously installed product.
  4718. my $tmp_db = $gInstallerMainDB;
  4719.  
  4720. if (not isDesktopProduct()) {
  4721. return 'UNKNOWN';
  4722. }
  4723.  
  4724. # If the installer DB is missing there is no product already installed so
  4725. # there is no mismatch.
  4726. # If not_configured is found, then install has already run once and has
  4727. # uninstalled everything.
  4728. if (not -e $gInstallerMainDB || -e $gRegistryDir . '/' . $gConfFlag) {
  4729. return '';
  4730. }
  4731.  
  4732. db_load();
  4733. my $bindir = db_get_answer('BINDIR');
  4734. if (-f $bindir . "/vmware") {
  4735. $binfile = $bindir . "/vmware";
  4736. } elsif (-f $bindir . "/vmplayer") {
  4737. $binfile = $bindir . "/vmplayer";
  4738. } else {
  4739. # There is no way to tell what may currently be installed, but something
  4740. # is still around if the database is found.
  4741. return 'UNKNOWN';
  4742. }
  4743. return $binfile;
  4744. }
  4745.  
  4746. #
  4747. # Check to see if the product we are installing is the same as the
  4748. # currently installed product, this is used to tell whether we are in
  4749. # what would be considered an upgrade situation or a conflict.
  4750. #
  4751. # return = 0: There is a match
  4752. # = 1: There is a mismatch
  4753. #
  4754. sub installed_product_mismatch {
  4755. my $msg;
  4756. my $binfile = get_installed_product_bin();
  4757. if ( $binfile eq '' ){
  4758. return 0;
  4759. }
  4760. if ( $binfile eq 'UNKNOWN' ){
  4761. return 1;
  4762. }
  4763. my $product_str = direct_command($binfile . ' -v');
  4764. my $product_name = vmware_product_name();
  4765. if ($product_str =~ /$product_name/){
  4766. return 0;
  4767. }
  4768.  
  4769. return 1;
  4770. }
  4771.  
  4772. #
  4773. # Given a product version string ala 'VMware Server X.X.X build-000000', break
  4774. # down the Xs and return a value that shows which string represents a newer
  4775. # version number, the same version number, or an older version number. X may be
  4776. # a digit or a letter, as in e.x.p build-000000
  4777. #
  4778. sub compare_version_strings {
  4779. my $version_str_A = shift;
  4780. my $version_str_B = shift;
  4781. my $index = 0;
  4782.  
  4783. # Match on non-spaces to allow for either numbers or letters. I.E. e.x.p and 1.0.4
  4784. $version_str_A =~ s/\D*(\S+.\S+.\S+)\s+build-(\d+)/$1.$2/;
  4785. $version_str_B =~ s/\D*(\S+.\S+.\S+)\s+build-(\d+)/$1.$2/;
  4786.  
  4787. chomp($version_str_A);
  4788. chomp($version_str_B);
  4789. my @versions_A = split(/\./, $version_str_A);
  4790. my @versions_B = split(/\./, $version_str_B);
  4791.  
  4792. while (($index < $#versions_A + 1) && ($versions_A[$index] eq $versions_B[$index])) {
  4793. $index++;
  4794. }
  4795. if ($index > $#versions_A) {
  4796. $index = $#versions_A;
  4797. }
  4798.  
  4799. my $result;
  4800. if ($versions_A[$index] =~ /\d+/ && $versions_B[$index] =~ /\d+/) {
  4801. $result = $versions_A[$index] - $versions_B[$index];
  4802. } elsif ($versions_A[$index] =~ /\w+/ && $versions_B[$index] =~ /\d+/) {
  4803. $result = -1;
  4804. } elsif ($versions_A[$index] =~ /\d+/ && $versions_B[$index] =~ /\w+/) {
  4805. $result = 1;
  4806. } else {
  4807. $result = 0;
  4808. }
  4809.  
  4810. return $result;
  4811. }
  4812.  
  4813. #
  4814. # Check to see what product is installed, and how it relates to the
  4815. # new product being installed, asking the user relevant questions,
  4816. # and allowing the user to abort(error out) if they don't want the
  4817. # existing installed product to be removed (as in for an up/downgrade
  4818. # or conflicting product).
  4819. #
  4820. sub prompt_user_to_remove_installed_product {
  4821. # First off, only a few products even have "mismatches", i.e. can possibly conflict.
  4822. if (((vmware_product() eq 'ws') ||
  4823. (vmware_product() eq 'player')) &&
  4824. (installed_product_mismatch() != 0)) {
  4825. if (get_answer('You have a product that conflicts with '.vmware_product_name().' installed. ' .
  4826. 'Continuing this install will first uninstall this product. ' .
  4827. 'Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
  4828. error "User canceled install.\n";
  4829. }
  4830. return;
  4831. }
  4832. #Now that the group of other-conflicting products is handled, we are sure this product simply
  4833. #conflicts with itself, even if its one of those.
  4834. my $binfile = get_installed_product_bin();
  4835. if ( $binfile eq 'UNKNOWN' or $binfile eq '' ){
  4836. #Without a binfile, we can't detect version, so we simply warn the user we are about to uninstall
  4837. #and ask them if they want that.
  4838. if (get_answer('You have a version of '.vmware_product_name().' installed. ' .
  4839. 'Continuing this install will first uninstall the currently installed version.' .
  4840. ' Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
  4841. error "User canceled install.\n";
  4842. }
  4843. return;
  4844. }
  4845.  
  4846. my $product_str = direct_command($binfile . ' -v');
  4847. my $installed_version = direct_command($binfile . ' -v');
  4848. my $product_version = vmware_version();
  4849. if (compare_version_strings($installed_version, $product_version) > 0) {
  4850. if (get_answer('You have a more recent version of '.vmware_product_name().' installed. ' .
  4851. 'Continuing this install will DOWNGRADE to the latest version by first ' .
  4852. 'uninstalling the more recent version. Do you wish to continue? (yes/no)', 'yesno', 'no') eq 'no') {
  4853. error "User canceled install.\n";
  4854. }
  4855. } else {
  4856. if (get_answer('You have a previous version of '.vmware_product_name().' installed. ' .
  4857. 'Continuing this install will upgrade to the latest version by first ' .
  4858. 'uninstalling the previous version. Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
  4859. error "User canceled install.\n";
  4860. }
  4861. }
  4862. }
  4863.  
  4864. #
  4865. # preuninstall_installed_tools
  4866. #
  4867. # hook scripts to run before uninstalling previously installed tools
  4868.  
  4869. sub preuninstall_installed_tools {
  4870. # esx35* tools will backup system configuration file during installation
  4871. # and restore the backuped file when to reconfigure tools or uninstall tools.
  4872. # It is flawed in that user's modification made between backup and restore·
  4873. # will lost. Specificly /etc/fstab was affected and reported as PR 400907.
  4874. #
  4875. # Below is a fix to keep user's modification by preventing uninstaller from·
  4876. # restore /etc/fstab. But it does not fix other configuration lost problem.
  4877. my $version;
  4878. my $file;
  4879. my $answer;
  4880. my %files_to_keep;
  4881. my @files_to_restore;
  4882. my @files_to_restore_filtered;
  4883.  
  4884. %files_to_keep = (
  4885. "OLD_FSTAB" => undef,
  4886. ); #can be extended to other backups
  4887.  
  4888. if (-e $gInstallerMainDB && -x $gInstallerObject) {
  4889. # check installer database version
  4890. if (system(shell_string($gInstallerObject) . ' version >/dev/null 2>&1')) {
  4891. $version = '1';
  4892. } else {
  4893. $version = direct_command(shell_string($gInstallerObject) . ' version');
  4894. chop($version);
  4895. }
  4896.  
  4897. #esx35* and above are of version 4.
  4898. if ($version == 4) {
  4899. db_load(); #initialize gDBAnswer
  4900. open(INSTALLDB, '>>' . $gInstallerMainDB);
  4901.  
  4902. #filter the RESTORE_BACK_LIST, remove files that we want to keep
  4903. $answer = db_get_answer_if_exists("RESTORE_BACK_LIST");
  4904. if (defined($answer)) {
  4905. @files_to_restore = split(':', $answer);
  4906. @files_to_restore_filtered = ();
  4907. foreach $file (@files_to_restore) {
  4908. if (!exists($files_to_keep{$file})) {
  4909. push(@files_to_restore_filtered, $file);
  4910. }
  4911. }
  4912.  
  4913. #save back to db
  4914. if (@files_to_restore > @files_to_restore_filtered) {
  4915. $answer = join(":", @files_to_restore_filtered);
  4916. db_remove_answer("RESTORE_BACK_LIST");
  4917. db_add_answer("RESTORE_BACK_LIST", $answer);
  4918. }
  4919. }
  4920.  
  4921. # Add INITRDMODS_CONF_VALS, so that it won't fail the old uninstaller.
  4922. # And this is PR 983072.
  4923. $answer = db_get_answer_if_exists("INITRDMODS_CONF_VALS");
  4924. if (!defined($answer)) {
  4925. db_add_answer("INITRDMODS_CONF_VALS", "");
  4926. }
  4927.  
  4928. db_save(); #close db
  4929. }
  4930. }
  4931. }
  4932.  
  4933.  
  4934. #
  4935. # Make sure we have an initial database suitable for this installer. The goal
  4936. # is to encapsulates all the compatibilty issues in this (consequently ugly)
  4937. # function
  4938. #
  4939. # SIDE EFFECTS:
  4940. # This function uninstalls previous products found (now managed by
  4941. # prompt_user_to_remove_installed_product)
  4942. #
  4943.  
  4944. sub get_initial_database {
  4945. my $made_dir1;
  4946. my $made_dir2;
  4947. my $bkp_dir;
  4948. my $bkp;
  4949. my $kind;
  4950. my $version;
  4951. my $intermediate_format;
  4952. my $status;
  4953. my $state_file;
  4954. my $state_files;
  4955. my $clear_db = 0;
  4956.  
  4957. if (not (-e $gInstallerMainDB)) {
  4958. create_initial_database();
  4959. return;
  4960. }
  4961.  
  4962. print wrap('A previous installation of ' . vmware_product_name()
  4963. . ' has been detected.' . "\n\n", 0);
  4964.  
  4965. #
  4966. # Convert the previous installer database to our format and backup it
  4967. # Uninstall the previous installation
  4968. #
  4969.  
  4970. $bkp_dir = make_tmp_dir('vmware-installer');
  4971. $bkp = $bkp_dir . '/prev_db.tar.gz';
  4972.  
  4973. if (-x $gInstallerObject) {
  4974. $kind = direct_command(shell_string($gInstallerObject) . ' kind');
  4975. chop($kind);
  4976. if (system(shell_string($gInstallerObject) . ' version >/dev/null 2>&1')) {
  4977. # No version method -> this is version 1
  4978. $version = '1';
  4979. } else {
  4980. $version = direct_command(shell_string($gInstallerObject) . ' version');
  4981. chop($version);
  4982. }
  4983. print wrap('The previous installation was made by the ' . $kind
  4984. . ' installer (version ' . $version . ').' . "\n\n", 0);
  4985.  
  4986. if ($version < 2) {
  4987. # The best database format those installers know is tar. We will have to
  4988. # upgrade the format
  4989. $intermediate_format = 'tar';
  4990. } elsif ($version == 2) {
  4991. # Those installers at least know about the tar2 database format. We won't
  4992. # have to do too much
  4993. $intermediate_format='tar2'
  4994. } elsif ($version == 3) {
  4995. # Those installers at least know about the tar3 database format. We won't
  4996. # have to do much
  4997. $intermediate_format = 'tar3';
  4998. } else {
  4999. # Those installers at least know about the tar4 database format. We won't
  5000. # have to do anything
  5001. $intermediate_format = 'tar4';
  5002. }
  5003. system(shell_string($gInstallerObject) . ' convertdb '
  5004. . shell_string($intermediate_format) . ' ' . shell_string($bkp));
  5005.  
  5006. # Uninstall the previous installation
  5007. if (((vmware_product() eq 'ws') ||
  5008. (vmware_product() eq 'player')) &&
  5009. (installed_product_mismatch() != 0)) {
  5010. $clear_db = 1;
  5011. }
  5012. # Remove any installed product *if* user accepts.
  5013. prompt_user_to_remove_installed_product();
  5014. if (isToolsProduct()) {
  5015. preuninstall_installed_tools();
  5016. }
  5017. $status = system(shell_string($gInstallerObject) . ' uninstall --upgrade');
  5018. if ($status) {
  5019. error("Uninstall failed. Please correct the failure and re run the install.\n\n");
  5020. }
  5021. if (vmware_product() eq 'ws') {
  5022. $gOption{'ws-upgrade'} = 1;
  5023. }
  5024.  
  5025. # Beware, beyond this point, $gInstallerObject does not exist
  5026. # anymore.
  5027. } else {
  5028. # No installer object -> this is the old installer, which we don't support
  5029. # anymore.
  5030. $status = 1;
  5031. }
  5032. if ($status) {
  5033. remove_tmp_dir($bkp_dir);
  5034. # remove the installer db so the next invocation of install can proceed.
  5035. if (get_answer('Uninstallation of previous install failed. ' .
  5036. 'Would you like to remove the install DB?', 'yesno', 'no') eq 'yes') {
  5037. print wrap('Removing installer DB, please re-run the installer.' . "\n\n", 0);
  5038. unlink $gInstallerMainDB;
  5039. }
  5040.  
  5041. error('Failure' . "\n\n");
  5042. }
  5043.  
  5044. if ($clear_db == 1) {
  5045. create_initial_database();
  5046. return;
  5047. }
  5048.  
  5049. # Create the directory structure to welcome the restored database
  5050. $made_dir1 = 0;
  5051. if (not (-d $gRegistryDir)) {
  5052. safe_mkdir($gRegistryDir);
  5053. $made_dir1 = 1;
  5054. }
  5055. safe_chmod(0755, $gRegistryDir);
  5056. $made_dir2 = 0;
  5057. if ($version >= 2) {
  5058. if (not (-d $gStateDir)) {
  5059. safe_mkdir($gStateDir);
  5060. $made_dir2 = 1;
  5061. }
  5062. safe_chmod(0755, $gStateDir);
  5063. }
  5064.  
  5065. # Some versions of tar (1.13.17+ are ok) do not untar directory permissions
  5066. # as described in their documentation (they overwrite permissions of
  5067. # existing, non-empty directories with permissions stored in the archive)
  5068. #
  5069. # Because we didn't know about that at the beginning, the previous
  5070. # uninstallation may have included the directory structure in their database
  5071. # backup.
  5072. #
  5073. # To avoid that, we must re-package the database backup
  5074. if (vmware_product() eq 'tools-for-solaris') {
  5075. # Solaris' default tar(1) does not support gnu tar's -C or -z options.
  5076. system('cd ' . shell_string($bkp_dir) . ';'
  5077. . shell_string($gHelper{'gunzip'}) . ' -c ' . shell_string($bkp)
  5078. . ' | ' . shell_string($gHelper{'tar'}) . ' -xopf -');
  5079. } else {
  5080. system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
  5081. . ' -xzopf ' . shell_string($bkp));
  5082. }
  5083. $state_files = '';
  5084. if (-d $bkp_dir . $gStateDir) {
  5085. foreach $state_file (internal_ls($bkp_dir . $gStateDir)) {
  5086. $state_files .= ' ' . shell_string('.' . $gStateDir . '/'. $state_file);
  5087. }
  5088. }
  5089. $bkp = $bkp_dir . '/prev_db2.tar.gz';
  5090. if (vmware_product() eq 'tools-for-solaris') {
  5091. system('cd ' . shell_string($bkp_dir) . ';'
  5092. . shell_string($gHelper{'tar'}) . ' -copf - '
  5093. . shell_string('.' . $gInstallerMainDB) . $state_files
  5094. . ' | ' . shell_string($gHelper{'gzip'}) . ' > ' . shell_string($bkp));
  5095. } else {
  5096. system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
  5097. . ' -czopf ' . shell_string($bkp) . ' '
  5098. . shell_string('.' . $gInstallerMainDB) . $state_files);
  5099. }
  5100.  
  5101. # Restore the database ready to be used by our installer
  5102. if (vmware_product() eq 'tools-for-solaris') {
  5103. system('cd /;'
  5104. . shell_string($gHelper{'gunzip'}) . ' -c ' . shell_string($bkp)
  5105. . ' | ' . shell_string($gHelper{'tar'}) . ' -xopf -');
  5106. } else {
  5107. system(shell_string($gHelper{'tar'}) . ' -C / -xzopf ' . shell_string($bkp));
  5108. }
  5109. remove_tmp_dir($bkp_dir);
  5110.  
  5111. if ($version < 2) {
  5112. print wrap('Converting the ' . $intermediate_format
  5113. . ' installer database format to the tar4 installer database format.'
  5114. . "\n\n", 0);
  5115. # Upgrade the database format: keep only the 'answer' statements, and add a
  5116. # 'file' statement for the main database file
  5117. my $id;
  5118.  
  5119. db_load();
  5120. if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
  5121. error('Unable to open the tar installer database ' . $gInstallerMainDB
  5122. . ' in write-mode.' . "\n\n");
  5123. }
  5124. db_add_file($gInstallerMainDB, 0);
  5125. foreach $id (keys %gDBAnswer) {
  5126. print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
  5127. }
  5128. db_save();
  5129. } elsif( $version == 2 ) {
  5130. print wrap('Converting the ' . $intermediate_format
  5131. . ' installer database format to the tar4 installer database format.'
  5132. . "\n\n", 0);
  5133. # Upgrade the database format: keep only the 'answer' statements, and add a
  5134. # 'file' statement for the main database file
  5135. my $id;
  5136.  
  5137. db_load();
  5138. if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
  5139. error('Unable to open the tar installer database ' . $gInstallerMainDB
  5140. . ' in write-mode.' . "\n\n");
  5141. }
  5142. db_add_file($gInstallerMainDB, 0);
  5143. foreach $id (keys %gDBAnswer) {
  5144. # For the rpm3|tar3 format, a number of keywords were removed. In their
  5145. # place a more flexible scheme was implemented for which each has a semantic
  5146. # equivalent:
  5147. #
  5148. # VNET_HOSTONLY -> VNET_1_HOSTONLY
  5149. # VNET_HOSTONLY_HOSTADDR -> VNET_1_HOSTONLY_HOSTADDR
  5150. # VNET_HOSTONLY_NETMASK -> VNET_1_HOSTONLY_NETMASK
  5151. # VNET_INTERFACE -> VNET_0_INTERFACE
  5152. #
  5153. # Note that we no longer use the samba variables, so these entries are
  5154. # removed (and not converted):
  5155. # VNET_SAMBA -> VNET_1_SAMBA
  5156. # VNET_SAMBA_MACHINESID -> VNET_1_SAMBA_MACHINESID
  5157. # VNET_SAMBA_SMBPASSWD -> VNET_1_SAMBA_SMBPASSWD
  5158. my $newid = $id;
  5159. if ("$id" eq 'VNET_SAMBA') {
  5160. next;
  5161. } elsif ("$id" eq 'VNET_SAMBA_MACHINESID') {
  5162. next;
  5163. } elsif ("$id" eq 'VNET_SAMBA_SMBPASSWD') {
  5164. next;
  5165. } elsif ("$id" eq 'VNET_HOSTONLY') {
  5166. $newid='VNET_1_HOSTONLY';
  5167. } elsif ("$id" eq 'VNET_HOSTONLY_HOSTADDR') {
  5168. $newid='VNET_1_HOSTONLY_HOSTADDR';
  5169. } elsif ("$id" eq 'VNET_HOSTONLY_NETMASK') {
  5170. $newid='VNET_1_HOSTONLY_NETMASK';
  5171. } elsif ("$id" eq 'VNET_INTERFACE') {
  5172. $newid='VNET_0_INTERFACE';
  5173. }
  5174.  
  5175. print INSTALLDB 'answer ' . $newid . ' ' . $gDBAnswer{$id} . "\n";
  5176. }
  5177.  
  5178. # For the rpm4|tar4 format, two keyword were added. We add them here if
  5179. # necessary. Note that it is only necessary to check the existence of two
  5180. # VNET_HOSTONLY_ keywords since the rpm2|tar2 format contained only a few
  5181. # VNET_ keywords
  5182. my $addr = db_get_answer_if_exists('VNET_HOSTONLY_HOSTADDR');
  5183. my $mask = db_get_answer_if_exists('VNET_HOSTONLY_NETMASK');
  5184. if (defined($addr) and defined($mask)) {
  5185. print INSTALLDB 'answer VNET_1_HOSTONLY_SUBNET ' .
  5186. compute_subnet($addr, $mask) . "\n";
  5187. print INSTALLDB "answer VNET_1_DHCP yes\n";
  5188. }
  5189.  
  5190. db_save();
  5191. } elsif ( $version == 3 ) {
  5192. print wrap('Converting the ' . $intermediate_format
  5193. . ' installer database format to the tar4 installer database format.'
  5194. . "\n\n", 0);
  5195. # Upgrade the database format: keep only the 'answer' statements, and add a
  5196. # 'file' statement for the main database file
  5197. my $id;
  5198.  
  5199. db_load();
  5200. if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
  5201. error('Unable to open the tar installer database ' . $gInstallerMainDB
  5202. . ' in write-mode.' . "\n\n");
  5203. }
  5204. db_add_file($gInstallerMainDB, 0);
  5205.  
  5206. # No conversions necessary between version 3 and 4, so add all answers
  5207. foreach $id (keys %gDBAnswer) {
  5208. print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
  5209. }
  5210.  
  5211. # Check whether we need to add the two new keywords for each virtual network:
  5212. # VNET_n_HOSTONLY_SUBNET -> set if VNET_n_HOSTONLY_{HOSTADDR,NETMASK} are set
  5213. # VNET_n_DHCP -> 'yes' iff VNET_n_INTERFACE is not defined and
  5214. # VNET_n_HOSTONLY_{HOSTADDR,NETMASK} are defined
  5215. #
  5216. my $i;
  5217. for ($i = $gMinVmnet; $i < $gMaxVmnet; $i++) {
  5218. my $pre = 'VNET_' . $i . '_';
  5219. my $interface = db_get_answer_if_exists($pre . 'INTERFACE');
  5220. my $hostaddr = db_get_answer_if_exists($pre . 'HOSTONLY_HOSTADDR');
  5221. my $netmask = db_get_answer_if_exists($pre . 'HOSTONLY_NETMASK');
  5222.  
  5223. if (defined($hostaddr) && defined($netmask)) {
  5224. my $subnet = compute_subnet($hostaddr, $netmask);
  5225. print INSTALLDB 'answer ' . $pre . 'HOSTONLY_SUBNET ' . $subnet . "\n";
  5226.  
  5227. if (not defined($interface)) {
  5228. print INSTALLDB 'answer ' . $pre . "DHCP yes\n";
  5229. }
  5230. }
  5231. }
  5232.  
  5233. db_save();
  5234. }
  5235.  
  5236. db_load();
  5237. db_append();
  5238. if ($made_dir1) {
  5239. db_add_dir($gRegistryDir);
  5240. }
  5241. if ($made_dir2) {
  5242. db_add_dir($gStateDir);
  5243. }
  5244. }
  5245.  
  5246. sub create_initial_database {
  5247. my $made_dir1;
  5248. undef %gDBAnswer;
  5249. undef %gDBFile;
  5250. undef %gDBDir;
  5251. undef %gDBLink;
  5252. undef %gDBMove;
  5253.  
  5254. # This is the first installation. Create the installer database from
  5255. # scratch
  5256. print wrap('Creating a new ' . vmware_product_name()
  5257. . ' installer database using the tar4 format.' . "\n\n", 0);
  5258.  
  5259. $made_dir1 = not create_dir($gRegistryDir, 0);
  5260. safe_chmod(0755, $gRegistryDir);
  5261.  
  5262. if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
  5263. if ($made_dir1) {
  5264. rmdir($gRegistryDir);
  5265. }
  5266. error('Unable to open the tar installer database ' . $gInstallerMainDB
  5267. . ' in write-mode.' . "\n\n");
  5268. }
  5269. # Force a flush after every write operation.
  5270. # See 'Programming Perl', p. 110
  5271. select((select(INSTALLDB), $| = 1)[0]);
  5272.  
  5273. if ($made_dir1) {
  5274. db_add_dir($gRegistryDir);
  5275. }
  5276. # This file is going to be modified after its creation by this program.
  5277. # Do not timestamp it
  5278. db_add_file($gInstallerMainDB, 0);
  5279. }
  5280.  
  5281. # SIGINT handler. We will never reset the handler to the DEFAULT one, because
  5282. # with the exception of pre-uninstaller not being installed, this one does
  5283. # the same thing as the default (kills the process) and even sends the end
  5284. # RPC for us in tools installations.
  5285. sub sigint_handler {
  5286. if ($gIsUninstallerInstalled == 0) {
  5287. 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);
  5288.  
  5289. return;
  5290. }
  5291.  
  5292. error('');
  5293. }
  5294.  
  5295. # Get the installed version of VMware
  5296. # Return the version if found, or ''
  5297. sub get_installed_version() {
  5298. my $backslash;
  5299. my $dollar;
  5300. my $pattern;
  5301. my $version;
  5302. my $nameTag;
  5303.  
  5304. # XXX In the future, we should use a method of the installer object to
  5305. # retrieve the installed version
  5306.  
  5307. #
  5308. # Try to retrieve the installed version from the configurator program. This
  5309. # works for both the tar and the rpm installers
  5310. #
  5311.  
  5312. if (not defined($gDBAnswer{'BINDIR'})) {
  5313. return '';
  5314. }
  5315.  
  5316. if (not open(FILE, '<' . db_get_answer('BINDIR') . $gConfigurator)) {
  5317. return '';
  5318. }
  5319.  
  5320. # Build the pattern without using the dollar character, so that CVS doesn't
  5321. # modify the pattern in tagged builds (bug 9303)
  5322. $backslash = chr(92);
  5323. $dollar = chr(36);
  5324. $pattern = '^ ' . $backslash . $dollar . 'buildNr = ' .
  5325. "'" . '(\S+) ' . "'" . ' ' . $backslash . '. q' .
  5326. $backslash . $dollar . 'Name: (\S+)? ' . $backslash . $dollar . ';' . $dollar;
  5327.  
  5328. $version = '';
  5329. $nameTag = '';
  5330. while (<FILE>) {
  5331. if (/$pattern/) {
  5332. $version = $1;
  5333. $nameTag = defined($2) ? $2 : '';
  5334. }
  5335. }
  5336. close(FILE);
  5337.  
  5338. return $version;
  5339. }
  5340.  
  5341. # Get the installed kind of VMware
  5342. # Return the kind if found, or ''
  5343. sub get_installed_kind() {
  5344. my $kind;
  5345.  
  5346. if (not (-x $cInstallerObject)) {
  5347. return '';
  5348. }
  5349.  
  5350. $kind = direct_command(shell_string($cInstallerObject) . ' kind');
  5351. chop($kind);
  5352.  
  5353. return $kind;
  5354. }
  5355.  
  5356. # Install the content of the module package
  5357. sub install_module {
  5358. my %patch;
  5359.  
  5360. print wrap('Installing the kernel modules contained in this package.' . "\n\n", 0);
  5361.  
  5362. undef %patch;
  5363. install_dir('./lib', db_get_answer('LIBDIR'), \%patch, 0x1);
  5364. }
  5365.  
  5366. # Uninstall modules
  5367. sub uninstall_module {
  5368. print wrap('Uninstalling currently installed kernel modules.' . "\n\n", 0);
  5369.  
  5370. uninstall_prefix(db_get_answer('LIBDIR') . '/modules');
  5371. }
  5372.  
  5373. # XXX Duplicated in config.pl
  5374. # format of the returned hash:
  5375. # - key is the system file
  5376. # - value is the backed up file.
  5377. # This function should never know about filenames. Only database
  5378. # operations.
  5379. sub db_get_files_to_restore {
  5380. my %fileToRestore;
  5381. undef %fileToRestore;
  5382. my $restorePrefix = 'RESTORE_';
  5383. my $restoreBackupSuffix = '_BAK';
  5384. my $restoreBackList = 'RESTORE_BACK_LIST';
  5385.  
  5386. if (defined db_get_answer_if_exists($restoreBackList)) {
  5387. my $restoreStr;
  5388. foreach $restoreStr (split(/:/, db_get_answer($restoreBackList))) {
  5389. if (defined db_get_answer_if_exists($restorePrefix . $restoreStr)) {
  5390. $fileToRestore{db_get_answer($restorePrefix . $restoreStr)} =
  5391. db_get_answer($restorePrefix . $restoreStr
  5392. . $restoreBackupSuffix);
  5393. }
  5394. }
  5395. }
  5396. return %fileToRestore;
  5397. }
  5398.  
  5399. # Returns an array with the list of files that changed since we installed
  5400. # them.
  5401. sub db_is_file_changed {
  5402.  
  5403. my $file = shift;
  5404. my @statbuf;
  5405.  
  5406. @statbuf = stat($file);
  5407. if (defined $gDBFile{$file} && $gDBFile{$file} ne '0' &&
  5408. $gDBFile{$file} ne $statbuf[9]) {
  5409. return 'yes';
  5410. } else {
  5411. return 'no';
  5412. }
  5413. }
  5414.  
  5415. sub filter_out_bkp_changed_files {
  5416.  
  5417. my $filesToRestoreRef = shift;
  5418. my $origFile;
  5419.  
  5420. foreach $origFile (keys %$filesToRestoreRef) {
  5421. if (db_file_in($origFile) && !-l $origFile &&
  5422. db_is_file_changed($origFile) eq 'yes') {
  5423. # We are in the case of bug 25444 where we are restoring a file
  5424. # that we backed up and was changed in the mean time by someone else
  5425. db_remove_file($origFile);
  5426. backup_file($$filesToRestoreRef{$origFile});
  5427. unlink $$filesToRestoreRef{$origFile};
  5428. print wrap("\n" . 'File ' . $$filesToRestoreRef{$origFile}
  5429. . ' was not restored from backup because our file '
  5430. . $origFile
  5431. . ' got changed or overwritten between the time '
  5432. . vmware_product_name()
  5433. . ' installed the file and now.' . "\n\n"
  5434. ,0);
  5435. delete $$filesToRestoreRef{$origFile};
  5436. }
  5437. }
  5438. }
  5439.  
  5440. sub restore_backedup_files {
  5441. my $fileToRestore = shift;
  5442. my $origFile;
  5443.  
  5444. foreach $origFile (keys %$fileToRestore) {
  5445. if (file_name_exist($origFile) &&
  5446. file_name_exist($$fileToRestore{$origFile})) {
  5447. backup_file($origFile);
  5448. unlink $origFile;
  5449. }
  5450. if ((not file_name_exist($origFile)) &&
  5451. file_name_exist($$fileToRestore{$origFile})) {
  5452. rename $$fileToRestore{$origFile}, $origFile;
  5453. }
  5454. }
  5455. }
  5456.  
  5457. # depmod_all_kernels
  5458. #
  5459. # Runs depmod on all installed kernels on the system.
  5460. sub depmod_all_kernels {
  5461. my $depmodBin = shell_string($gHelper{'depmod'});
  5462.  
  5463. foreach my $kRel (internal_ls('/lib/modules/')) {
  5464. # Check if the modules.dep file exists. If so, then
  5465. # rebuild modules.dep for that kernel.
  5466. my $depmodPath = "/lib/modules/$kRel/modules.dep";
  5467. if (-f $depmodPath) {
  5468. system(join(' ', $depmodBin, '-a', $kRel));
  5469. }
  5470. }
  5471. }
  5472.  
  5473. # The initrd in place includes modules we added on configure. If the module
  5474. # files containing references to these modules have been restored then simply
  5475. # remaking the initrd will put it back into original condition.
  5476. sub restore_kernel_initrd {
  5477. my $cmd = db_get_answer_if_exists('RESTORE_RAMDISK_CMD');
  5478.  
  5479. if (defined($cmd)) {
  5480. # Rebuild all the system modules.dep files to reflect
  5481. # us ripping out all of the kernel modules.
  5482. depmod_all_kernels();
  5483.  
  5484. my $kernListStr = db_get_answer_if_exists('RESTORE_RAMDISK_KERNELS');
  5485. my $oneCall = db_get_answer_if_exists('RESTORE_RAMDISK_ONECALL');
  5486. if ($oneCall) {
  5487. if (system(join(' ', $cmd, '>/dev/null 2>&1')) != 0) {
  5488. # Check to ensure that the command succeded. If it didn't the system may
  5489. # not boot. We need to error out if that is the case.
  5490. error( wrap("ERROR: \"$cmd\" exited with non-zero status.\n" .
  5491. "\n" .
  5492. 'Your system currently may not have a functioning init ' .
  5493. 'image and may not boot properly. DO NOT REBOOT! ' .
  5494. 'Please ensure that you have enough free space available ' .
  5495. "in your /boot directory and run this command: \"$cmd\" " .
  5496. "again.\n\n", 0));
  5497.  
  5498. }
  5499.  
  5500. } elsif ($kernListStr) {
  5501. my @kerns = split(/,/, $kernListStr);
  5502.  
  5503. # Now for each kernel in our list, run the initrd restore command on it
  5504. foreach my $kern (@kerns) {
  5505. next unless (-e "/lib/modules/$kern/modules.dep");
  5506. my $fullCmd = $cmd;
  5507. $fullCmd =~ s/KREL/$kern/g;
  5508. if (system(join(' ', $fullCmd, '>/dev/null 2>&1')) != 0) {
  5509. error( wrap("ERROR: \"$fullCmd\" exited with non-zero status.\n" .
  5510. "\n" .
  5511. 'Your system currently may not have a functioning init ' .
  5512. 'image and may not boot properly. DO NOT REBOOT! ' .
  5513. 'Please ensure that you have enough free space available ' .
  5514. "in your /boot directory and run this command: \"$fullCmd\" " .
  5515. "again.\n\n", 0));
  5516. }
  5517. }
  5518. } else {
  5519. error("RESTORE_RAMDISK parameters were not properly set.\n");
  5520. }
  5521. # Now reset all the answers
  5522. db_remove_answer('RESTORE_RAMDISK_CMD');
  5523. db_remove_answer('RESTORE_RAMDISK_KERNELS');
  5524. db_remove_answer('RESTORE_RAMDISK_ONECALL');
  5525. }
  5526. }
  5527.  
  5528.  
  5529. ##
  5530. # unset_kmod_db_entries
  5531. #
  5532. # Iterates through the database and unsets kmod specific DB entries. This
  5533. # function is called at uninstall time since these modules are deleted as
  5534. # part of the uninstall. Yes I know I could do this faster... whatev.
  5535. #
  5536. sub unset_kmod_db_entries {
  5537. foreach my $kmod (@cKernelModules) {
  5538. my $regexp = '^' . uc($kmod) . '_.+_(PATH|NAME)';
  5539. foreach my $key (keys %gDBAnswer) {
  5540. db_remove_answer($key) if ($key =~ m/$regexp/);
  5541. }
  5542. }
  5543. }
  5544.  
  5545.  
  5546. ##
  5547. # deconfigure_updatedb
  5548. #
  5549. # Deconfigures updatedb.conf. Removes hgfs entry from PRUNEFS.
  5550. #
  5551. sub deconfigure_updatedb {
  5552. my $file = db_get_answer_if_exists('UPDATEDB_CONF_FILE');
  5553.  
  5554. return 0 unless ($file and -e $file);
  5555.  
  5556. my $key = db_get_answer('UPDATEDB_CONF_KEY');
  5557. db_remove_answer('UPDATEDB_CONF_FILE');
  5558. db_remove_answer('UPDATEDB_CONF_KEY');
  5559.  
  5560. my $regex = '^\s*(' . $key . '\s*=\s*")(.*)(")$';
  5561. my $delim = ' ';
  5562. my $entry = 'vmhgfs';
  5563. return removeTextInKVEntryInFile($file, $regex, $delim, $entry);
  5564. }
  5565.  
  5566. ##
  5567. # deconfigure_initrd_suse
  5568. #
  5569. # deconfigures /etc/sysconfig/kernel
  5570. #
  5571. sub deconfigure_initrd_suse {
  5572. my $file = db_get_answer_if_exists('INITRDMODS_CONF_FILE');
  5573.  
  5574. return 0 unless ($file and -e $file);
  5575.  
  5576. my $key = db_get_answer('INITRDMODS_CONF_KEY');
  5577. my $vals = db_get_answer_if_exists('INITRDMODS_CONF_VALS');
  5578.  
  5579. # this should never hit, but just in case
  5580. if (not defined $vals) {
  5581. print wrap("warning: could not INITRDMODS_CONF_VALS value in locations db.\n\n", 0);
  5582.  
  5583. db_remove_answer('INITRDMODS_CONF_FILE');
  5584. db_remove_answer('INITRDMODS_CONF_KEY');
  5585. return 0;
  5586. }
  5587.  
  5588. # put the space-delimited kmods in an array
  5589. my @splitVals = split(' ', $vals);
  5590.  
  5591. my $regex = '^\s*(' . $key . '\s*=\s*")(.*)(")$';
  5592. my $delim = ' ';
  5593.  
  5594. # removing all of the initrd kmods from the initrd file requires
  5595. # a loop because of the logic in removeTextInKVEntryInFile
  5596. foreach my $val (@splitVals) {
  5597. removeTextInKVEntryInFile($file, $regex, $delim, $val);
  5598. }
  5599.  
  5600. db_remove_answer('INITRDMODS_CONF_FILE');
  5601. db_remove_answer('INITRDMODS_CONF_KEY');
  5602. db_remove_answer('INITRDMODS_CONF_VALS');
  5603.  
  5604. }
  5605.  
  5606. ##
  5607. # deconfigure_dracut
  5608. #
  5609. # deconfigures /etc/dracut.conf
  5610. #
  5611. sub deconfigure_dracut {
  5612. my $file = db_get_answer_if_exists('INITRDMODS_CONF_FILE');
  5613.  
  5614. return 0 unless ($file and -e $file);
  5615.  
  5616. # we only deconfigure dracut.conf because /etc/dracut.conf.d/vmware-tools.conf
  5617. # should be removed through the normal uninstallation routes (i.e., it will be removed)
  5618. if ($file eq '/etc/dracut.conf') {
  5619. # Then we have to deconfigure it inline (should only need on fedora 12).
  5620. my $key = db_get_answer_if_exists('INITRDMODS_CONF_KEY');
  5621. my $vals = db_get_answer_if_exists('INITRDMODS_CONF_VALS');
  5622.  
  5623. if (not $key or not $vals) {
  5624. print wrap("warning: Unable to find $key or $vals in locations database.\n\n", 0);
  5625. return 0;
  5626. }
  5627.  
  5628. # put the space-delimited kmods in an array
  5629. my @splitVals = split(' ', $vals);
  5630.  
  5631. my $regex = '^\s*(' . $key . '\s*\+=\s*")(.*)(")$';
  5632. my $delim = ' ';
  5633.  
  5634. # removing all of the initrd kmods from the initrd file requires
  5635. # a loop because of the logic in removeTextInKVEntryInFile
  5636. foreach my $val (@splitVals) {
  5637. removeTextInKVEntryInFile($file, $regex, $delim, $val);
  5638. }
  5639.  
  5640. db_remove_answer('INITRDMODS_CONF_KEY');
  5641. db_remove_answer('INITRDMODS_CONF_VALS');
  5642.  
  5643. } elsif($file eq '/etc/dracut.conf.d/vmware-tools.conf') {
  5644. # do nothing because this file will be (or has already been) removed
  5645. # via our normal uninstallation routes (i.e., uninstaller goes through
  5646. # the installed files and removes them one by one).
  5647. } else {
  5648. print wrap("warning: Unable to deconfigure dracut.\n", 0);
  5649. }
  5650.  
  5651. # remove the answer regardless
  5652. db_remove_answer('INITRDMODS_CONF_FILE');
  5653. }
  5654.  
  5655. ##
  5656. # deconfigure_initmodfile
  5657. #
  5658. # Deconfigures the suse or dracut style initrd mechanisms
  5659. # (/etc/sysconfig/kernel or /etc/dracut.conf)
  5660. # deconfigure_dracut() defers Fedora 13+ .d style configurations
  5661. # to the normal uninstall mechanisms (removing the
  5662. # /etc/dracut.conf.d/vmware-tools.conf file)
  5663. #
  5664. sub deconfigure_initmodfile {
  5665. if (-e '/etc/SuSE-release') { # same logic we use to determine distribution in config.pl
  5666. deconfigure_initrd_suse();
  5667. } elsif (internal_which('dracut') ne '') {
  5668. deconfigure_dracut();
  5669. }
  5670. }
  5671.  
  5672.  
  5673. #
  5674. # For files modified with block_append(), rather than restoring a backup file
  5675. # remove what was appended. This will preserve any changes a user may have made
  5676. # to these files after install/config ran.
  5677. sub restore_appended_files {
  5678. my $list = '';
  5679.  
  5680. $list = db_get_answer_if_exists($cDBAppendString);
  5681. if (not defined($list)) {
  5682. return;
  5683. }
  5684.  
  5685. foreach my $file (split(':', $list)) {
  5686. if (-f $file) {
  5687. block_restore($file, $cMarkerBegin, $cMarkerEnd);
  5688. }
  5689. }
  5690. }
  5691.  
  5692. ### Does the dstDir have enough space to hold srcDir
  5693. sub check_disk_space {
  5694. my $srcDir = shift;
  5695. my $dstDir = shift;
  5696. my $srcSpace;
  5697. my $dstSpace;
  5698. my @parser;
  5699.  
  5700. # get the src usage
  5701. open (OUTPUT, shell_string($gHelper{'du'}) . ' -sk ' . shell_string($srcDir)
  5702. . ' 2>/dev/null|') or error("Failed to open 'du'.");
  5703. $_ = <OUTPUT>;
  5704. @parser = split(/\s+/);
  5705. $srcSpace = $parser[0];
  5706. close OUTPUT;
  5707.  
  5708. # Before we can check the space, $dst must exist. Walk up the directory path
  5709. # until we find something that exists.
  5710. while (! -d $dstDir) {
  5711. $dstDir = internal_dirname($dstDir);
  5712. }
  5713. open (OUTPUT, shell_string($gHelper{'df'}) . ' -k ' . shell_string($dstDir)
  5714. . ' 2>/dev/null|');
  5715. while (<OUTPUT>) {
  5716. @parser = split(/\s+/);
  5717. if ($parser[0] ne 'Filesystem') {
  5718. $dstSpace = $parser[3];
  5719. }
  5720. }
  5721. close OUTPUT;
  5722.  
  5723. # Return the amount of space available in kbytes.
  5724. return ($dstSpace - $srcSpace);
  5725. }
  5726.  
  5727.  
  5728. #
  5729. # Check to see that the product architecture is a mismatch for this os.
  5730. # Return an error string if there is a mismatch, otherwise return undef
  5731. #
  5732. sub product_os_match {
  5733.  
  5734. init_product_arch_hash();
  5735. if (!defined($multi_arch_products{vmware_product()})) {
  5736. return undef;
  5737. }
  5738.  
  5739. if (is64BitUserLand() == (vmware_product_architecture() eq "x86_64")) {
  5740. return undef;
  5741. }
  5742. if (is64BitUserLand() != (vmware_product_architecture() ne "x86_64")) {
  5743. return undef;
  5744. }
  5745.  
  5746. return sprintf('This version of "%s" is incompatible with this '
  5747. . 'operating system. Please install the "%s" '
  5748. . 'version of this program instead.'
  5749. . "\n\n", vmware_product_name(),
  5750. is64BitUserLand() ? 'x86_64' : 'i386');
  5751. }
  5752.  
  5753. #
  5754. # Create a list of products that support both a 32bit and a 64bit
  5755. # architecture and thus should be matched to the running OS.
  5756. #
  5757. sub init_product_arch_hash {
  5758. $multi_arch_products{'ws'} = 1;
  5759. $multi_arch_products{'vix'} = 1;
  5760. $multi_arch_products{'api'} = 1;
  5761. $multi_arch_products{'vicli'} = 1;
  5762. }
  5763.  
  5764. # Look for the location of an answer in a different database and return the
  5765. # the value or the empty string if no answer or file is found.
  5766. sub alt_db_get_answer {
  5767. my $db_file = shift;
  5768. my $key = shift;
  5769. my $answer = '';
  5770.  
  5771. if (open(PLAYERINSTALLDB, '<' . $db_file)) {
  5772. while (<PLAYERINSTALLDB>) {
  5773. chomp;
  5774. if (/^answer\s+$key\s+(.+)$/) {
  5775. $answer = $1;
  5776. } elsif (/^remove_answer\s+$key\s*$/) {
  5777. $answer = '';
  5778. }
  5779. }
  5780. close(PLAYERINSTALLDB);
  5781. }
  5782. return $answer;
  5783. }
  5784.  
  5785.  
  5786. # match the output of 'uname -s' to the product. These are compared without
  5787. # case sensitivity.
  5788. sub DoesOSMatchProduct {
  5789.  
  5790. my %osProductHash = (
  5791. 'tools-for-linux' => 'linux',
  5792. 'tools-for-solaris' => 'sunos',
  5793. 'tools-for-freebsd' => 'freebsd'
  5794. );
  5795.  
  5796. my $OS = `uname -s`;
  5797. chomp($OS);
  5798.  
  5799. return ($osProductHash{vmware_product()} =~ m/$OS/i) ? 1 : 0;
  5800.  
  5801. }
  5802.  
  5803.  
  5804. ##
  5805. # Checks to see if any of the package names in a given list
  5806. # are currently installed by RPM on the system.
  5807. # @param - A list of RPM packages to check for.
  5808. # @returns - A list of the installed RPM packages that this
  5809. # function checked for and found (if any).
  5810. #
  5811. sub checkRPMForPackages {
  5812. my @pkgList = @_;
  5813. my @instPkgs;
  5814. my $bin = internal_which('rpm');
  5815. my $cmd = join(' ', $bin, '-qa --queryformat \'%{NAME}\n\'');
  5816.  
  5817. if (-x $bin) {
  5818. open(OUTPUT, "$cmd |");
  5819. foreach my $instPkgName (<OUTPUT>) {
  5820. chomp $instPkgName;
  5821. foreach my $pkgName (@pkgList) {
  5822. if ($pkgName eq $instPkgName) {
  5823. push @instPkgs, $instPkgName;
  5824. }
  5825. }
  5826. }
  5827. close(OUTPUT);
  5828. }
  5829. return @instPkgs
  5830. }
  5831.  
  5832. ##
  5833. # Checks to see if any of the package names in a given list
  5834. # are currently installed by dpkg on the system.
  5835. # @param - A list of deb packages to check for.
  5836. # @returns - A list of the installed deb packages that this
  5837. # function checked for and found (if any).
  5838. #
  5839. sub checkDPKGForPackages {
  5840. my @pkgList = @_;
  5841. my @instPkgs;
  5842. my $bin = internal_which('dpkg-query');
  5843. my $cmd = join(' ', $bin, '--show --showformat=\'${Package}\n\'');
  5844.  
  5845. if (-x $bin) {
  5846. open(OUTPUT, "$cmd |");
  5847. foreach my $instPkgName (<OUTPUT>) {
  5848. chomp $instPkgName;
  5849. foreach my $pkgName (@pkgList) {
  5850. if ($pkgName eq $instPkgName) {
  5851. push @instPkgs, $instPkgName;
  5852. }
  5853. }
  5854. }
  5855. close(OUTPUT);
  5856. }
  5857. return @instPkgs
  5858. }
  5859.  
  5860.  
  5861. ##
  5862. # Attempts to remove the given list of RPM packages
  5863. # @param - List of rpm packages to remove
  5864. # @returns - -1 if there was an internal error, otherwise
  5865. # the return value of RPM
  5866. #
  5867. sub removeRPMPackages {
  5868. my @pkgList = @_;
  5869. my $bin = internal_which('rpm');
  5870. my @cmd = (("$bin", '-e'), @pkgList);
  5871.  
  5872. if (-x $bin) {
  5873. return system(@cmd);
  5874. } else {
  5875. return -1;
  5876. }
  5877. }
  5878.  
  5879.  
  5880. ##
  5881. # Attempts to remove the given list of DEB packages
  5882. # @param - List of deb packages to remove
  5883. # @returns - -1 if there was an internal error, otherwise
  5884. # the return value of dpkg
  5885. #
  5886. sub removeDEBPackages {
  5887. my @pkgList = @_;
  5888. my $bin = internal_which('dpkg');
  5889. my @cmd = (("$bin", '-r'), @pkgList);
  5890.  
  5891. if (-x $bin) {
  5892. return system(@cmd);
  5893. } else {
  5894. return -1;
  5895. }
  5896. }
  5897.  
  5898. sub check_ovt_compatibility {
  5899. # see bug #1460576:
  5900. if (vmware_product() eq 'tools-for-linux') {
  5901. if (getKernRelInteger() >= kernel_version_integer(4, 0, 0)) {
  5902. my $vmtoolsd = internal_which('vmtoolsd');
  5903.  
  5904. my $vmtoolsd_version_string = direct_command(shell_string($vmtoolsd) . " -v 2> /dev/null");
  5905. if (($vmtoolsd_version_string =~ /version ([\d+\.]+)/) and
  5906. (dot_version_compare($1, '10.0.0') < 0)) {
  5907.  
  5908. my $ans;
  5909. $ans = get_answer('For kernels >= 4.0.0, open-vm-tools need to be of ' .
  5910. 'version 10.0.0 or higher for VMware Host Guest Filessystem ' .
  5911. '(vmhgfs) to function with VMware Tools. ' .
  5912. 'Please upgrade open-vm-tools and rerun this installer, ' .
  5913. 'or uninstall open-vm-tools. Alternatively, you can disable using ' .
  5914. 'the vmhgfs when VMware Tools are configured.' . "\n\n" .
  5915. 'Enter yes to proceed.', 'yesno', ($gOption{'force-install'} == 1) ? 'yes' : 'no');
  5916. if ($ans ne 'yes') {
  5917. error('');
  5918. }
  5919. return('no');
  5920. }
  5921. }
  5922. }
  5923. return('yes');
  5924. }
  5925.  
  5926. # Program entry point
  5927. sub main {
  5928. my (@setOption, $opt);
  5929. my $chk_msg;
  5930. my $originalPath;
  5931. my $progpath = $0;
  5932. my $scriptname = internal_basename($progpath);
  5933. my $default_db_enable_hgfs;
  5934.  
  5935. if ((vmware_product() eq 'tools-for-linux' ||
  5936. vmware_product() eq 'tools-for-freebsd' ||
  5937. vmware_product() eq 'tools-for-solaris')
  5938. && !DoesOSMatchProduct()) {
  5939. error(vmware_longname() . ' will not install on the operating system you are ' .
  5940. 'running. Please be sure you install the version of ' .
  5941. vmware_product_name() . ' that is appropriate for your operating system.' .
  5942. "\n\n");
  5943. }
  5944.  
  5945. $chk_msg = product_os_match();
  5946. if (defined($chk_msg)) {
  5947. error($chk_msg);
  5948. }
  5949.  
  5950. if (!is_root()) {
  5951. error('Please re-run this program as the super user.' . "\n\n");
  5952. }
  5953.  
  5954. # Force the path to reduce the risk of using "modified" external helpers
  5955. # If the user has a special system setup, he will will prompted for the
  5956. # proper location anyway
  5957. $originalPath = $ENV{'PATH'};
  5958. $ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
  5959.  
  5960. initialize_globals(internal_dirname($0));
  5961. initialize_external_helpers();
  5962.  
  5963. # List of questions answered with command-line arguments
  5964. @setOption = ();
  5965.  
  5966. if (internal_basename($0) eq $cInstallerFileName or
  5967. internal_basename($0) eq $cInstallerFileNameReal) {
  5968. my $answer;
  5969.  
  5970. if ($#ARGV > -1) {
  5971. # There are only two possible arguments
  5972. while ($#ARGV != -1) {
  5973. my $arg;
  5974. $arg = shift(@ARGV);
  5975.  
  5976. if (lc($arg) =~ /^(-)?(-)?d(efault)?$/) {
  5977. $gOption{'default'} = 1;
  5978. } elsif (lc($arg) =~ /^(-)?(-)?r(egenerate-cert)?$/) {
  5979. # force to regenerate server key and cert files:
  5980. $gOption{'regenerate-cert'} = 1;
  5981. } elsif (lc($arg) =~ /^(-)?(-)?f(orce-install)?$/) {
  5982. # force install even though ovt is available:
  5983. $gOption{'force-install'} = 1;
  5984. } elsif (lc($arg) =~ /^--clobber-kernel-modules=([\w,]+)$/) {
  5985. $gOption{'clobberKernelModules'} = "$1";
  5986. } elsif (lc($arg) =~ /^-?-?prefix=.+/) {
  5987. # repeat regex with non-transformed arg to preserve case:
  5988. $arg =~ /^-?-?prefix=(.+)/;
  5989. $gOption{'prefix'} = $1;
  5990. } elsif ($arg =~ /=yes/ || $arg =~ /=no/) {
  5991. push(@setOption, $arg);
  5992. } elsif (lc($arg) =~ /^(-)?(-)?(no-create-shortcuts)$/) {
  5993. $gOption{'create_shortcuts'} = 0;
  5994. } else {
  5995. send_rpc('toolinstall.end 0');
  5996. install_usage();
  5997. }
  5998. }
  5999. }
  6000.  
  6001. if (-e '/etc/vmware/database' && (vmware_product() eq 'ws')) {
  6002. error("An incompatible VMware product is already installed on this " .
  6003. "machine. You must uninstall it by running vmware-uninstall.\n\n");
  6004. } elsif (-e '/etc/vmware-vix/database' && vmware_product() eq 'vix') {
  6005. error("An incompatible VMware product is already installed on this " .
  6006. "machine. You must uninstall it by running vmware-uninstall-vix.\n\n");
  6007. }
  6008.  
  6009. # Other installers will be able to remove this installation cleanly only if
  6010. # they find the uninstaller. That's why we:
  6011. # . Install the uninstaller ASAP
  6012. # . Prevent users from playing with Control-C while doing so
  6013.  
  6014. $gIsUninstallerInstalled = 0;
  6015.  
  6016. # Install the SIGINT handler. Don't bother resetting it, see
  6017. # sigint_handler for details.
  6018. $SIG{INT} = \&sigint_handler;
  6019. $SIG{QUIT} = \&sigint_handler;
  6020.  
  6021. # Tell the Host that the installer for tools is now
  6022. # active.
  6023. if (vmware_product() eq 'tools-for-linux' ||
  6024. vmware_product() eq 'tools-for-freebsd' ||
  6025. vmware_product() eq 'tools-for-solaris') {
  6026. send_rpc("toolinstall.installerActive 1");
  6027. }
  6028.  
  6029. # Check for open-vm-tools and related packages before we install
  6030. # tools-for-linux.
  6031. if (vmware_product() eq 'tools-for-linux') {
  6032. my @debPkgs = checkDPKGForPackages(@cOpenVMToolsDEBPackages);
  6033. my @rpmPkgs = checkRPMForPackages(@cOpenVMToolsRPMPackages);
  6034.  
  6035. if (@debPkgs or @rpmPkgs) {
  6036. my $pkg;
  6037.  
  6038. print wrap ('The installer has detected an existing ' .
  6039. 'installation of open-vm-tools on this system ' .
  6040. 'and will not attempt to remove and replace ' .
  6041. 'these user-space applications. It is recommended ' .
  6042. 'to use the open-vm-tools packages provided by ' .
  6043. 'the operating system. If you do not want to use ' .
  6044. 'the existing installation of open-vm-tools and ' .
  6045. 'attempt to install VMware Tools, you must ' .
  6046. 'uninstall the open-vm-tools packages and re-run ' .
  6047. 'this installer.' . "\n");
  6048. print wrap ("The packages that need to be removed are:\n");
  6049. foreach $pkg (@debPkgs, @rpmPkgs) {
  6050. print $pkg . "\n";
  6051. }
  6052. my $ans = get_answer('The installer will next check if there are ' .
  6053. 'any missing kernel drivers. Type yes if you want ' .
  6054. 'to do this, otherwise type no', 'yesno', 'yes');
  6055.  
  6056. if ($ans ne 'yes') {
  6057. error(
  6058. "\n\nPlease manually remove open-vm-tools before " .
  6059. "installing VMware Tools.\n\n");
  6060. } else {
  6061. if (check_ovt_compatibility() eq 'no') {
  6062. # we need to set the default to 'no' but the db isn't setup yet,
  6063. # so we need to remember this for later:
  6064. $default_db_enable_hgfs = 'no';
  6065. }
  6066. $open_vm_compat = 1;
  6067. }
  6068. } else {
  6069. my %os = identify_linux_variant();
  6070. if (%os) {
  6071. my $id = $os{"ID"};
  6072. my $version_id;
  6073.  
  6074. if (defined $os{"VERSION_ID"}) {
  6075. $version_id = $os{"VERSION_ID"};
  6076. } else {
  6077. # Assume Debian sid, the unstable distribution, has open-vm-tools.
  6078. if ($id eq "debian") {
  6079. $version_id = 7;
  6080. } else {
  6081. $version_id = 0;
  6082. }
  6083. }
  6084.  
  6085. $version_id =~ s/[^0-9.]//g;
  6086. if (($id eq "rhel" && $version_id >= 7.0) ||
  6087. ($id eq "centos" && $version_id >= 7.0) ||
  6088. ($id eq "ol" && $version_id >= 7.0) ||
  6089. ($id eq "fedora" && $version_id >= 19) ||
  6090. ($id eq "sles" && $version_id >= 12) ||
  6091. ($id eq "sled" && $version_id >= 12) ||
  6092. ($id eq "opensuse" && $version_id >= 12.2) ||
  6093. ($id eq "ubuntu" && $version_id >= 14.04) ||
  6094. ($id eq "debian" && $version_id >= 7)) {
  6095. # If installer db exists, user already made his choice to proceed.
  6096. my $ans = get_answer(
  6097. "open-vm-tools are available from the OS vendor and " .
  6098. "VMware recommends using open-vm-tools. " .
  6099. "See http://kb.vmware.com/kb/2073803 for more information.\n" .
  6100. "Do you still want to proceed with this legacy installer?",
  6101. 'yesno', (-e $gInstallerMainDB) || ($gOption{'force-install'} == 1) ? 'yes' : 'no');
  6102. if ($ans ne 'yes') {
  6103. exit 0;
  6104. }
  6105. }
  6106. }
  6107. }
  6108. }
  6109.  
  6110. # Don't allow installation of tools-for-solaris unless this is Solaris 9
  6111. # or later and 32-bit (for now). Note that we only officially support
  6112. # Solaris 10 Update 1 and higher, but we'll allow users to install on 9.
  6113. if (vmware_product() eq 'tools-for-solaris') {
  6114. my $solVersion = direct_command(shell_string($gHelper{'uname'}) . ' -r');
  6115. chomp($solVersion);
  6116. my ($major, $minor) = split /\./, $solVersion; # / Fix emacs fontification
  6117.  
  6118. if ($major != 5 || $minor < 9) {
  6119. error('VMware Tools for Solaris is only supported on Solaris 10 and later.'
  6120. . "\n\n");
  6121. }
  6122.  
  6123. # Warn users that we don't support Solaris 9, but they can install
  6124. if ($minor == 9) {
  6125. if (get_answer('WARNING: VMware Tools for Solaris is officially supported '
  6126. . 'on Solaris 10 and later, but you are running Solaris 9. '
  6127. . 'Would you like to continue with the installation?',
  6128. 'yesno', 'yes') eq 'no') {
  6129. error('You have selected to not install VMware Tools for Solaris on '
  6130. . 'Solaris 9.' . "\n\n");
  6131. }
  6132. }
  6133. }
  6134. if (vmware_product() eq 'tools-for-solaris' ||
  6135. vmware_product() eq 'tools-for-linux' ||
  6136. vmware_product() eq 'tools-for-freebsd') {
  6137. if (-e $dspMarkerFile) {
  6138. error('VMware Tools cannot be installed, since they have already ' .
  6139. 'been installed using a package-based mechanism (rpm or deb) ' .
  6140. 'on this system. If you wish to continue, you must first ' .
  6141. 'remove the currently installed VMware Tools using the '.
  6142. 'appropriate packaged-based mechanism, and then restart this ' .
  6143. 'installer' . "\n\n");
  6144. }
  6145. }
  6146.  
  6147. if (vmware_product() ne 'tools-for-linux' &&
  6148. vmware_product() ne 'tools-for-freebsd' &&
  6149. vmware_product() ne 'tools-for-solaris') {
  6150.  
  6151. # If the product is not tools, we need to bail on detecting a xen kernel.
  6152. if ( -d '/proc/xen' ) {
  6153. error('You cannot install ' .
  6154. vmware_product_name() .
  6155. ' on a system running a xen kernel.');
  6156. }
  6157. }
  6158.  
  6159. # The uninstall of legacy tools must come before get_initial_database()
  6160. if (vmware_product() eq 'tools-for-linux' ||
  6161. vmware_product() eq 'tools-for-freebsd') {
  6162. uninstall_content_legacy_tools();
  6163. }
  6164.  
  6165. if ( $progpath =~ /(.*?)\/$scriptname/ ) {
  6166. chdir($1);
  6167. }
  6168.  
  6169. my $dstDir = $gRegistryDir;
  6170. $gFirstCreatedDir = $dstDir;
  6171. while (!-d $dstDir) {
  6172. $gFirstCreatedDir = $dstDir;
  6173. $dstDir = internal_dirname($dstDir);
  6174. }
  6175. get_initial_database();
  6176.  
  6177. if($open_vm_compat) {
  6178. db_add_answer('OPEN_VM_COMPAT', 'yes');
  6179. } else {
  6180. db_add_answer('OPEN_VM_COMPAT', 'no');
  6181. }
  6182.  
  6183. # Binary wrappers can be run by any user and need to read the
  6184. # database.
  6185. safe_chmod(0644, $gInstallerMainDB);
  6186.  
  6187. db_add_answer('INSTALL_CYCLE', 'yes');
  6188.  
  6189. foreach $opt (@setOption) {
  6190. my ($key, $val);
  6191. ($key, $val) = ($opt =~ /^([^=]*)=([^=]*)/);
  6192. db_add_answer($key, $val);
  6193. }
  6194.  
  6195. if (defined($default_db_enable_hgfs)) {
  6196. db_add_answer('ENABLE_HGFS', $default_db_enable_hgfs);
  6197. }
  6198.  
  6199. if (vmware_product() eq 'api') {
  6200. my $previous = $gOption{'default'};
  6201. $gOption{'default'} = 0;
  6202. show_EULA();
  6203. $gOption{'default'} = $previous;
  6204. }
  6205.  
  6206. install_or_upgrade();
  6207.  
  6208. if (vmware_product() eq 'ws' || vmware_product() =~ 'tools-for-(linux|solaris)') {
  6209. configure_gtk2();
  6210. }
  6211.  
  6212. # Reset these answers in case we have installed new versions of these
  6213. # documents.
  6214. if (vmware_product() ne 'ws') {
  6215. db_remove_answer('EULA_AGREED');
  6216. db_remove_answer('ISC_COPYRIGHT_SEEN');
  6217. }
  6218. if (vmware_product() eq 'vix') {
  6219. print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
  6220. exit 0;
  6221. }
  6222.  
  6223. if (vmware_product() ne 'api' &&
  6224. vmware_product() ne 'nvdk' &&
  6225. vmware_product() ne 'vix-disklib') {
  6226. if (file_name_exist($gConfFlag)) {
  6227. $answer = get_persistent_answer('Before running '
  6228. . vmware_product_name()
  6229. . ' for the first time, you need to '
  6230. . 'configure it by invoking the '
  6231. . 'following command: "'
  6232. . db_get_answer('BINDIR')
  6233. . '/' . "$gConfigurator" . '". Do you '
  6234. . 'want this program to invoke the '
  6235. . 'command for you now?'
  6236. , 'RUN_CONFIGURATOR', 'yesno', 'yes');
  6237. } else {
  6238. if (vmware_product() ne 'vix') {
  6239. print wrap('Before running ' . vmware_product_name() . ' for the '
  6240. . 'first time, you need to configure it by invoking the'
  6241. . ' following command: "' . db_get_answer('BINDIR')
  6242. . '/' . "$gConfigurator" . '"' . "\n\n", 0);
  6243. }
  6244. $answer = 'no';
  6245. }
  6246. }
  6247.  
  6248. db_save();
  6249.  
  6250. my $configResult;
  6251.  
  6252. if ((vmware_product() ne 'api') &&
  6253. (vmware_product() ne 'nvdk') &&
  6254. ((vmware_product() ne 'vix-disklib')) &&
  6255. ($answer eq 'yes')) {
  6256. my $defaultOpt = ($gOption{'default'} == 1) ? ' --default' : '';
  6257. $defaultOpt .= defined($gOption{'prefix'}) ? ' --prefix'
  6258. . '=' . $gOption{'prefix'} : '';
  6259.  
  6260. # Pass in the clobber kernel modules option if necessary.
  6261. if (defined $gOption{'clobberKernelModules'}) {
  6262. $defaultOpt .= ' --clobber-kernel-modules=' .
  6263. $gOption{'clobberKernelModules'};
  6264. }
  6265.  
  6266. # If we're the tools installer, forego sending the end RPC and let
  6267. # the configurator do it.
  6268. my $rpcOpt = (vmware_product() eq 'tools-for-linux' ||
  6269. vmware_product() eq 'tools-for-freebsd' ||
  6270. vmware_product() eq 'tools-for-solaris') ?
  6271. ' --rpc-on-end' : '';
  6272.  
  6273. my $shortcutOpt = $gOption{'create_shortcuts'} ? '' : ' --no-create-shortcuts';
  6274.  
  6275. my $certOpt = ($gOption{'regenerate-cert'} == 1) ? ' --regenerate-cert' : '';
  6276.  
  6277. # restore the user's original PATH before running the configurator
  6278. $ENV{'PATH'} = $originalPath;
  6279.  
  6280. # Catch error result to see if configurator died abnormally.
  6281. $configResult = system(shell_string(db_get_answer('BINDIR') .
  6282. '/' . $gConfigurator) .
  6283. $defaultOpt . $rpcOpt . $shortcutOpt . $certOpt . ' --preserve');
  6284. } else {
  6285. print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
  6286. }
  6287.  
  6288. if (vmware_product() eq 'tools-for-linux') {
  6289. # For the fix to bug 304998, we are removing the hard-coded vmhgfs
  6290. # entry from /etc/fstab, and instead mounting/unmounting dynamically
  6291. # from the tools init script at startup/shutdown respectively. This
  6292. # allows the init script to check for certain conditions (e.g., not
  6293. # running on ESX) before deciding to do the mount.
  6294. block_restore('/etc/fstab', $cMarkerBegin, $cMarkerEnd);
  6295. }
  6296.  
  6297. # Tell the Host that the installer for tools is now
  6298. # active.
  6299. if (vmware_product() eq 'tools-for-linux' ||
  6300. vmware_product() eq 'tools-for-freebsd' ||
  6301. vmware_product() eq 'tools-for-solaris') {
  6302. send_rpc("toolinstall.installerActive 0");
  6303. }
  6304.  
  6305. exit 0;
  6306. }
  6307.  
  6308. #
  6309. # Module updater.
  6310. #
  6311. # XXX This is not clean. We really need separate packages, managed
  6312. # by the VMware package manager
  6313. #
  6314.  
  6315. if (internal_basename($0) eq $cModuleUpdaterFileName) {
  6316. my $installed_version;
  6317. my $installed_kind;
  6318. my $answer;
  6319.  
  6320. print wrap('Looking for a currently installed '
  6321. . vmware_longname() . ' tar package.' . "\n\n", 0);
  6322.  
  6323. if (not (-e $cInstallerMainDB)) {
  6324. error('Unable to find the ' . vmware_product_name() .
  6325. ' installer database file (' . $cInstallerMainDB . ').' .
  6326. "\n\n" . 'You may want to re-install the ' .
  6327. vmware_longname() . ' package, then re-run this program.' . "\n\n");
  6328. }
  6329. db_load();
  6330.  
  6331. $installed_version = get_installed_version();
  6332. $installed_kind = get_installed_kind();
  6333.  
  6334. if (not (($installed_version eq '10.0.12') and
  6335. ($installed_kind eq 'tar'))) {
  6336. error('This ' . vmware_product_name()
  6337. . ' Kernel Modules package is intended to be used in conjunction '
  6338. . 'with the ' . vmware_longname() . ' tar package only.' . "\n\n");
  6339. }
  6340.  
  6341. # All module files are under LIBDIR
  6342. if (not defined($gDBAnswer{'LIBDIR'})) {
  6343. error('Unable to determine where the ' . vmware_longname()
  6344. . ' package installed the library files.' . "\n\n"
  6345. . 'You may want to re-install the ' . vmware_product_name() . ' '
  6346. . vmware_version() . ' package, then re-run this program.' . "\n\n");
  6347. }
  6348.  
  6349. db_append();
  6350. uninstall_module();
  6351. install_module();
  6352.  
  6353. print wrap('The installation of ' . vmware_product_name()
  6354. . ' Kernel Modules '
  6355. . vmware_version() . ' completed successfully.' . "\n\n", 0);
  6356.  
  6357. if (-e $cConfFlag) {
  6358. $answer = get_persistent_answer('Before running the VMware software for '
  6359. . 'the first time after this update, you'
  6360. . ' need to configure it for your '
  6361. . 'running kernel by invoking the '
  6362. . 'following command: "'
  6363. . db_get_answer('BINDIR')
  6364. . '/' . $gConfigurator . '". Do you want this '
  6365. . 'program to invoke the command for you now?',
  6366. 'RUN_CONFIGURATOR', 'yesno', 'yes');
  6367. } else {
  6368. $answer = 'no';
  6369. }
  6370.  
  6371. db_save();
  6372.  
  6373. if ($answer eq 'yes') {
  6374. system(shell_string(db_get_answer('BINDIR') . '/' . $gConfigurator));
  6375. } else {
  6376. print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
  6377. }
  6378. exit 0;
  6379. }
  6380.  
  6381. if (internal_basename($0) eq $gUninstallerFileName) {
  6382. print wrap('Uninstalling the tar installation of ' .
  6383. vmware_product_name() . '.' . "\n\n", 0);
  6384.  
  6385. if ($#ARGV > -1) {
  6386. @setOption = ();
  6387. # There are currently two options: --upgrade and --preserve-guest-proxy-data.
  6388. while ($#ARGV != -1) {
  6389. my $arg;
  6390. $arg = shift(@ARGV);
  6391. if (lc($arg) =~ /^(-)?(-)?u(pgrade)?$/) {
  6392. $gOption{'upgrade'} = 1;
  6393. } elsif (lc($arg) =~ /^(-)?(-)?p(reserve-guest-proxy-data)?$/) {
  6394. $gOption{'preserve-guest-proxy-data'} = 1;
  6395. } elsif ($arg =~ /=yes/ || $arg =~ /=no/) {
  6396. push(@setOption, $arg);
  6397. }
  6398. }
  6399. }
  6400.  
  6401. if (not (-e $gInstallerMainDB)) {
  6402. error('Unable to find the tar installer database file (' .
  6403. $gInstallerMainDB . ')' . "\n\n");
  6404. }
  6405. db_load();
  6406.  
  6407. db_append();
  6408.  
  6409. ### Begin check for non-VMware modules ###
  6410. foreach $opt (@setOption) {
  6411. my ($key, $val);
  6412. ($key, $val) = ($opt =~ /^([^=]*)=([^=]*)/);
  6413. delete $gDBAnswer{$key};
  6414. db_add_answer($key, $val);
  6415. }
  6416.  
  6417. if (vmware_product() eq 'tools-for-linux' ||
  6418. vmware_product() eq 'tools-for-freebsd' ||
  6419. vmware_product() eq 'tools-for-solaris') {
  6420.  
  6421. my %fileToRestore;
  6422.  
  6423. # Clean up the module loader config file from vmxnet.
  6424. if (vmware_product() eq 'tools-for-freebsd' &&
  6425. defined db_get_answer_if_exists('VMXNET_CONFED') &&
  6426. db_get_answer('VMXNET_CONFED') eq 'yes') {
  6427. my $loader_conf = '/boot/loader.conf';
  6428. my $tmp_dir;
  6429. my $tmp; # / unconfuse emacs fontification
  6430. $tmp_dir = make_tmp_dir('vmware-installer');
  6431. $tmp = $tmp_dir . '/loader.conf';
  6432. if (block_remove($loader_conf, $tmp, $cMarkerBegin, $cMarkerEnd) >= 0) {
  6433. system(shell_string($gHelper{'mv'}) . ' -f ' . shell_string($tmp)
  6434. . ' '
  6435. . shell_string($loader_conf));
  6436. }
  6437. remove_tmp_dir($tmp_dir);
  6438. }
  6439.  
  6440. #
  6441. # Legacy autostart hooks involved modifying system files, so we must manually
  6442. # restore the VMware-added blocks.
  6443. #
  6444. if (vmware_product() =~ /^tools-for-(linux|freebsd|solaris)$/) {
  6445. unconfigure_autostart_legacy($cMarkerBegin, $cMarkerEnd);
  6446. }
  6447.  
  6448. # Get the file names before they disappear from the database.
  6449. %fileToRestore = db_get_files_to_restore();
  6450.  
  6451. filter_out_bkp_changed_files(\%fileToRestore);
  6452.  
  6453. if (db_get_answer('OPEN_VM_COMPAT') eq 'yes') {
  6454. $open_vm_compat = 1
  6455. }
  6456.  
  6457. # Do the bulk of the file uninstallation. Pass in the (slightly)
  6458. # different name for FreeBSD Tools so that they get stopped correctly.
  6459. if (vmware_product() eq 'tools-for-freebsd') {
  6460. uninstall('/vmware-tools.sh');
  6461. } else {
  6462. uninstall('/vmware-tools');
  6463. }
  6464.  
  6465. # Clean up drivers with rem_drv(1M) (corresponds to add_drv(1M) calls in
  6466. # configure_module_solaris() in configure script). This needs to happen
  6467. # after the services are stopped in uninstall().
  6468. if (vmware_product() eq 'tools-for-solaris') {
  6469. if (defined db_get_answer_if_exists('VMXNET_CONFED') &&
  6470. db_get_answer('VMXNET_CONFED') eq 'yes') {
  6471.  
  6472. system(shell_string($gHelper{'rem_drv'}) . ' vmxnet');
  6473.  
  6474. # Give pcn its claim on pci1022,2000 back
  6475. if (direct_command(shell_string($gHelper{'uname'}) . ' -r') =~ 5.9) {
  6476. # Try to add back the pcn driver we removed
  6477. system(shell_string($gHelper{'add_drv'})
  6478. . ' -i \'"pci103c,104c" "pci1022,2000"\' pcn >/dev/null 2>&1');
  6479. } else {
  6480. system(shell_string($gHelper{'update_drv'}) . ' -a -i \'"pci1022,2000"\' '
  6481. . 'pcn >/dev/null 2>&1');
  6482. }
  6483. }
  6484. if (defined db_get_answer_if_exists('VMXNET3S_CONFED') &&
  6485. db_get_answer('VMXNET3S_CONFED') eq 'yes') {
  6486. system(shell_string($gHelper{'rem_drv'}) . ' vmxnet3s');
  6487. }
  6488. if (defined db_get_answer_if_exists('VMHGFS_CONFED') &&
  6489. db_get_answer('VMHGFS_CONFED') eq 'yes') {
  6490. my $devLinkTable = "/etc/devlink.tab";
  6491. my $searchString = "name=vmhgfs";
  6492.  
  6493. system(shell_string($gHelper{'rem_drv'}) . ' vmhgfs');
  6494.  
  6495. if (system(shell_string($gHelper{'grep'}) . ' ' . $searchString
  6496. . ' ' . $devLinkTable . ' > /dev/null 2>&1') == 0) {
  6497. # XXX There has to be a better way, but I don't know Perl
  6498. my $tmpFile = "/tmp/VMware.devlink.tab";
  6499. system(shell_string($gHelper{'cat'}) . ' ' . $devLinkTable . ' | '
  6500. . shell_string($gHelper{'grep'}) . ' -v ' . $searchString
  6501. . ' > ' . $tmpFile);
  6502. system(shell_string($gHelper{'mv'}) . ' ' . $tmpFile . ' '
  6503. . $devLinkTable);
  6504. }
  6505. }
  6506. }
  6507.  
  6508. if (vmware_product() eq 'tools-for-linux') {
  6509. if (defined db_get_answer_if_exists('VMHGFS_CONFED') &&
  6510. db_get_answer('VMHGFS_CONFED') eq 'yes') {
  6511. # remove the entries for the vmhgfs mount.
  6512. block_restore('/etc/fstab', $cMarkerBegin, $cMarkerEnd);
  6513. }
  6514.  
  6515. # If we modfified the ld.so cache during the install, we need to
  6516. # run ldconfig here to ensure that the tools libraries are no
  6517. # longer in the system library path.
  6518. if (defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_ADDED_FILE') or
  6519. defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_MODIFIED')) {
  6520. #
  6521. # Check to see if we modified ld.so.conf. If we did, then we need
  6522. # to properly restore it.
  6523. #
  6524. if (defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_MODIFIED')) {
  6525. my $file = db_get_answer('LD_DOT_SO_DOT_CONF_MODIFIED');
  6526. block_restore($file, $cMarkerBegin, $cMarkerEnd);
  6527. }
  6528.  
  6529. if (internal_which('ldconfig') ne '') {
  6530. system('ldconfig &> /dev/null');
  6531. }
  6532. }
  6533.  
  6534. # Call the prelink_restore function to fix that if it has been modified.
  6535. prelink_restore();
  6536. }
  6537.  
  6538. # remove the modules added to the list for the initrd.
  6539. # Also restore the system Ramdisk (either initrd or initramfs)
  6540. restore_appended_files();
  6541. restore_backedup_files(\%fileToRestore);
  6542. deconfigure_initmodfile();
  6543. restore_kernel_initrd();
  6544.  
  6545. if (defined db_get_answer_if_exists('VMWGFX_CONFED') &&
  6546. db_get_answer('VMWGFX_CONFED') eq 'yes' &&
  6547. (internal_which('ldconfig') ne '')) {
  6548. system('ldconfig &> /dev/null');
  6549. }
  6550.  
  6551. deconfigure_updatedb();
  6552. unset_kmod_db_entries();
  6553.  
  6554. # Check the DB to see if we need to restart HAL.
  6555. if (defined db_get_answer_if_exists('HAL_RESTART_ON_UNINSTALL') and
  6556. db_get_answer('HAL_RESTART_ON_UNINSTALL') eq 'yes') {
  6557. restart_hal();
  6558. }
  6559.  
  6560. # do not kill vmtoolsd on upgrade (see bug #838010)
  6561. if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
  6562. # Kill vmusr vmtoolsd instance before we exit.
  6563. my $pkillBin = internal_which('pkill');
  6564. if (-x $pkillBin) {
  6565. system("$pkillBin -f 'vmtoolsd -n vmusr' >/dev/null 2>&1");
  6566. }
  6567. }
  6568.  
  6569. } elsif (vmware_product() eq 'vix') {
  6570. uninstall_vix();
  6571. } elsif (vmware_product() eq 'ws') {
  6572. uninstall('/vmware');
  6573. } elsif (vmware_product() eq 'vix-disklib') {
  6574. uninstall('/vmware-vix-disklib');
  6575. } elsif (vmware_product() eq 'nvdk') {
  6576. uninstall('/nvdk');
  6577. } else {
  6578. uninstall('/vmware');
  6579. }
  6580.  
  6581. db_save();
  6582.  
  6583. my $msg = 'The removal of ' . vmware_longname() . ' completed '
  6584. . 'successfully.';
  6585. if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
  6586. $msg .= " Thank you for having tried this software.";
  6587. }
  6588. $msg .= "\n\n";
  6589. print wrap($msg, 0);
  6590.  
  6591. system(internal_which('sync'));
  6592.  
  6593. exit 0;
  6594. }
  6595.  
  6596. error('This program must be named ' . $cInstallerFileName . ' or '
  6597. . $gUninstallerFileName . '.' . "\n\n");
  6598. }
  6599.  
  6600. main();
  6601.  
Advertisement
Add Comment
Please, Sign In to add comment