· 10 years ago · Aug 30, 2016, 08:52 AM
1#!/usr/bin/perl -w
2# If your copy of perl is not in /usr/bin, please adjust the line above.
3#
4# Copyright (c) 1998-2016 VMware, Inc. All rights reserved.
5#
6# Tar package manager for VMware
7
8use strict;
9use IO::Handle qw( ); # For autoflush
10STDOUT->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
19use strict;
20no warnings 'once'; # Warns about use of Config::Config in config.pl
21
22my $have_thinprint='yes';
23my $have_vgauth='yes';
24my $have_caf='yes';
25my $have_grabbitmqproxy='yes';
26
27# A list of known open-vm-tools packages
28#
29my @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
42my @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
51my %gOption;
52# Moved from various scripts that include util.pl
53my %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#
60my @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#
69my %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#
77my %cKernelModuleDeps = (vsock => ('vmci'),
78 vmhgfs => ('vmci'));
79
80#
81# Module PCI ID and alias definitions.
82#
83my %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#
102my %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
115my %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
126my %cToolsLinuxServices;
127if ($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
138my %cToolsSolarisServices = (
139 'services' => 'vmware-tools',
140);
141
142my %cToolsFreeBSDServices = (
143 'services' => 'vmware-tools.sh',
144);
145
146#
147# Hashes to track vmware modules.
148#
149my %gNonVmwareModules = ();
150my %gVmwareInstalledModules = ();
151my %gVmwareRunningModules = ();
152
153my $cTerminalLineSize = 79;
154
155# Flags
156my $cFlagTimestamp = 0x1;
157my $cFlagConfig = 0x2;
158my $cFlagDirectoryMark = 0x4;
159my $cFlagUserModified = 0x8;
160my $cFlagFailureOK = 0x10;
161
162# See vmware_service_issue_command
163my $cServiceCommandDirect = 0;
164my $cServiceCommandSystem = 1;
165
166# Strings for Block Appends.
167my $cMarkerBegin = "# Beginning of the block added by the VMware software - DO NOT EDIT\n";
168my $cMarkerEnd = "# End of the block added by the VMware software\n";
169my $cDBAppendString = 'APPENDED_FILES';
170
171# util.pl Globals
172my %gSystem;
173
174# Needed to access $Config{...}, the Perl system configuration information.
175require Config;
176
177# Tell if the user is the super user
178sub 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.
185sub 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.
201sub isDesktopProduct {
202 return vmware_product() eq "ws" || vmware_product() eq "player";
203}
204
205sub 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.
213sub 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.
221sub 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.
230sub 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
242sub 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.
277sub 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.
288sub 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
298sub 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
314sub 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
353sub 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#
385sub 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
392sub 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
414sub 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
423sub 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
468sub 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
482sub 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
524sub 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
542sub 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
571sub 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
602sub 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
647sub 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
667sub 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.
723sub 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
749sub 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
759sub 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)
803sub direct_command {
804 return `$_[0]`;
805}
806
807# If there is a pid for this process, consider it running.
808sub 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.
817sub 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
854sub 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
867sub 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
904sub 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.
948sub 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.
976sub 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.
1097sub 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#
1136sub 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
1166sub 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
1205sub 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#
1254sub 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
1266sub 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
1288sub 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
1333sub 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
1343sub 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#
1367sub 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#
1397sub 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#
1428sub 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
1491sub 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#
1520sub 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
1593sub 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
1612sub 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#
1626sub 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
1643sub 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
1652use POSIX;
1653use Config;
1654
1655# Constants
1656my $cInstallerFileName = 'vmware-install.pl';
1657my $cInstallerFileNameReal = 'vmware-install.real.pl';
1658my $cModuleUpdaterFileName = 'install.pl';
1659my $cInstallerDir = './installer';
1660my $cStartupFileName = $cInstallerDir . '/services.sh';
1661my $cStartupFileNameThinPrint = $cInstallerDir . '/thinprint.sh';
1662my $cRegistryDir = '/etc/vmware';
1663my $cInstallerMainDB = $cRegistryDir . '/locations';
1664my $cInstallerObject = $cRegistryDir . '/installer.sh';
1665my $cConfFlag = $cRegistryDir . '/not_configured';
1666my $dspMarkerFile = '/usr/lib/vmware-tools/dsp';
1667# Constant defined as the smallest vmnet that is allowed
1668my $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
1673my $gMaxVmnet = '99';
1674
1675my $open_vm_compat = 0;
1676
1677my $cChkconfigInfo = <<END;
1678# Basic support for IRIX style chkconfig
1679# chkconfig: 2345 03 99
1680# description: Manages the services needed to run VMware software
1681END
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
1688my $cChkconfigInfoThinPrint = <<END;
1689# Basic support for IRIX style chkconfig
1690# chkconfig: 2345 57 43
1691# description: Manages the services needed to run VMware software
1692END
1693
1694my $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
1706END
1707
1708my $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
1718END
1719
1720# MANIFEST file and hash for installing ACE VMs
1721my $cManifestFilename = 'MANIFEST';
1722my %gManifest;
1723my $gACEVMUpdate = 0;
1724my $gHostVmplDir = "/etc/vmware/vmware-ace";
1725my $gPlayerBundle = '';
1726
1727# Has the uninstaller been installed?
1728my $gIsUninstallerInstalled;
1729
1730# Hash of multi architecture supporting products
1731my %multi_arch_products;
1732
1733# BEGINNING OF THE SECOND LIBRARY FUNCTIONS
1734# Global variables
1735my $gRegistryDir;
1736my $gFirstCreatedDir = undef;
1737my $gStateDir;
1738my $gInstallerMainDB;
1739my $gInstallerObject;
1740my $gConfFlag;
1741my $gUninstallerFileName;
1742my $gConfigurator;
1743my $gConfig;
1744my $gConfigFile;
1745
1746my %gDBAnswer;
1747my %gDBFile;
1748my %gDBDir;
1749my %gDBLink;
1750my %gDBMove;
1751
1752# list of files that are config failes users may modify
1753my %gDBUserModified;
1754my %gDBConfig;
1755
1756#
1757# db_clear
1758#
1759# Unsets all variables modified in the db_load process
1760#
1761sub 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#
1777sub 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
1814sub 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
1826sub 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
1847sub 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
1855sub 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
1863sub 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
1870sub db_dir_in {
1871 my $dir = shift;
1872
1873 return defined($gDBDir{$dir});
1874}
1875
1876# Return the timestamp of an installed file
1877sub db_file_ts {
1878 my $file = shift;
1879
1880 return $gDBFile{$file};
1881}
1882
1883# Add a directory to the tar installer database
1884sub 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
1892sub 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
1902sub 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
1912sub 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;
1925sub 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
1937sub db_save {
1938 close(INSTALLDB);
1939}
1940
1941# END OF THE SECOND LIBRARY FUNCTIONS
1942
1943# BEGINNING OF THE LIBRARY FUNCTIONS
1944# Global variables
1945my %gAnswerSize;
1946my %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
1954sub 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 ''
1986sub 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
2007sub 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
2024sub 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.
2043sub 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
2085sub 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
2095sub 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()
2125sub 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
2152sub 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
2161sub 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
2190sub 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
2211sub 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
2233sub 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
2256sub 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
2282sub 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
2335sub 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
2367sub vmware_version {
2368 my $buildNr;
2369
2370 $buildNr = '10.0.6 build-3595377';
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 ''
2376sub 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 ''
2398sub 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
2412sub internal_basename {
2413 return substr($_[0], rindex($_[0], '/') + 1);
2414}
2415
2416# Set the name of the main /etc/vmware* directory.
2417sub 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
2467sub load_config() {
2468 $gConfig = new VMware::Config;
2469 $gConfig->readin($gConfigFile);
2470}
2471
2472# Set up the location of external helpers
2473sub 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 ''
2551sub 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 ''
2592sub 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 ''
2628sub 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 ''
2666sub 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 ''
2686sub 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 ''
2705sub 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
2722sub 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
2745sub 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
2835sub 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.
2876sub 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
2978sub 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.
2992sub 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.
3000sub 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.
3035sub 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
3075sub 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
3127sub 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
3172sub 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
3181sub 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
3206sub 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
3225sub 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'.
3242sub 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'.
3257sub 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
3275sub 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.
3317sub 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
3343sub 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
3353sub 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 install_content_caf($rootdir);
3527
3528 if ($have_grabbitmqproxy eq 'yes') {
3529 install_content_guestproxy($rootdir);
3530 }
3531 if ($have_vgauth eq 'yes') {
3532 install_content_vgauth($rootdir);
3533 }
3534 }
3535
3536 # We don't yet maintain ownership and permissions metadata for all the
3537 # files we install. For the timebeing until vmis obsoletes this code,
3538 # this will workaround the scenario of the install tarball being extracted
3539 # as a user, and thus the suid bit on vmware-user-suid-wrapper being
3540 # cleared before install.
3541
3542 # Setuid root
3543 if (vmware_product() eq 'tools-for-freebsd') {
3544 safe_chmod(04555, $answer . '/bin32-63/vmware-user-suid-wrapper');
3545 safe_chmod(04555, $answer . '/bin64-63/vmware-user-suid-wrapper');
3546 } elsif (vmware_product() eq 'tools-for-solaris') {
3547 # note: for solaris, the amd64 version is a symlink to this i86 version
3548 safe_chmod(04555, $answer . '/bin/i86/vmware-user-suid-wrapper');
3549 } elsif (vmware_product() eq 'tools-for-linux') {
3550 safe_chmod(04555, $answer . '/bin32/vmware-user-suid-wrapper');
3551 safe_chmod(04555, $answer . '/bin64/vmware-user-suid-wrapper');
3552 }
3553
3554 # Deal with hgfsmounter which is not suid anymore
3555 # .. and with vmblockmounter as well.
3556 if (vmware_product() eq 'tools-for-linux') {
3557 safe_chmod(0555, $answer . '/sbin32/vmware-hgfsmounter');
3558 safe_chmod(0555, $answer . '/sbin64/vmware-hgfsmounter');
3559 } elsif (vmware_product() eq 'tools-for-solaris') {
3560 safe_chmod(0555, $answer . '/sbin/i86/vmware-hgfsmounter');
3561 safe_chmod(0555, $answer . '/sbin/amd64/vmware-hgfsmounter');
3562 safe_chmod(0555, $answer . '/sbin/i86/vmware-vmblockmounter');
3563 safe_chmod(0555, $answer . '/sbin/amd64/vmware-vmblockmounter');
3564 } elsif (vmware_product() eq 'tools-for-freebsd') {
3565 safe_chmod(0555, $answer . '/sbin32-63/vmware-vmblockmounter');
3566 safe_chmod(0555, $answer . '/sbin64-63/vmware-vmblockmounter');
3567 }
3568
3569 $docdir = $rootdir . '/share/doc';
3570 if (not (-d $docdir)) {
3571 $docdir = $rootdir . '/doc';
3572 }
3573 $answer = spacechk_answer('In which directory do you want to install the '
3574 . 'documentation files?', 'dirpath', $docdir
3575 . '/vmware-tools', './doc');
3576 db_add_answer('DOCDIR', $answer);
3577 undef %patch;
3578 install_dir('./doc', $answer, \%patch, 0x1);
3579
3580 #
3581 # Modify vmware-user.desktop so that the Execute variable gets
3582 # a full path to the vmware-user binary instead of having to
3583 # rely on the PATH var being set correctly.
3584 #
3585 # See bug 368867 for details. -astiegmann
3586 #
3587 my $execStr = 'Exec=' . db_get_answer('BINDIR') . '/vmware-user';
3588 my $filePath = $gRegistryDir . '/vmware-user.desktop';
3589 %patch = ('Exec=.*$' => $execStr);
3590 internal_sed ('./etc/vmware-user.desktop', $filePath, 0, \%patch);
3591
3592 # re-add file to database so they it will not stay behind on uninstall
3593 # see bug #745860
3594 db_add_file($filePath, 0x1);
3595}
3596
3597sub uninstall_content_legacy_tools {
3598 my $OldInstallerDB = '/etc/vmware-tools/tools_log';
3599 my $OldInstallerDBOld = '/etc/vmware/tools_log';
3600 my $TmpMainDB = $gInstallerMainDB;
3601 my $File;
3602 my @Files;
3603 my $MovedFile;
3604 my $LinkedFile;
3605 my $answer;
3606 my $runlevel;
3607
3608 # This is necessary for old installations of the tools
3609 # when /etc/vmware was one and unique dump for all the products
3610 if (-e $OldInstallerDBOld) {
3611 $OldInstallerDB = $OldInstallerDBOld;
3612 }
3613 if (!-e $OldInstallerDB) {
3614 # Old tools database not found, assume that the system is clean.
3615 return;
3616 }
3617 # Swap the db with the old one temporarely.
3618 $gInstallerMainDB = $OldInstallerDB;
3619
3620 db_load();
3621 if (not open(INSTALLDB, '>>' . $gInstallerMainDB)) {
3622 error('Unable to open the tar installer database ' . $gInstallerMainDB
3623 . ' in write-mode.' . "\n\n");
3624 }
3625
3626 $answer = get_answer('An old installation of the tools is detected. '
3627 . 'Should this installation be removed ?',
3628 'yesno', 'yes');
3629 if ($answer eq 'no') {
3630 error('');
3631 }
3632
3633 # Stop the services
3634 foreach $File (keys %gDBFile) {
3635 if ($File =~ /\S+\/dualconf(\.sh)?$/) {
3636 system(shell_string($File) . ' stop');
3637 print "\n";
3638 last;
3639 }
3640 }
3641 # Remove the files
3642 foreach $File (keys %gDBFile) {
3643 if ($File !~ /\/tmp\S+/) {
3644 uninstall_file($File);
3645 }
3646 }
3647 # Remove the links
3648 foreach $LinkedFile (keys %gDBLink) {
3649 unlink $LinkedFile;
3650 }
3651 # At last, replace the original files.
3652 foreach $MovedFile (keys %gDBMove) {
3653 # XXX we do not have a timestamp for those files so we can't
3654 # know if the user changed it, so I back it up.
3655 if (-e $gDBMove{$MovedFile}) {
3656 backup_file($gDBMove{$MovedFile});
3657 unlink $gDBMove{$MovedFile};
3658 }
3659 if (-e $MovedFile) {
3660 if ($MovedFile =~ /\S+\.org/) {
3661 rename $MovedFile, $gDBMove{$MovedFile};
3662 } elsif ($gDBMove{$MovedFile} =~ /\.new$/) {
3663 # Nothing to do for /etc/rc and /etc/rc.shutdown
3664 } else {
3665 backup_file($MovedFile);
3666 unlink $MovedFile;
3667 }
3668 }
3669 }
3670
3671 # Clean up the broken links.
3672 foreach $File (qw(/etc/modules.conf /etc/conf.modules /etc/XF86Config
3673 /etc/X11/XF86Config /etc/X11/XF86Config-4)) {
3674 if ((-l $File) && (-e ($File . '.org'))) {
3675 unlink $File;
3676 rename $File . '.org', $File;
3677 }
3678 }
3679
3680 get_initscriptsdir();
3681 $Files[0] = db_get_answer('INITSCRIPTSDIR') . '/vmmemctl';
3682 foreach $runlevel ('0', '1', '2', '3', '4', '5', '6', 'S', 's') {
3683 push @Files, db_get_answer('INITDIR') . '/rc' . $runlevel
3684 . '.d/S99vmmemctl';
3685 }
3686 # Cleanup the files that aren't mentionned in the install database.
3687 foreach $File (@Files) {
3688 if (file_name_exist($File)) {
3689 unlink $File;
3690 }
3691 }
3692
3693 db_save();
3694 unlink $gInstallerMainDB;
3695
3696 if (direct_command('LANG=C ' .
3697 shell_string(vmware_product() eq 'tools-for-freebsd' ?
3698 $gHelper{'kldstat'} : $gHelper{'lsmod'})) =~
3699 /vmmemctl/) {
3700 print wrap('The uninstallation of legacy tools completed. '
3701 . 'Please restart this virtual machine to ensure that '
3702 . 'all the loaded components are removed from the memory and '
3703 . 'run this installer again to continue with the upgrade.'
3704 . "\n\n", 0);
3705 exit 0;
3706 }
3707 # Restore the original database file name in case we don't have
3708 # to reboot because of the loaded vmmemctl.
3709 $gInstallerMainDB = $TmpMainDB;
3710}
3711
3712#BEGIN UNINSTALLER SECTION
3713# Uninstaller section for old style MUI installer: Most of this code is
3714# directly copied over from the old installer
3715my %gConfData;
3716
3717# END UNINSTALLER SECTION
3718# Install the content of the tar package
3719sub install_content {
3720 my $rootdir;
3721 my $answer;
3722 my %patch;
3723 my $mandir;
3724 my $docdir;
3725 my $initdir;
3726 my $libdir;
3727 my $initscriptsdir;
3728
3729 undef %patch;
3730 install_dir('./etc', $gRegistryDir, \%patch, 0x1);
3731
3732 $rootdir = '/usr';
3733
3734 my $redo = 1;
3735 while ($redo) {
3736 $answer = spacechk_answer('In which directory do you want '
3737 . 'to install the binary files?', 'dirpath',
3738 $rootdir . '/bin', './bin', 'BINDIR');
3739 undef %patch;
3740 $redo=install_dir('./bin', $answer, \%patch, 0x1, 1);
3741 }
3742
3743 get_initscriptsdir();
3744 $initscriptsdir = db_get_answer('INITSCRIPTSDIR');
3745
3746 #
3747 # Install the startup script (and make the old installer aware of this one)
3748 #
3749 undef %patch;
3750 install_file($cStartupFileName, $initscriptsdir . '/vmware', \%patch, 0x1);
3751
3752 $gIsUninstallerInstalled = 1;
3753
3754 # Setuid root
3755 safe_chmod(04555, $answer . '/vmware-ping');
3756
3757 $rootdir = internal_dirname($answer);
3758 # Don't display a double slash (was bug 14109)
3759 if ($rootdir eq '/') {
3760 $rootdir = '';
3761 }
3762
3763 # We don't use get_persistent_answer() here because once the user has
3764 # selected the root directory, we can give him better default answers than
3765 # his/her previous answers. Even though this is asking for a directory,
3766 # the actual source of the files is within the source ./lib so the
3767 # spacechk_answer() below handles it.
3768 if (vmware_product() eq 'ws') {
3769 $redo=1;
3770 while($redo) {
3771 $answer = get_answer('In which directory do you want to install '
3772 . 'the daemon files?', 'dirpath', $rootdir . '/sbin');
3773 db_add_answer('SBINDIR', $answer);
3774 undef %patch;
3775 $redo=install_dir('./sbin', $answer, \%patch, 0x1, 1);
3776 }
3777 # Setuid root
3778 safe_chmod(04555, $answer . '/vmware-authd');
3779 }
3780
3781 $redo=1;
3782 while ($redo) {
3783 $answer = spacechk_answer('In which directory do you want to install '
3784 . 'the library files?', 'dirpath',
3785 $rootdir . '/lib/vmware', './lib');
3786 db_add_answer('LIBDIR', $answer);
3787 $libdir = $answer;
3788 undef %patch;
3789 $redo=install_dir('./lib', $answer, \%patch, 0x1, 1);
3790 }
3791 # Setuid root
3792 safe_chmod(04555, $answer . '/bin/vmware-vmx');
3793 safe_chmod(04555, $answer . '/bin/vmware-vmx-debug');
3794 safe_chmod(04555, $answer . '/bin/vmware-vmx-stats');
3795
3796 # If the product has man pages ask for the man pages location. */
3797 if (-d './man') {
3798 $mandir = $rootdir . '/share/man';
3799 if (not (-d $mandir)) {
3800 $mandir = $rootdir . '/man';
3801 }
3802 $answer = spacechk_answer('In which directory do you want to install '
3803 . 'the manual files?', 'dirpath',
3804 $mandir, './man');
3805 db_add_answer('MANDIR', $answer);
3806 undef %patch;
3807 install_dir('./man', $answer, \%patch, 0x1);
3808 }
3809
3810 $docdir = $rootdir . '/share/doc';
3811 if (not (-d $docdir)) {
3812 $docdir = $rootdir . '/doc';
3813 }
3814 $answer = spacechk_answer('In which directory do you want to install '
3815 . 'the documentation files?', 'dirpath',
3816 $docdir . '/vmware', './doc');
3817 db_add_answer('DOCDIR', $answer);
3818 undef %patch;
3819 install_dir('./doc', $answer, \%patch, 0x1);
3820 install_symlink(db_get_answer('DOCDIR') . '/EULA',
3821 $libdir . '/share/EULA.txt');
3822
3823 # Don't forget the vix perl tar ball..
3824 if (-d 'vmware-vix/api' ) {
3825 undef %patch;
3826 # Create the parent directory separately so install_dir() can be called on the
3827 # specific subdir rather than any and all subdirs when passing just 'vmware-vix'.
3828 db_add_dir($libdir . '/vmware-vix');
3829 install_dir( './vmware-vix/api', $libdir . '/vmware-vix/api', \%patch, 0x1);
3830 }
3831
3832 find_vix_tar();
3833
3834 if (vmware_product() eq 'ws') {
3835 install_content_player();
3836 }
3837
3838 if (vmware_product() eq 'ws') {
3839 configure_vnetlib();
3840 }
3841}
3842
3843sub install_content_player {
3844 my %patch;
3845 install_dir('./system_etc', '/etc', \%patch, 1);
3846 undef %patch;
3847 install_dir('./usr', '/usr', \%patch, 1);
3848}
3849
3850sub get_initscriptsdir {
3851 my $initdir;
3852 my $initscriptsdir;
3853 my $answer;
3854
3855 if (vmware_product() eq 'tools-for-freebsd') {
3856 $initdir = '/usr/local/etc/rc.d';
3857 $initscriptsdir = '/usr/local/etc/rc.d';
3858 db_add_answer('INITDIR', $initdir);
3859 db_add_answer('INITSCRIPTSDIR', $initscriptsdir);
3860 return $initscriptsdir;
3861 }
3862
3863 # The "SuSE version >= 7.1" way
3864 $initdir = '/etc/init.d';
3865 if (check_answer_initdirpath($initdir, 'default') eq '') {
3866 # The "SuSE version < 7.1" way
3867 $initdir = '/sbin/init.d';
3868 if (check_answer_initdirpath($initdir, 'default') eq '') {
3869 # The "RedHat" way
3870 $initdir = '/etc/rc.d';
3871 if (check_answer_initdirpath($initdir, 'default') eq '') {
3872 # The "Debian" way
3873 $initdir = '/etc';
3874 if (check_answer_initdirpath($initdir, 'default') eq '') {
3875 $initdir = '';
3876 }
3877 }
3878 }
3879 }
3880 $answer = get_persistent_answer('What is the directory that contains the init'
3881 .' directories (rc0.d/ to rc6.d/)?'
3882 , 'INITDIR', 'initdirpath', $initdir);
3883
3884 # The usual way
3885 $initscriptsdir = $answer . '/init.d';
3886 if ( $answer =~ m/init.d/ ) {
3887 # if the string contains init.d, do not default to containing init.d,
3888 # instead just default to the initdir as the initscripstdir
3889 $initscriptsdir = $answer;
3890 }
3891
3892 if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
3893 # The "SuSE version >= 7.1" way
3894 $initscriptsdir = $answer;
3895 if (check_answer_initscriptsdirpath($initscriptsdir, 'default') eq '') {
3896 $initscriptsdir = '';
3897 }
3898 }
3899 $answer = get_persistent_answer('What is the directory that contains the init'
3900 .' scripts?', 'INITSCRIPTSDIR'
3901 , 'initscriptsdirpath', $initscriptsdir);
3902 return $answer;
3903}
3904
3905# Install a tar package or upgrade an already installed tar package
3906sub install_or_upgrade {
3907 print wrap('Installing ' . vmware_product_name() . ".\n\n", 0);
3908
3909 if (vmware_product() eq 'api') {
3910 install_perl_api();
3911 } elsif (vmware_product() eq 'tools-for-linux' ||
3912 vmware_product() eq 'tools-for-freebsd' ||
3913 vmware_product() eq 'tools-for-solaris') {
3914 install_content_tools();
3915 } elsif (vmware_product() eq 'vix') {
3916 install_content_vix();
3917 } elsif (vmware_product() eq 'vix-disklib') {
3918 install_content_vix_disklib();
3919 } elsif (vmware_product() eq 'nvdk') {
3920 install_content_nvdk();
3921 } else {
3922 install_content();
3923 }
3924
3925 print wrap('The installation of ' . vmware_longname()
3926 . ' completed successfully. '
3927 . 'You can decide to remove this software from your system at any '
3928 . 'time by invoking the following command: "'
3929 . db_get_answer('BINDIR') . '/' . $gUninstallerFileName . '".'
3930 . "\n\n", 0);
3931
3932}
3933
3934# Uninstall files and directories beginning with a given prefix
3935sub uninstall_prefix {
3936 my $prefix = shift;
3937 my $prefix_len;
3938 my $file;
3939 my $dir;
3940
3941 $prefix_len = length($prefix);
3942
3943 # Remove all files beginning with $prefix
3944 foreach $file (keys %gDBFile) {
3945 if (substr($file, 0, $prefix_len) eq $prefix) {
3946 uninstall_file($file);
3947 }
3948 }
3949
3950 # Remove all directories beginning with $prefix
3951 # We sort them by decreasing order of their length, to ensure that we will
3952 # remove the inner ones before the outer ones
3953 foreach $dir (sort {length($b) <=> length($a)} keys %gDBDir) {
3954 if (substr($dir, 0, $prefix_len) eq $prefix) {
3955 uninstall_dir($dir, '0');
3956 }
3957 }
3958}
3959
3960# Uninstall a tar package
3961sub uninstall {
3962 my $service_name = shift;
3963 my @services;
3964
3965 if (vmware_product() eq 'tools-for-linux') {
3966 @services = ('/vmware-tools');
3967 if ($have_thinprint eq 'yes') {
3968 push (@services, '/vmware-tools-thinprint');
3969 }
3970 } elsif (vmware_product() eq 'tools-for-freebsd') {
3971 @services = ('/vmware-tools.sh');
3972 } else {
3973 @services = ($service_name);
3974 }
3975
3976 # New school Upstart support for Linux Tools.
3977 if (vmware_product() eq 'tools-for-linux' and
3978 db_get_answer_if_exists('UPSTARTJOB')) {
3979
3980 foreach my $service (@services) {
3981 my $service = (substr($service, 0, 1) eq '/')
3982 ? substr($service, 1) : $service;
3983 print wrap('Stopping services for ' . $service . "\n\n", 0);
3984 vmware_service_issue_command1($cServiceCommandSystem, $service, 'stop');
3985 }
3986
3987 # Legacy SYSV/rc support for all products.
3988 } elsif (defined($gDBAnswer{'INITSCRIPTSDIR'})
3989 && db_file_in(db_get_answer('INITSCRIPTSDIR') . $service_name)) {
3990
3991 if (isDesktopProduct()) {
3992 # Check that there are no VMs active else the server will fail to stop.
3993 print wrap("Checking for active VMs:\n", 0);
3994 if (system(shell_string(db_get_answer('INITSCRIPTSDIR') . '/vmware') .
3995 ' status vmcount > /dev/null 2>&1') >> 8 == 2) {
3996 my $msg = vmware_product_name() . ' cannot quiesce. Please '
3997 . 'suspend or power off each VM.' . "\n\n";
3998 error($msg);
3999 }
4000 print wrap("There are no Active VMs.\n", 0);
4001 }
4002
4003 print wrap('Stopping services for ' . vmware_product_name() . "\n\n", 0);
4004
4005 foreach my $service (@services) {
4006
4007 # The installation process ran far enough to create the startup script
4008 my $status;
4009 # Stop the services
4010 $status = system(shell_string(db_get_answer('INITSCRIPTSDIR')
4011 . $service) . ' stop') >> 8;
4012 if ($status) {
4013 if ($status == 2) {
4014 # At least one instance of VMware is still running. We must refuse to
4015 # uninstall
4016 error('Unable to stop ' . vmware_product_name()
4017 . '\'s services. Aborting the uninstallation.' . "\n\n");
4018 }
4019
4020 # Oh well, at worst the user will have to reboot the machine... The
4021 # uninstallation process should now go as far as possible
4022 print STDERR wrap('Unable to stop ' . vmware_product_name()
4023 . '\'s services.' . "\n\n", 0);
4024 } else {
4025 print "\n";
4026 }
4027
4028 my $init_style = db_get_answer_if_exists('INIT_STYLE');
4029
4030 # In case service links were created the LSB way, remove them
4031 my $unlinked = 0;
4032 if ("$init_style" eq 'lsb') {
4033 if ($gHelper{'insserv'} ne '') {
4034 if (0 == system(shell_string($gHelper{'insserv'}) . ' -r '
4035 . shell_string(db_get_answer('INITSCRIPTSDIR') . $service)
4036 . ' >/dev/null 2>&1')) {
4037 $unlinked = 1;
4038 }
4039 else {
4040 print wrap("WARNING: The installer initially used the " .
4041 "insserv application to setup the vmware-tools service. " .
4042 "That application did not run successfully. " .
4043 "Please re-install the insserv application or check your settings. " .
4044 "This script will now attempt to manually remove the " .
4045 "vmware-tools service.\n\n", 0);
4046 }
4047 }
4048 }
4049
4050 # Use chkconfig
4051 if (($unlinked == 0) and ($gHelper{'chkconfig'} ne '')) {
4052 # We need to trim the leading '/' off of the service name.
4053 my $trim_service_name = (substr($service, 0, 1) eq '/')
4054 ? substr($service, 1) : $service;
4055 if (0 == system(shell_string($gHelper{'chkconfig'}) . ' --del ' . $trim_service_name)) {
4056 $unlinked = 1;
4057 }
4058 else {
4059 print wrap("WARNING: The installer initially used the " .
4060 "chkconfig application to setup the vmware-tools service. " .
4061 "That application did not run successfully. " .
4062 "Please re-install the chkconfig application or check your settings. " .
4063 "This script will now attempt to manually remove the " .
4064 "vmware-tools service.\n\n", 0);
4065 }
4066 }
4067
4068 # Use update-rc.d
4069 if (($unlinked == 0) and ($gHelper{'update-rc.d'} ne '')) {
4070 # We need to trim the leading '/' off of the service name.
4071 my $trim_service_name = (substr($service, 0, 1) eq '/')
4072 ? substr($service, 1) : $service;
4073 if (0 == system(shell_string($gHelper{'update-rc.d'}) . ' -f ' . $trim_service_name .
4074 ' remove')) {
4075 $unlinked = 1;
4076 }
4077 else {
4078 print wrap("WARNING: The installer initially used the " .
4079 "update-rc.d application to setup the vmware-tools service. " .
4080 "That application did not run successfully. " .
4081 "Please re-install the update-rc.d application or check your settings. " .
4082 "This script will now attempt to manually remove the " .
4083 "vmware-tools service.\n\n", 0);
4084 }
4085 }
4086
4087 # If neither of the above worked, the links will be removed automatically
4088 # by the installer.
4089 }
4090 }
4091
4092 # Check to see if this uninstall is part of an upgrade. When an upgrade occurs,
4093 # an install ontop of a current product, the uninstall part is called with the
4094 # upgrade option set to 1.
4095 if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
4096 if (vmware_product() eq 'ws') {
4097 uninstall_vix();
4098 }
4099
4100 if (vmware_product() eq 'ws') {
4101 deconfigure_vnetlib();
4102 }
4103
4104 if (vmware_product() eq 'tools-for-linux') {
4105 if (!$open_vm_compat) {
4106 system('/etc/vmware-caf/pme/install/preuninstall.sh');
4107 uninstall_content_caf();
4108 }
4109 }
4110
4111 }
4112 else {
4113 if (vmware_product() eq 'tools-for-linux') {
4114 if (!$open_vm_compat) {
4115 system('/etc/vmware-caf/pme/install/preupgrade.sh');
4116 }
4117 }
4118 }
4119
4120 my $eclipse_dir = db_get_answer_if_exists('ECLIPSEDIR');
4121 if (defined $eclipse_dir) {
4122 system($gHelper{'rm'} . ' -rf ' . $eclipse_dir . '/../configuration/com.vmware.bfg*');
4123 }
4124
4125 # Let the VMX know that we're uninstalling the Tools. We need to
4126 # do this before we remove the files, because we use guestd to
4127 # send the RPC. But we'd like to do it as late as possible in the
4128 # uninstall process so that we won't accidentally tell the VMX that the
4129 # Tools are gone when they're still there.
4130 if (!$open_vm_compat) {
4131 if (vmware_product() eq 'tools-for-linux' ||
4132 vmware_product() eq 'tools-for-freebsd' ||
4133 vmware_product() eq 'tools-for-solaris') {
4134 send_rpc('tools.set.version 0');
4135 }
4136 }
4137 if ($open_vm_compat == 0 && $have_grabbitmqproxy eq 'yes') {
4138 uninstall_content_guestproxy();
4139 }
4140 uninstall_prefix('');
4141}
4142
4143# Configure vnetlib
4144sub configure_vnetlib() {
4145 my $vnetlib = shell_string("$gDBAnswer{'BINDIR'}/vmware-networks");
4146 my $vers;
4147 my $ret;
4148
4149 db_add_answer('NETWORKING', 'yes');
4150
4151 # pre-vnetlib upgrade
4152 if (!db_get_answer_if_exists('VNETLIB_CONFED') && $gOption{'ws-upgrade'}) {
4153 print wrap("Migrating network settings... ", 0);
4154 if (system("$vnetlib --migrate-network-settings $gInstallerMainDB") == 0) {
4155 db_add_answer('VNETLIB_CONFED', 'yes');
4156 return 1;
4157 } else {
4158 $vers = 0;
4159 }
4160 } elsif (db_get_answer_if_exists('VNETLIB_CONFED')) { # post-vnetlib upgrade
4161 $vers = 1;
4162 } else { # new install
4163 $vers = 0;
4164 }
4165
4166 if ($vers == 0) {
4167 print wrap("Configuring default networks...\n\n", 0);
4168 } elsif ($vers == 1) {
4169 print wrap("Restoring network settings...\n\n", 0);
4170 }
4171
4172 my $cmd = sprintf("%s --postinstall %s,%s,1 > /dev/null", $vnetlib, vmware_product(), $vers);
4173 $ret = system($cmd);
4174
4175 if ($ret == 0) {
4176 db_add_answer('VNETLIB_CONFED', 'yes');
4177 }
4178
4179 return $ret == 0;
4180}
4181
4182# Cleanup after vnetlib
4183sub deconfigure_vnetlib() {
4184 foreach my $path ("$gRegistryDir/networking.*", "$gRegistryDir/vmnet*",
4185 "/var/run/vmnat.*", "/var/log/vnetlib", "$gRegistryDir/networking",
4186 "/var/run/vmnet-*") {
4187 system(shell_string($gHelper{'rm'}) . " -rf $path");
4188 }
4189}
4190
4191
4192sub install_content_vix_disklib {
4193 my $rootdir;
4194 my $bindir;
4195 my $answer;
4196 my %patch;
4197 my $docdir;
4198 my $libdir;
4199 my $suffix = is64BitUserLand() ? '64' : '32';
4200
4201 my $old_default = $gOption{'default'};
4202 $gOption{'default'} = 0;
4203 show_EULA();
4204 $gOption{'default'} = $old_default;
4205
4206 undef %patch;
4207
4208 install_dir('./etc', $gRegistryDir, \%patch, 0x1);
4209
4210 $rootdir = get_persistent_answer("What prefix do you want to use to install " .
4211 vmware_product_name() . "?\n\n" . 'The prefix is the root directory where the other
4212 folders such as man, bin, doc, lib, etc. will be placed.', 'PREFIX', 'dirpath',
4213 '/usr');
4214
4215 # Don't display a double slash (was bug 14109)
4216 if ($rootdir eq '/') {
4217 $rootdir = '';
4218 }
4219
4220 undef %patch;
4221 $bindir = "$rootdir/lib/vmware-vix-disklib/bin";
4222 install_dir('./bin64', $bindir . '64', \%patch, 0x1);
4223 create_dir("$rootdir/bin", 1);
4224 install_symlink("$bindir$suffix/vmware-vdiskmanager", "$rootdir/bin/vmware-vdiskmanager");
4225 install_symlink("$bindir$suffix/vmware-uninstall-vix-disklib.pl",
4226 "$rootdir/bin/vmware-uninstall-vix-disklib.pl");
4227 db_add_answer('BINDIR', "$rootdir/bin");
4228
4229 $gIsUninstallerInstalled = 1;
4230
4231 $libdir = "$rootdir/lib/vmware-vix-disklib/lib";
4232 undef %patch;
4233 install_dir('./lib64', $libdir . '64', \%patch, 0x1);
4234
4235 foreach my $arch (qw(64)) {
4236 install_symlink("$libdir$arch/libssl.so.0.9.8", "$bindir$arch/libssl.so.0.9.8");
4237 install_symlink("$libdir$arch/libcrypto.so.0.9.8", "$bindir$arch/libcrypto.so.0.9.8");
4238 }
4239 db_add_answer('VIXDISKLIBDIR', $libdir);
4240 db_add_answer('LIBDIR', $libdir);
4241
4242 undef %patch;
4243 install_dir('./include', "$rootdir/lib/vmware-vix-disklib/include", \%patch, 0x1);
4244
4245 my $pkgdir = "$rootdir/lib/pkgconfig";
4246 create_dir($pkgdir, 1);
4247 foreach my $arch (qw(64)) {
4248 my $pcfile = "$pkgdir/vix-disklib-$arch.pc";
4249 if (open(PKGCONFIG, '>' . $pcfile)) {
4250 db_add_file($pcfile, 0);
4251 print PKGCONFIG "prefix=$rootdir/lib/vmware-vix-disklib\n";
4252 print PKGCONFIG "exec_prefix=\${prefix}\n";
4253 print PKGCONFIG "libdir=\${exec_prefix}/lib$arch\n";
4254 print PKGCONFIG "includedir=\${prefix}/include\n";
4255 print PKGCONFIG "Name: vix-disklib\n";
4256 print PKGCONFIG "Description: VMware VIX DiskLib\n";
4257 print PKGCONFIG "Version: " . vmware_version() . "\n";
4258 print PKGCONFIG "Libs: -L\${libdir} -lvixDiskLib\n";
4259 print PKGCONFIG "Cflags: -I\${includedir}\n";
4260 close PKGCONFIG;
4261 }
4262 }
4263
4264 # Runtime
4265 install_symlink("vmware-vix-disklib/lib$suffix/libvixDiskLib.so.5",
4266 "$rootdir/lib/libvixDiskLib.so.5");
4267 # Devel only
4268 install_symlink("vix-disklib-$suffix.pc", "$pkgdir/vix-disklib.pc");
4269 install_symlink("libvixDiskLib.so.5",
4270 "$rootdir/lib/libvixDiskLib.so");
4271
4272 $docdir = $rootdir . '/share/doc/vmware-vix-disklib';
4273 install_dir('./doc', $docdir, \%patch, 0x1);
4274
4275 return 1;
4276}
4277
4278sub install_content_nvdk {
4279 my $rootdir;
4280 my $bindir;
4281 my $answer;
4282 my %patch;
4283 my $docdir;
4284 my $suffix = is64BitUserLand() ? '64' : '32';
4285
4286 my $old_default = $gOption{'default'};
4287 $gOption{'default'} = 0;
4288 show_EULA();
4289 $gOption{'default'} = $old_default;
4290
4291 undef %patch;
4292
4293 install_dir('./etc', $gRegistryDir, \%patch, 0x1);
4294
4295 $rootdir = get_persistent_answer("What prefix do you want to use to install " .
4296 vmware_product_name() . "?\n\n" . 'The prefix is the root directory where the other
4297 folders such as man, bin, doc, lib, etc. will be placed.', 'PREFIX', 'dirpath',
4298 '/usr');
4299
4300 # Don't display a double slash
4301 if ($rootdir eq '/') {
4302 $rootdir = '';
4303 }
4304
4305 undef %patch;
4306 $bindir = "$rootdir/lib/nvdk/bin";
4307 install_dir('./bin', $bindir, \%patch, 0x1);
4308 create_dir("$rootdir/bin", 1);
4309 install_symlink("$bindir/vmware-uninstall-nvdk.pl",
4310 "$rootdir/bin/vmware-uninstall-nvdk.pl");
4311 db_add_answer('BINDIR', "$rootdir/bin");
4312
4313 $gIsUninstallerInstalled = 1;
4314
4315 undef %patch;
4316 install_dir('./include', "$rootdir/lib/nvdk/include", \%patch, 0x1);
4317
4318 my $pkgdir = "$rootdir/lib/pkgconfig";
4319 create_dir($pkgdir, 1);
4320 my $pcfile = "$pkgdir/nvdk.pc";
4321 if (open(PKGCONFIG, '>' . $pcfile)) {
4322 db_add_file($pcfile, 0);
4323 print PKGCONFIG "prefix=$rootdir/lib/nvdk\n";
4324 print PKGCONFIG "includedir=\${prefix}/include\n";
4325 print PKGCONFIG "Name: nvdk\n";
4326 print PKGCONFIG "Description: VMware NAS VAAI Development Kit\n";
4327 print PKGCONFIG "Version: " . vmware_version() . "\n";
4328 print PKGCONFIG "Cflags: -I\${includedir}\n";
4329 close PKGCONFIG;
4330 }
4331
4332 $docdir = $rootdir . '/share/doc/nvdk';
4333 install_dir('./doc', $docdir, \%patch, 0x1);
4334
4335 return 1;
4336}
4337
4338# Ask the user for file locations for libs, bins, etc. Check
4339# to see if this build is an official one or not, and show the
4340# EULA if it's not an official build.
4341sub install_content_vix {
4342 my $rootdir;
4343 my $answer;
4344 my %patch;
4345 my $mandir;
4346 my $docdir;
4347 my $initdir;
4348 my $initscriptsdir;
4349 my $libdir;
4350
4351 undef %patch;
4352 install_dir('./etc', $gRegistryDir, \%patch, 0x1);
4353
4354 if ('3595377' != 0) {
4355 # suspend any '--default' option to force user interaction here. The user
4356 # must answer the EULA question before continuing.
4357 my $tmp = $gOption{'default'};
4358 $gOption{'default'} = 0;
4359 show_EULA();
4360 $gOption{'default'} = $tmp;
4361 }
4362
4363 if (db_get_answer_if_exists('NESTED') &&
4364 db_get_answer('NESTED') eq 'yes' &&
4365 $gOption{'default'} == 1) {
4366 db_add_answer('TERSE', 'yes');
4367 }
4368
4369 # If workstation is already installed and VIX has not already defined
4370 # it's own BINDIR, then base the default root on the workstation BINDIR.
4371 if (!defined(db_get_answer_if_exists('BINDIR'))) {
4372 my $newbin;
4373 if (-f $cInstallerMainDB) {
4374 $newbin = alt_db_get_answer($cInstallerMainDB, 'BINDIR');
4375 if (defined($newbin)) {
4376 db_add_answer('BINDIR', $newbin);
4377 }
4378 }
4379 }
4380
4381 $rootdir = '/usr';
4382 $answer = $gOption{'prefix'} || spacechk_answer('In which directory do you want '
4383 . 'to install the ' . vmware_product_name()
4384 . ' binary files?', 'dirpath',
4385 $rootdir . '/bin', './bin', 'BINDIR');
4386
4387 # Make sure stuff is installed in a 'bin' dir.
4388 my $basename = internal_basename($answer);
4389 if ($basename ne 'bin') {
4390 $answer = $answer . '/bin';
4391 }
4392
4393 db_add_answer('BINDIR', $answer);
4394 undef %patch;
4395 install_dir('./bin', $answer, \%patch, 0x1);
4396 # We might be in a 'NESTED' install and workstation would have already
4397 # installed vmrun. No reason to check for 'NESTED' really. If we're
4398 # installed standalone, then the uninstall would remove vmrun. If not,
4399 # then vmrun will already exist.
4400 if (! file_name_exist($answer . '/vmrun')) {
4401 my %patch;
4402 install_file('./vmware-vix/bin/vmrun', $answer . '/vmrun', \%patch, 0x1);
4403 }
4404
4405 $rootdir = internal_dirname($answer);
4406 # Don't display a double slash (was bug 14109)
4407 if ($rootdir eq '/') {
4408 $rootdir = '';
4409 }
4410 $gIsUninstallerInstalled = 1;
4411
4412 $libdir = 'vmware-vix/lib';
4413 $answer = spacechk_answer('In which directory do you want '
4414 . 'to install the ' . vmware_product_name()
4415 . ' library files?', 'dirpath',
4416 $rootdir . '/lib/'. $libdir, 'vmware-vix/lib' );
4417
4418 db_add_answer('VIXLIBDIR', $answer);
4419 db_add_answer('LIBDIR', $answer);
4420
4421 undef %patch;
4422 install_dir($libdir, $answer, \%patch, 0x1);
4423 my $globallibdir = is64BitUserLand() ? '/lib64' : '/lib32';
4424 my $shared_object = 'libvixAllProducts.so';
4425
4426 if ((! -d $globallibdir) && (! -d '/usr' . $globallibdir)) {
4427 install_symlink($answer . '/' . $shared_object, '/lib/' . $shared_object);
4428 } else {
4429 if (-d $globallibdir) {
4430 install_symlink($answer . '/' . $shared_object,
4431 $globallibdir . '/' . $shared_object);
4432 }
4433 if (-d '/usr' . $globallibdir) {
4434 install_symlink($answer . '/' . $shared_object,
4435 '/usr' . $globallibdir . '/' . $shared_object);
4436 }
4437 }
4438
4439 # If the product has man pages ask for the man pages location. */
4440 if (-d './man') {
4441 $mandir = $rootdir . '/share/man';
4442 if (not (-d $mandir)) {
4443 $mandir = $rootdir . '/man';
4444 }
4445 $answer = spacechk_answer('In which directory do you want '
4446 . 'to install the ' . vmware_product_name()
4447 . ' man pages?', 'dirpath',
4448 $rootdir . '/man', 'vmware-vix/man');
4449 db_add_answer('MANDIR', $answer);
4450 undef %patch;
4451 install_dir('vmware-vix/man', $answer, \%patch, 0x1);
4452 }
4453
4454 $docdir = $rootdir . '/share/doc';
4455 if (not (-d $docdir)) {
4456 $docdir = $rootdir . '/doc';
4457 }
4458 $answer = spacechk_answer('In which directory do you want '
4459 . 'to install the ' . vmware_product_name()
4460 . ' document pages?', 'dirpath',
4461 $docdir . '/vmware-vix', 'doc');
4462
4463 undef %patch;
4464 install_dir('./doc', $answer, \%patch, 0x1);
4465 db_add_answer('DOCDIR', $answer);
4466 undef %patch;
4467 install_dir('vmware-vix/include', $rootdir . '/include', \%patch, 0x1);
4468 undef %patch;
4469 install_dir('vmware-vix/api', db_get_answer('VIXLIBDIR') . '/api', \%patch, 0x1);
4470
4471 # tell the Vix world where to find the libs, putting the VIXLIBDIR value
4472 # into /etc/vmware/config.
4473 finalize_vix_install();
4474
4475 # Make sure the verbose meter is turned up.
4476 db_remove_answer('TERSE');
4477
4478 return 1;
4479}
4480
4481# Add the variable, vix.libdir, to /etc/vmware/config
4482# so the Vix API can figure out where its libraries
4483# are. If this is the standalone version, create config.
4484sub finalize_vix_install {
4485 if (! -d "/etc/vmware") {
4486 create_dir("/etc/vmware", 0x1);
4487 }
4488
4489 my $libdir = db_get_answer_if_exists('VIXLIBDIR');
4490
4491 if (!defined($libdir)) {
4492 error("Unable to look up VIX libdir.\n");
4493 }
4494
4495 $gConfig->set("vix.libdir", $libdir);
4496
4497 if (!$gConfig->writeout($gConfigFile)) {
4498 error("Unable to write VIX libdir to configuration file.\n");
4499 }
4500}
4501
4502# find the vix tar package within the workstation distribution tree and install
4503# it into db_get_answer('LIBDIR')/vmware-vix
4504sub find_vix_tar {
4505 my %patch;
4506 my $vixTarFile = 'vmware-vix/vmware-vix.tar.gz';
4507 my $vixInstalledTarFile = db_get_answer('LIBDIR') . '/' . $vixTarFile;
4508
4509 # If this is a workstation tar install there will be a vix tarball:
4510 # vmware-distrib/vmware-vix/vmware-vix.tar.gz. "Install" it into
4511 # its final spot in the tree. If this is an rpm install, the tarball
4512 # will already be in its final location. This is where the vmware-config
4513 # script will look for the tar file.
4514 if (-e $vixTarFile) {
4515 undef %patch;
4516 install_file($vixTarFile, $vixInstalledTarFile, \%patch, 0x1);
4517 return 1;
4518 }
4519 return 0;
4520}
4521
4522# Remove the text we added to the core config file in
4523# /etc/vmware/config. Call uninstall on the whole tree.
4524sub uninstall_vix {
4525 my @statbuf;
4526
4527 # If this is not the Vix product in here, then the only thing to do is to launch
4528 # the Vix uninstaller. When Vix comes through here, skipping this if, all of
4529 # the normal uninstall pieces occurr.
4530 if (vmware_product() ne 'vix') {
4531 my $where = alt_db_get_answer('/etc/vmware-vix/locations', 'BINDIR');
4532 if ($where) {
4533 $where .= '/vmware-uninstall-vix.pl';
4534 if (-f $where) {
4535 system(shell_string($where));
4536 }
4537 }
4538 return;
4539 }
4540
4541 $gConfig->remove('vix.libdir');
4542 if (!$gConfig->writeout($gConfigFile)) {
4543 error("Unable to write VIX libdir to configuration file.\n");
4544 }
4545
4546 # If we just removed the last bits from the file, statbuf[7] == size in bytes,
4547 # then remove the file so it won't get left behind in an uninstall.
4548 @statbuf = stat($gConfigFile);
4549 if ( !$statbuf[7]) {
4550 unlink ($gConfigFile);
4551 }
4552
4553 uninstall_prefix('');
4554
4555 # check to see if $gRegistryDir is still around. If it has no files,
4556 # remove it.
4557 if (-d $gRegistryDir) {
4558 if (!direct_command('find ' . $gRegistryDir . ' -type f -o -type l')) {
4559 rmdir($gRegistryDir);
4560 }
4561 }
4562
4563}
4564
4565# Return the specific VMware product
4566sub vmware_product {
4567 return 'tools-for-linux';
4568}
4569
4570# this is a function instead of a macro in the off chance that product_name
4571# will one day contain a language-specific escape character.
4572sub vmware_product_name {
4573 return 'VMware Tools';
4574}
4575
4576# This function returns i386 under most circumstances, returning x86_64 when
4577# the product is Workstation and is the 64bit version at that.
4578sub vmware_product_architecture {
4579 return '@@PRODUCT_ARCHITECTURE@@';
4580}
4581
4582# Return product name and version
4583sub vmware_longname {
4584 my $name = vmware_product_name() . ' ' . vmware_version();
4585
4586 if (not (vmware_product() eq 'server')) {
4587 if (vmware_product() eq 'tools-for-solaris') {
4588 $name .= ' for Solaris';
4589 } elsif (vmware_product() eq 'tools-for-freebsd') {
4590 $name .= ' for FreeBSD';
4591 } else {
4592 $name .= ' for Linux';
4593 }
4594 }
4595
4596 return $name;
4597}
4598
4599# Display a usage error message for the install program and exit
4600sub install_usage {
4601 print STDERR wrap(vmware_longname() . ' installer' . "\n" . 'Usage: ' . $0 . "\n"
4602 . ' [[-][-]d[efault]]' . "\n"
4603 . ' default: Automatically answer questions with the '
4604 . 'proposed answer.'
4605 . "\n"
4606 . ' [[-][-]f[orce-install]]' . "\n"
4607 . ' force-install: install even if open-vm-tools are available '
4608 . 'for this distribution.'
4609 . "\n"
4610 . ' [[-][-]prefix=<path to install product: bin, lib, doc>]' . "\n"
4611 . ' Put the installation at <path> instead of the default '
4612 . "location. This implies '--default'."
4613 . "\n"
4614 . ' [[-][-]r[egenerate-cert]]' . "\n"
4615 . ' Force to regenerate server key/cert files if they already exist.'
4616 . "\n"
4617 . ' --clobber-kernel-modules=<module1,module2,...>' . "\n"
4618 . ' Forcefully removes any VMware related modules '
4619 . 'installed by any other installer and installs the modules provided '
4620 . 'by this installer. This is a comma seperated list of modules.'
4621 . "\n\n", 0);
4622 exit 1;
4623}
4624
4625# Remove a temporary directory
4626sub remove_tmp_dir {
4627 my $dir = shift;
4628
4629 if (system(shell_string($gHelper{'rm'}) . ' -rf ' . shell_string($dir))) {
4630 error('Unable to remove the temporary directory ' . $dir . '.' . "\n\n");
4631 };
4632}
4633
4634# ARGH! More code duplication from pkg_mgr.pl
4635# We really need to have some kind of include system
4636sub get_cc {
4637 $gHelper{'gcc'} = '';
4638 if (defined($ENV{'CC'}) && (not ($ENV{'CC'} eq ''))) {
4639 $gHelper{'gcc'} = internal_which($ENV{'CC'});
4640 if ($gHelper{'gcc'} eq '') {
4641 print wrap('Unable to find the compiler specified in the CC environnment variable: "'
4642 . $ENV{'CC'} . '".' . "\n\n", 0);
4643 }
4644 }
4645 if ($gHelper{'gcc'} eq '') {
4646 $gHelper{'gcc'} = internal_which('gcc');
4647 if ($gHelper{'gcc'} eq '') {
4648 $gHelper{'gcc'} = internal_which('egcs');
4649 if ($gHelper{'gcc'} eq '') {
4650 $gHelper{'gcc'} = internal_which('kgcc');
4651 if ($gHelper{'gcc'} eq '') {
4652 $gHelper{'gcc'} = DoesBinaryExist_Prompt('gcc');
4653 }
4654 }
4655 }
4656 }
4657 print wrap('Using compiler "' . $gHelper{'gcc'}
4658 . '". Use environment variable CC to override.' . "\n\n", 0);
4659 return $gHelper{'gcc'};
4660}
4661
4662# These quaddot functions and compute_subnet are from config.pl and are needed
4663# for the tar4|rpm4 upgrade
4664# Converts an quad-dotted IPv4 address into a integer
4665sub quaddot_to_int {
4666 my $quaddot = shift;
4667 my @quaddot_a;
4668 my $int;
4669 my $i;
4670
4671 @quaddot_a = split(/\./, $quaddot);
4672 $int = 0;
4673 for ($i = 0; $i < 4; $i++) {
4674 $int <<= 8;
4675 $int |= $quaddot_a[$i];
4676 }
4677
4678 return $int;
4679}
4680
4681# Converts an integer into a quad-dotted IPv4 address
4682sub int_to_quaddot {
4683 my $int = shift;
4684 my @quaddot_a;
4685 my $i;
4686
4687 for ($i = 3; $i >= 0; $i--) {
4688 $quaddot_a[$i] = $int & 0xFF;
4689 $int >>= 8;
4690 }
4691
4692 return join('.', @quaddot_a);
4693}
4694
4695# Compute the subnet address associated to a couple IP/netmask
4696sub compute_subnet {
4697 my $ip = shift;
4698 my $netmask = shift;
4699
4700 return int_to_quaddot(quaddot_to_int($ip) & quaddot_to_int($netmask));
4701}
4702
4703#
4704# This sub fetches the installed product's binfile and returns it.
4705# It returns '' if there is no product, 'UNKNOWN' if a product but
4706# no known bin.
4707#
4708sub get_installed_product_bin {
4709 my $binfile;
4710
4711 # If there's no database, then there isn't any
4712 # previously installed product.
4713 my $tmp_db = $gInstallerMainDB;
4714
4715 if (not isDesktopProduct()) {
4716 return 'UNKNOWN';
4717 }
4718
4719 # If the installer DB is missing there is no product already installed so
4720 # there is no mismatch.
4721 # If not_configured is found, then install has already run once and has
4722 # uninstalled everything.
4723 if (not -e $gInstallerMainDB || -e $gRegistryDir . '/' . $gConfFlag) {
4724 return '';
4725 }
4726
4727 db_load();
4728 my $bindir = db_get_answer('BINDIR');
4729 if (-f $bindir . "/vmware") {
4730 $binfile = $bindir . "/vmware";
4731 } elsif (-f $bindir . "/vmplayer") {
4732 $binfile = $bindir . "/vmplayer";
4733 } else {
4734 # There is no way to tell what may currently be installed, but something
4735 # is still around if the database is found.
4736 return 'UNKNOWN';
4737 }
4738 return $binfile;
4739}
4740
4741#
4742# Check to see if the product we are installing is the same as the
4743# currently installed product, this is used to tell whether we are in
4744# what would be considered an upgrade situation or a conflict.
4745#
4746# return = 0: There is a match
4747# = 1: There is a mismatch
4748#
4749sub installed_product_mismatch {
4750 my $msg;
4751 my $binfile = get_installed_product_bin();
4752 if ( $binfile eq '' ){
4753 return 0;
4754 }
4755 if ( $binfile eq 'UNKNOWN' ){
4756 return 1;
4757 }
4758 my $product_str = direct_command($binfile . ' -v');
4759 my $product_name = vmware_product_name();
4760 if ($product_str =~ /$product_name/){
4761 return 0;
4762 }
4763
4764 return 1;
4765}
4766
4767#
4768# Given a product version string ala 'VMware Server X.X.X build-000000', break
4769# down the Xs and return a value that shows which string represents a newer
4770# version number, the same version number, or an older version number. X may be
4771# a digit or a letter, as in e.x.p build-000000
4772#
4773sub compare_version_strings {
4774 my $version_str_A = shift;
4775 my $version_str_B = shift;
4776 my $index = 0;
4777
4778 # Match on non-spaces to allow for either numbers or letters. I.E. e.x.p and 1.0.4
4779 $version_str_A =~ s/\D*(\S+.\S+.\S+)\s+build-(\d+)/$1.$2/;
4780 $version_str_B =~ s/\D*(\S+.\S+.\S+)\s+build-(\d+)/$1.$2/;
4781
4782 chomp($version_str_A);
4783 chomp($version_str_B);
4784 my @versions_A = split(/\./, $version_str_A);
4785 my @versions_B = split(/\./, $version_str_B);
4786
4787 while (($index < $#versions_A + 1) && ($versions_A[$index] eq $versions_B[$index])) {
4788 $index++;
4789 }
4790 if ($index > $#versions_A) {
4791 $index = $#versions_A;
4792 }
4793
4794 my $result;
4795 if ($versions_A[$index] =~ /\d+/ && $versions_B[$index] =~ /\d+/) {
4796 $result = $versions_A[$index] - $versions_B[$index];
4797 } elsif ($versions_A[$index] =~ /\w+/ && $versions_B[$index] =~ /\d+/) {
4798 $result = -1;
4799 } elsif ($versions_A[$index] =~ /\d+/ && $versions_B[$index] =~ /\w+/) {
4800 $result = 1;
4801 } else {
4802 $result = 0;
4803 }
4804
4805 return $result;
4806}
4807
4808#
4809# Check to see what product is installed, and how it relates to the
4810# new product being installed, asking the user relevant questions,
4811# and allowing the user to abort(error out) if they don't want the
4812# existing installed product to be removed (as in for an up/downgrade
4813# or conflicting product).
4814#
4815sub prompt_user_to_remove_installed_product {
4816 # First off, only a few products even have "mismatches", i.e. can possibly conflict.
4817 if (((vmware_product() eq 'ws') ||
4818 (vmware_product() eq 'player')) &&
4819 (installed_product_mismatch() != 0)) {
4820 if (get_answer('You have a product that conflicts with '.vmware_product_name().' installed. ' .
4821 'Continuing this install will first uninstall this product. ' .
4822 'Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
4823 error "User canceled install.\n";
4824 }
4825 return;
4826 }
4827 #Now that the group of other-conflicting products is handled, we are sure this product simply
4828 #conflicts with itself, even if its one of those.
4829 my $binfile = get_installed_product_bin();
4830 if ( $binfile eq 'UNKNOWN' or $binfile eq '' ){
4831 #Without a binfile, we can't detect version, so we simply warn the user we are about to uninstall
4832 #and ask them if they want that.
4833 if (get_answer('You have a version of '.vmware_product_name().' installed. ' .
4834 'Continuing this install will first uninstall the currently installed version.' .
4835 ' Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
4836 error "User canceled install.\n";
4837 }
4838 return;
4839 }
4840
4841 my $product_str = direct_command($binfile . ' -v');
4842 my $installed_version = direct_command($binfile . ' -v');
4843 my $product_version = vmware_version();
4844 if (compare_version_strings($installed_version, $product_version) > 0) {
4845 if (get_answer('You have a more recent version of '.vmware_product_name().' installed. ' .
4846 'Continuing this install will DOWNGRADE to the latest version by first ' .
4847 'uninstalling the more recent version. Do you wish to continue? (yes/no)', 'yesno', 'no') eq 'no') {
4848 error "User canceled install.\n";
4849 }
4850 } else {
4851 if (get_answer('You have a previous version of '.vmware_product_name().' installed. ' .
4852 'Continuing this install will upgrade to the latest version by first ' .
4853 'uninstalling the previous version. Do you wish to continue? (yes/no)', 'yesno', 'yes') eq 'no') {
4854 error "User canceled install.\n";
4855 }
4856 }
4857}
4858
4859#
4860# preuninstall_installed_tools
4861#
4862# hook scripts to run before uninstalling previously installed tools
4863
4864sub preuninstall_installed_tools {
4865 # esx35* tools will backup system configuration file during installation
4866 # and restore the backuped file when to reconfigure tools or uninstall tools.
4867 # It is flawed in that user's modification made between backup and restore·
4868 # will lost. Specificly /etc/fstab was affected and reported as PR 400907.
4869 #
4870 # Below is a fix to keep user's modification by preventing uninstaller from·
4871 # restore /etc/fstab. But it does not fix other configuration lost problem.
4872 my $version;
4873 my $file;
4874 my $answer;
4875 my %files_to_keep;
4876 my @files_to_restore;
4877 my @files_to_restore_filtered;
4878
4879 %files_to_keep = (
4880 "OLD_FSTAB" => undef,
4881 ); #can be extended to other backups
4882
4883 if (-e $gInstallerMainDB && -x $gInstallerObject) {
4884 # check installer database version
4885 if (system(shell_string($gInstallerObject) . ' version >/dev/null 2>&1')) {
4886 $version = '1';
4887 } else {
4888 $version = direct_command(shell_string($gInstallerObject) . ' version');
4889 chop($version);
4890 }
4891
4892 #esx35* and above are of version 4.
4893 if ($version == 4) {
4894 db_load(); #initialize gDBAnswer
4895 open(INSTALLDB, '>>' . $gInstallerMainDB);
4896
4897 #filter the RESTORE_BACK_LIST, remove files that we want to keep
4898 $answer = db_get_answer_if_exists("RESTORE_BACK_LIST");
4899 if (defined($answer)) {
4900 @files_to_restore = split(':', $answer);
4901 @files_to_restore_filtered = ();
4902 foreach $file (@files_to_restore) {
4903 if (!exists($files_to_keep{$file})) {
4904 push(@files_to_restore_filtered, $file);
4905 }
4906 }
4907
4908 #save back to db
4909 if (@files_to_restore > @files_to_restore_filtered) {
4910 $answer = join(":", @files_to_restore_filtered);
4911 db_remove_answer("RESTORE_BACK_LIST");
4912 db_add_answer("RESTORE_BACK_LIST", $answer);
4913 }
4914 }
4915
4916 # Add INITRDMODS_CONF_VALS, so that it won't fail the old uninstaller.
4917 # And this is PR 983072.
4918 $answer = db_get_answer_if_exists("INITRDMODS_CONF_VALS");
4919 if (!defined($answer)) {
4920 db_add_answer("INITRDMODS_CONF_VALS", "");
4921 }
4922
4923 db_save(); #close db
4924 }
4925 }
4926}
4927
4928
4929#
4930# Make sure we have an initial database suitable for this installer. The goal
4931# is to encapsulates all the compatibilty issues in this (consequently ugly)
4932# function
4933#
4934# SIDE EFFECTS:
4935# This function uninstalls previous products found (now managed by
4936# prompt_user_to_remove_installed_product)
4937#
4938
4939sub get_initial_database {
4940 my $made_dir1;
4941 my $made_dir2;
4942 my $bkp_dir;
4943 my $bkp;
4944 my $kind;
4945 my $version;
4946 my $intermediate_format;
4947 my $status;
4948 my $state_file;
4949 my $state_files;
4950 my $clear_db = 0;
4951
4952 if (not (-e $gInstallerMainDB)) {
4953 create_initial_database();
4954 return;
4955 }
4956
4957 print wrap('A previous installation of ' . vmware_product_name()
4958 . ' has been detected.' . "\n\n", 0);
4959
4960 #
4961 # Convert the previous installer database to our format and backup it
4962 # Uninstall the previous installation
4963 #
4964
4965 $bkp_dir = make_tmp_dir('vmware-installer');
4966 $bkp = $bkp_dir . '/prev_db.tar.gz';
4967
4968 if (-x $gInstallerObject) {
4969 $kind = direct_command(shell_string($gInstallerObject) . ' kind');
4970 chop($kind);
4971 if (system(shell_string($gInstallerObject) . ' version >/dev/null 2>&1')) {
4972 # No version method -> this is version 1
4973 $version = '1';
4974 } else {
4975 $version = direct_command(shell_string($gInstallerObject) . ' version');
4976 chop($version);
4977 }
4978 print wrap('The previous installation was made by the ' . $kind
4979 . ' installer (version ' . $version . ').' . "\n\n", 0);
4980
4981 if ($version < 2) {
4982 # The best database format those installers know is tar. We will have to
4983 # upgrade the format
4984 $intermediate_format = 'tar';
4985 } elsif ($version == 2) {
4986 # Those installers at least know about the tar2 database format. We won't
4987 # have to do too much
4988 $intermediate_format='tar2'
4989 } elsif ($version == 3) {
4990 # Those installers at least know about the tar3 database format. We won't
4991 # have to do much
4992 $intermediate_format = 'tar3';
4993 } else {
4994 # Those installers at least know about the tar4 database format. We won't
4995 # have to do anything
4996 $intermediate_format = 'tar4';
4997 }
4998 system(shell_string($gInstallerObject) . ' convertdb '
4999 . shell_string($intermediate_format) . ' ' . shell_string($bkp));
5000
5001 # Uninstall the previous installation
5002 if (((vmware_product() eq 'ws') ||
5003 (vmware_product() eq 'player')) &&
5004 (installed_product_mismatch() != 0)) {
5005 $clear_db = 1;
5006 }
5007 # Remove any installed product *if* user accepts.
5008 prompt_user_to_remove_installed_product();
5009 if (isToolsProduct()) {
5010 preuninstall_installed_tools();
5011 }
5012 $status = system(shell_string($gInstallerObject) . ' uninstall --upgrade');
5013 if ($status) {
5014 error("Uninstall failed. Please correct the failure and re run the install.\n\n");
5015 }
5016 if (vmware_product() eq 'ws') {
5017 $gOption{'ws-upgrade'} = 1;
5018 }
5019
5020 # Beware, beyond this point, $gInstallerObject does not exist
5021 # anymore.
5022 } else {
5023 # No installer object -> this is the old installer, which we don't support
5024 # anymore.
5025 $status = 1;
5026 }
5027 if ($status) {
5028 remove_tmp_dir($bkp_dir);
5029 # remove the installer db so the next invocation of install can proceed.
5030 if (get_answer('Uninstallation of previous install failed. ' .
5031 'Would you like to remove the install DB?', 'yesno', 'no') eq 'yes') {
5032 print wrap('Removing installer DB, please re-run the installer.' . "\n\n", 0);
5033 unlink $gInstallerMainDB;
5034 }
5035
5036 error('Failure' . "\n\n");
5037 }
5038
5039 if ($clear_db == 1) {
5040 create_initial_database();
5041 return;
5042 }
5043
5044 # Create the directory structure to welcome the restored database
5045 $made_dir1 = 0;
5046 if (not (-d $gRegistryDir)) {
5047 safe_mkdir($gRegistryDir);
5048 $made_dir1 = 1;
5049 }
5050 safe_chmod(0755, $gRegistryDir);
5051 $made_dir2 = 0;
5052 if ($version >= 2) {
5053 if (not (-d $gStateDir)) {
5054 safe_mkdir($gStateDir);
5055 $made_dir2 = 1;
5056 }
5057 safe_chmod(0755, $gStateDir);
5058 }
5059
5060 # Some versions of tar (1.13.17+ are ok) do not untar directory permissions
5061 # as described in their documentation (they overwrite permissions of
5062 # existing, non-empty directories with permissions stored in the archive)
5063 #
5064 # Because we didn't know about that at the beginning, the previous
5065 # uninstallation may have included the directory structure in their database
5066 # backup.
5067 #
5068 # To avoid that, we must re-package the database backup
5069 if (vmware_product() eq 'tools-for-solaris') {
5070 # Solaris' default tar(1) does not support gnu tar's -C or -z options.
5071 system('cd ' . shell_string($bkp_dir) . ';'
5072 . shell_string($gHelper{'gunzip'}) . ' -c ' . shell_string($bkp)
5073 . ' | ' . shell_string($gHelper{'tar'}) . ' -xopf -');
5074 } else {
5075 system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
5076 . ' -xzopf ' . shell_string($bkp));
5077 }
5078 $state_files = '';
5079 if (-d $bkp_dir . $gStateDir) {
5080 foreach $state_file (internal_ls($bkp_dir . $gStateDir)) {
5081 $state_files .= ' ' . shell_string('.' . $gStateDir . '/'. $state_file);
5082 }
5083 }
5084 $bkp = $bkp_dir . '/prev_db2.tar.gz';
5085 if (vmware_product() eq 'tools-for-solaris') {
5086 system('cd ' . shell_string($bkp_dir) . ';'
5087 . shell_string($gHelper{'tar'}) . ' -copf - '
5088 . shell_string('.' . $gInstallerMainDB) . $state_files
5089 . ' | ' . shell_string($gHelper{'gzip'}) . ' > ' . shell_string($bkp));
5090 } else {
5091 system(shell_string($gHelper{'tar'}) . ' -C ' . shell_string($bkp_dir)
5092 . ' -czopf ' . shell_string($bkp) . ' '
5093 . shell_string('.' . $gInstallerMainDB) . $state_files);
5094 }
5095
5096 # Restore the database ready to be used by our installer
5097 if (vmware_product() eq 'tools-for-solaris') {
5098 system('cd /;'
5099 . shell_string($gHelper{'gunzip'}) . ' -c ' . shell_string($bkp)
5100 . ' | ' . shell_string($gHelper{'tar'}) . ' -xopf -');
5101 } else {
5102 system(shell_string($gHelper{'tar'}) . ' -C / -xzopf ' . shell_string($bkp));
5103 }
5104 remove_tmp_dir($bkp_dir);
5105
5106 if ($version < 2) {
5107 print wrap('Converting the ' . $intermediate_format
5108 . ' installer database format to the tar4 installer database format.'
5109 . "\n\n", 0);
5110 # Upgrade the database format: keep only the 'answer' statements, and add a
5111 # 'file' statement for the main database file
5112 my $id;
5113
5114 db_load();
5115 if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
5116 error('Unable to open the tar installer database ' . $gInstallerMainDB
5117 . ' in write-mode.' . "\n\n");
5118 }
5119 db_add_file($gInstallerMainDB, 0);
5120 foreach $id (keys %gDBAnswer) {
5121 print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
5122 }
5123 db_save();
5124 } elsif( $version == 2 ) {
5125 print wrap('Converting the ' . $intermediate_format
5126 . ' installer database format to the tar4 installer database format.'
5127 . "\n\n", 0);
5128 # Upgrade the database format: keep only the 'answer' statements, and add a
5129 # 'file' statement for the main database file
5130 my $id;
5131
5132 db_load();
5133 if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
5134 error('Unable to open the tar installer database ' . $gInstallerMainDB
5135 . ' in write-mode.' . "\n\n");
5136 }
5137 db_add_file($gInstallerMainDB, 0);
5138 foreach $id (keys %gDBAnswer) {
5139 # For the rpm3|tar3 format, a number of keywords were removed. In their
5140 # place a more flexible scheme was implemented for which each has a semantic
5141 # equivalent:
5142 #
5143 # VNET_HOSTONLY -> VNET_1_HOSTONLY
5144 # VNET_HOSTONLY_HOSTADDR -> VNET_1_HOSTONLY_HOSTADDR
5145 # VNET_HOSTONLY_NETMASK -> VNET_1_HOSTONLY_NETMASK
5146 # VNET_INTERFACE -> VNET_0_INTERFACE
5147 #
5148 # Note that we no longer use the samba variables, so these entries are
5149 # removed (and not converted):
5150 # VNET_SAMBA -> VNET_1_SAMBA
5151 # VNET_SAMBA_MACHINESID -> VNET_1_SAMBA_MACHINESID
5152 # VNET_SAMBA_SMBPASSWD -> VNET_1_SAMBA_SMBPASSWD
5153 my $newid = $id;
5154 if ("$id" eq 'VNET_SAMBA') {
5155 next;
5156 } elsif ("$id" eq 'VNET_SAMBA_MACHINESID') {
5157 next;
5158 } elsif ("$id" eq 'VNET_SAMBA_SMBPASSWD') {
5159 next;
5160 } elsif ("$id" eq 'VNET_HOSTONLY') {
5161 $newid='VNET_1_HOSTONLY';
5162 } elsif ("$id" eq 'VNET_HOSTONLY_HOSTADDR') {
5163 $newid='VNET_1_HOSTONLY_HOSTADDR';
5164 } elsif ("$id" eq 'VNET_HOSTONLY_NETMASK') {
5165 $newid='VNET_1_HOSTONLY_NETMASK';
5166 } elsif ("$id" eq 'VNET_INTERFACE') {
5167 $newid='VNET_0_INTERFACE';
5168 }
5169
5170 print INSTALLDB 'answer ' . $newid . ' ' . $gDBAnswer{$id} . "\n";
5171 }
5172
5173 # For the rpm4|tar4 format, two keyword were added. We add them here if
5174 # necessary. Note that it is only necessary to check the existence of two
5175 # VNET_HOSTONLY_ keywords since the rpm2|tar2 format contained only a few
5176 # VNET_ keywords
5177 my $addr = db_get_answer_if_exists('VNET_HOSTONLY_HOSTADDR');
5178 my $mask = db_get_answer_if_exists('VNET_HOSTONLY_NETMASK');
5179 if (defined($addr) and defined($mask)) {
5180 print INSTALLDB 'answer VNET_1_HOSTONLY_SUBNET ' .
5181 compute_subnet($addr, $mask) . "\n";
5182 print INSTALLDB "answer VNET_1_DHCP yes\n";
5183 }
5184
5185 db_save();
5186 } elsif ( $version == 3 ) {
5187 print wrap('Converting the ' . $intermediate_format
5188 . ' installer database format to the tar4 installer database format.'
5189 . "\n\n", 0);
5190 # Upgrade the database format: keep only the 'answer' statements, and add a
5191 # 'file' statement for the main database file
5192 my $id;
5193
5194 db_load();
5195 if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
5196 error('Unable to open the tar installer database ' . $gInstallerMainDB
5197 . ' in write-mode.' . "\n\n");
5198 }
5199 db_add_file($gInstallerMainDB, 0);
5200
5201 # No conversions necessary between version 3 and 4, so add all answers
5202 foreach $id (keys %gDBAnswer) {
5203 print INSTALLDB 'answer ' . $id . ' ' . $gDBAnswer{$id} . "\n";
5204 }
5205
5206 # Check whether we need to add the two new keywords for each virtual network:
5207 # VNET_n_HOSTONLY_SUBNET -> set if VNET_n_HOSTONLY_{HOSTADDR,NETMASK} are set
5208 # VNET_n_DHCP -> 'yes' iff VNET_n_INTERFACE is not defined and
5209 # VNET_n_HOSTONLY_{HOSTADDR,NETMASK} are defined
5210 #
5211 my $i;
5212 for ($i = $gMinVmnet; $i < $gMaxVmnet; $i++) {
5213 my $pre = 'VNET_' . $i . '_';
5214 my $interface = db_get_answer_if_exists($pre . 'INTERFACE');
5215 my $hostaddr = db_get_answer_if_exists($pre . 'HOSTONLY_HOSTADDR');
5216 my $netmask = db_get_answer_if_exists($pre . 'HOSTONLY_NETMASK');
5217
5218 if (defined($hostaddr) && defined($netmask)) {
5219 my $subnet = compute_subnet($hostaddr, $netmask);
5220 print INSTALLDB 'answer ' . $pre . 'HOSTONLY_SUBNET ' . $subnet . "\n";
5221
5222 if (not defined($interface)) {
5223 print INSTALLDB 'answer ' . $pre . "DHCP yes\n";
5224 }
5225 }
5226 }
5227
5228 db_save();
5229 }
5230
5231 db_load();
5232 db_append();
5233 if ($made_dir1) {
5234 db_add_dir($gRegistryDir);
5235 }
5236 if ($made_dir2) {
5237 db_add_dir($gStateDir);
5238 }
5239}
5240
5241sub create_initial_database {
5242 my $made_dir1;
5243 undef %gDBAnswer;
5244 undef %gDBFile;
5245 undef %gDBDir;
5246 undef %gDBLink;
5247 undef %gDBMove;
5248
5249 # This is the first installation. Create the installer database from
5250 # scratch
5251 print wrap('Creating a new ' . vmware_product_name()
5252 . ' installer database using the tar4 format.' . "\n\n", 0);
5253
5254 $made_dir1 = not create_dir($gRegistryDir, 0);
5255 safe_chmod(0755, $gRegistryDir);
5256
5257 if (not open(INSTALLDB, '>' . $gInstallerMainDB)) {
5258 if ($made_dir1) {
5259 rmdir($gRegistryDir);
5260 }
5261 error('Unable to open the tar installer database ' . $gInstallerMainDB
5262 . ' in write-mode.' . "\n\n");
5263 }
5264 # Force a flush after every write operation.
5265 # See 'Programming Perl', p. 110
5266 select((select(INSTALLDB), $| = 1)[0]);
5267
5268 if ($made_dir1) {
5269 db_add_dir($gRegistryDir);
5270 }
5271 # This file is going to be modified after its creation by this program.
5272 # Do not timestamp it
5273 db_add_file($gInstallerMainDB, 0);
5274}
5275
5276# SIGINT handler. We will never reset the handler to the DEFAULT one, because
5277# with the exception of pre-uninstaller not being installed, this one does
5278# the same thing as the default (kills the process) and even sends the end
5279# RPC for us in tools installations.
5280sub sigint_handler {
5281 if ($gIsUninstallerInstalled == 0) {
5282 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);
5283
5284 return;
5285 }
5286
5287 error('');
5288}
5289
5290# Get the installed version of VMware
5291# Return the version if found, or ''
5292sub get_installed_version() {
5293 my $backslash;
5294 my $dollar;
5295 my $pattern;
5296 my $version;
5297 my $nameTag;
5298
5299 # XXX In the future, we should use a method of the installer object to
5300 # retrieve the installed version
5301
5302 #
5303 # Try to retrieve the installed version from the configurator program. This
5304 # works for both the tar and the rpm installers
5305 #
5306
5307 if (not defined($gDBAnswer{'BINDIR'})) {
5308 return '';
5309 }
5310
5311 if (not open(FILE, '<' . db_get_answer('BINDIR') . $gConfigurator)) {
5312 return '';
5313 }
5314
5315 # Build the pattern without using the dollar character, so that CVS doesn't
5316 # modify the pattern in tagged builds (bug 9303)
5317 $backslash = chr(92);
5318 $dollar = chr(36);
5319 $pattern = '^ ' . $backslash . $dollar . 'buildNr = ' .
5320 "'" . '(\S+) ' . "'" . ' ' . $backslash . '. q' .
5321 $backslash . $dollar . 'Name: (\S+)? ' . $backslash . $dollar . ';' . $dollar;
5322
5323 $version = '';
5324 $nameTag = '';
5325 while (<FILE>) {
5326 if (/$pattern/) {
5327 $version = $1;
5328 $nameTag = defined($2) ? $2 : '';
5329 }
5330 }
5331 close(FILE);
5332
5333 return $version;
5334}
5335
5336# Get the installed kind of VMware
5337# Return the kind if found, or ''
5338sub get_installed_kind() {
5339 my $kind;
5340
5341 if (not (-x $cInstallerObject)) {
5342 return '';
5343 }
5344
5345 $kind = direct_command(shell_string($cInstallerObject) . ' kind');
5346 chop($kind);
5347
5348 return $kind;
5349}
5350
5351# Install the content of the module package
5352sub install_module {
5353 my %patch;
5354
5355 print wrap('Installing the kernel modules contained in this package.' . "\n\n", 0);
5356
5357 undef %patch;
5358 install_dir('./lib', db_get_answer('LIBDIR'), \%patch, 0x1);
5359}
5360
5361# Uninstall modules
5362sub uninstall_module {
5363 print wrap('Uninstalling currently installed kernel modules.' . "\n\n", 0);
5364
5365 uninstall_prefix(db_get_answer('LIBDIR') . '/modules');
5366}
5367
5368# XXX Duplicated in config.pl
5369# format of the returned hash:
5370# - key is the system file
5371# - value is the backed up file.
5372# This function should never know about filenames. Only database
5373# operations.
5374sub db_get_files_to_restore {
5375 my %fileToRestore;
5376 undef %fileToRestore;
5377 my $restorePrefix = 'RESTORE_';
5378 my $restoreBackupSuffix = '_BAK';
5379 my $restoreBackList = 'RESTORE_BACK_LIST';
5380
5381 if (defined db_get_answer_if_exists($restoreBackList)) {
5382 my $restoreStr;
5383 foreach $restoreStr (split(/:/, db_get_answer($restoreBackList))) {
5384 if (defined db_get_answer_if_exists($restorePrefix . $restoreStr)) {
5385 $fileToRestore{db_get_answer($restorePrefix . $restoreStr)} =
5386 db_get_answer($restorePrefix . $restoreStr
5387 . $restoreBackupSuffix);
5388 }
5389 }
5390 }
5391 return %fileToRestore;
5392}
5393
5394# Returns an array with the list of files that changed since we installed
5395# them.
5396sub db_is_file_changed {
5397
5398 my $file = shift;
5399 my @statbuf;
5400
5401 @statbuf = stat($file);
5402 if (defined $gDBFile{$file} && $gDBFile{$file} ne '0' &&
5403 $gDBFile{$file} ne $statbuf[9]) {
5404 return 'yes';
5405 } else {
5406 return 'no';
5407 }
5408}
5409
5410sub filter_out_bkp_changed_files {
5411
5412 my $filesToRestoreRef = shift;
5413 my $origFile;
5414
5415 foreach $origFile (keys %$filesToRestoreRef) {
5416 if (db_file_in($origFile) && !-l $origFile &&
5417 db_is_file_changed($origFile) eq 'yes') {
5418 # We are in the case of bug 25444 where we are restoring a file
5419 # that we backed up and was changed in the mean time by someone else
5420 db_remove_file($origFile);
5421 backup_file($$filesToRestoreRef{$origFile});
5422 unlink $$filesToRestoreRef{$origFile};
5423 print wrap("\n" . 'File ' . $$filesToRestoreRef{$origFile}
5424 . ' was not restored from backup because our file '
5425 . $origFile
5426 . ' got changed or overwritten between the time '
5427 . vmware_product_name()
5428 . ' installed the file and now.' . "\n\n"
5429 ,0);
5430 delete $$filesToRestoreRef{$origFile};
5431 }
5432 }
5433}
5434
5435sub restore_backedup_files {
5436 my $fileToRestore = shift;
5437 my $origFile;
5438
5439 foreach $origFile (keys %$fileToRestore) {
5440 if (file_name_exist($origFile) &&
5441 file_name_exist($$fileToRestore{$origFile})) {
5442 backup_file($origFile);
5443 unlink $origFile;
5444 }
5445 if ((not file_name_exist($origFile)) &&
5446 file_name_exist($$fileToRestore{$origFile})) {
5447 rename $$fileToRestore{$origFile}, $origFile;
5448 }
5449 }
5450}
5451
5452# depmod_all_kernels
5453#
5454# Runs depmod on all installed kernels on the system.
5455sub depmod_all_kernels {
5456 my $depmodBin = shell_string($gHelper{'depmod'});
5457
5458 foreach my $kRel (internal_ls('/lib/modules/')) {
5459 # Check if the modules.dep file exists. If so, then
5460 # rebuild modules.dep for that kernel.
5461 my $depmodPath = "/lib/modules/$kRel/modules.dep";
5462 if (-f $depmodPath) {
5463 system(join(' ', $depmodBin, '-a', $kRel));
5464 }
5465 }
5466}
5467
5468# The initrd in place includes modules we added on configure. If the module
5469# files containing references to these modules have been restored then simply
5470# remaking the initrd will put it back into original condition.
5471sub restore_kernel_initrd {
5472 my $cmd = db_get_answer_if_exists('RESTORE_RAMDISK_CMD');
5473
5474 if (defined($cmd)) {
5475 # Rebuild all the system modules.dep files to reflect
5476 # us ripping out all of the kernel modules.
5477 depmod_all_kernels();
5478
5479 my $kernListStr = db_get_answer_if_exists('RESTORE_RAMDISK_KERNELS');
5480 my $oneCall = db_get_answer_if_exists('RESTORE_RAMDISK_ONECALL');
5481 if ($oneCall) {
5482 if (system(join(' ', $cmd, '>/dev/null 2>&1')) != 0) {
5483 # Check to ensure that the command succeded. If it didn't the system may
5484 # not boot. We need to error out if that is the case.
5485 error( wrap("ERROR: \"$cmd\" exited with non-zero status.\n" .
5486 "\n" .
5487 'Your system currently may not have a functioning init ' .
5488 'image and may not boot properly. DO NOT REBOOT! ' .
5489 'Please ensure that you have enough free space available ' .
5490 "in your /boot directory and run this command: \"$cmd\" " .
5491 "again.\n\n", 0));
5492
5493 }
5494
5495 } elsif ($kernListStr) {
5496 my @kerns = split(/,/, $kernListStr);
5497
5498 # Now for each kernel in our list, run the initrd restore command on it
5499 foreach my $kern (@kerns) {
5500 next unless (-e "/lib/modules/$kern/modules.dep");
5501 my $fullCmd = $cmd;
5502 $fullCmd =~ s/KREL/$kern/g;
5503 if (system(join(' ', $fullCmd, '>/dev/null 2>&1')) != 0) {
5504 error( wrap("ERROR: \"$fullCmd\" exited with non-zero status.\n" .
5505 "\n" .
5506 'Your system currently may not have a functioning init ' .
5507 'image and may not boot properly. DO NOT REBOOT! ' .
5508 'Please ensure that you have enough free space available ' .
5509 "in your /boot directory and run this command: \"$fullCmd\" " .
5510 "again.\n\n", 0));
5511 }
5512 }
5513 } else {
5514 error("RESTORE_RAMDISK parameters were not properly set.\n");
5515 }
5516 # Now reset all the answers
5517 db_remove_answer('RESTORE_RAMDISK_CMD');
5518 db_remove_answer('RESTORE_RAMDISK_KERNELS');
5519 db_remove_answer('RESTORE_RAMDISK_ONECALL');
5520 }
5521}
5522
5523
5524##
5525# unset_kmod_db_entries
5526#
5527# Iterates through the database and unsets kmod specific DB entries. This
5528# function is called at uninstall time since these modules are deleted as
5529# part of the uninstall. Yes I know I could do this faster... whatev.
5530#
5531sub unset_kmod_db_entries {
5532 foreach my $kmod (@cKernelModules) {
5533 my $regexp = '^' . uc($kmod) . '_.+_(PATH|NAME)';
5534 foreach my $key (keys %gDBAnswer) {
5535 db_remove_answer($key) if ($key =~ m/$regexp/);
5536 }
5537 }
5538}
5539
5540
5541##
5542# deconfigure_updatedb
5543#
5544# Deconfigures updatedb.conf. Removes hgfs entry from PRUNEFS.
5545#
5546sub deconfigure_updatedb {
5547 my $file = db_get_answer_if_exists('UPDATEDB_CONF_FILE');
5548
5549 return 0 unless ($file and -e $file);
5550
5551 my $key = db_get_answer('UPDATEDB_CONF_KEY');
5552 db_remove_answer('UPDATEDB_CONF_FILE');
5553 db_remove_answer('UPDATEDB_CONF_KEY');
5554
5555 my $regex = '^\s*(' . $key . '\s*=\s*")(.*)(")$';
5556 my $delim = ' ';
5557 my $entry = 'vmhgfs';
5558 return removeTextInKVEntryInFile($file, $regex, $delim, $entry);
5559}
5560
5561##
5562# deconfigure_initrd_suse
5563#
5564# deconfigures /etc/sysconfig/kernel
5565#
5566sub deconfigure_initrd_suse {
5567 my $file = db_get_answer_if_exists('INITRDMODS_CONF_FILE');
5568
5569 return 0 unless ($file and -e $file);
5570
5571 my $key = db_get_answer('INITRDMODS_CONF_KEY');
5572 my $vals = db_get_answer_if_exists('INITRDMODS_CONF_VALS');
5573
5574 # this should never hit, but just in case
5575 if (not defined $vals) {
5576 print wrap("warning: could not INITRDMODS_CONF_VALS value in locations db.\n\n", 0);
5577
5578 db_remove_answer('INITRDMODS_CONF_FILE');
5579 db_remove_answer('INITRDMODS_CONF_KEY');
5580 return 0;
5581 }
5582
5583 # put the space-delimited kmods in an array
5584 my @splitVals = split(' ', $vals);
5585
5586 my $regex = '^\s*(' . $key . '\s*=\s*")(.*)(")$';
5587 my $delim = ' ';
5588
5589 # removing all of the initrd kmods from the initrd file requires
5590 # a loop because of the logic in removeTextInKVEntryInFile
5591 foreach my $val (@splitVals) {
5592 removeTextInKVEntryInFile($file, $regex, $delim, $val);
5593 }
5594
5595 db_remove_answer('INITRDMODS_CONF_FILE');
5596 db_remove_answer('INITRDMODS_CONF_KEY');
5597 db_remove_answer('INITRDMODS_CONF_VALS');
5598
5599}
5600
5601##
5602# deconfigure_dracut
5603#
5604# deconfigures /etc/dracut.conf
5605#
5606sub deconfigure_dracut {
5607 my $file = db_get_answer_if_exists('INITRDMODS_CONF_FILE');
5608
5609 return 0 unless ($file and -e $file);
5610
5611 # we only deconfigure dracut.conf because /etc/dracut.conf.d/vmware-tools.conf
5612 # should be removed through the normal uninstallation routes (i.e., it will be removed)
5613 if ($file eq '/etc/dracut.conf') {
5614 # Then we have to deconfigure it inline (should only need on fedora 12).
5615 my $key = db_get_answer_if_exists('INITRDMODS_CONF_KEY');
5616 my $vals = db_get_answer_if_exists('INITRDMODS_CONF_VALS');
5617
5618 if (not $key or not $vals) {
5619 print wrap("warning: Unable to find $key or $vals in locations database.\n\n", 0);
5620 return 0;
5621 }
5622
5623 # put the space-delimited kmods in an array
5624 my @splitVals = split(' ', $vals);
5625
5626 my $regex = '^\s*(' . $key . '\s*\+=\s*")(.*)(")$';
5627 my $delim = ' ';
5628
5629 # removing all of the initrd kmods from the initrd file requires
5630 # a loop because of the logic in removeTextInKVEntryInFile
5631 foreach my $val (@splitVals) {
5632 removeTextInKVEntryInFile($file, $regex, $delim, $val);
5633 }
5634
5635 db_remove_answer('INITRDMODS_CONF_KEY');
5636 db_remove_answer('INITRDMODS_CONF_VALS');
5637
5638 } elsif($file eq '/etc/dracut.conf.d/vmware-tools.conf') {
5639 # do nothing because this file will be (or has already been) removed
5640 # via our normal uninstallation routes (i.e., uninstaller goes through
5641 # the installed files and removes them one by one).
5642 } else {
5643 print wrap("warning: Unable to deconfigure dracut.\n", 0);
5644 }
5645
5646 # remove the answer regardless
5647 db_remove_answer('INITRDMODS_CONF_FILE');
5648}
5649
5650##
5651# deconfigure_initmodfile
5652#
5653# Deconfigures the suse or dracut style initrd mechanisms
5654# (/etc/sysconfig/kernel or /etc/dracut.conf)
5655# deconfigure_dracut() defers Fedora 13+ .d style configurations
5656# to the normal uninstall mechanisms (removing the
5657# /etc/dracut.conf.d/vmware-tools.conf file)
5658#
5659sub deconfigure_initmodfile {
5660 if (-e '/etc/SuSE-release') { # same logic we use to determine distribution in config.pl
5661 deconfigure_initrd_suse();
5662 } elsif (internal_which('dracut') ne '') {
5663 deconfigure_dracut();
5664 }
5665}
5666
5667
5668#
5669# For files modified with block_append(), rather than restoring a backup file
5670# remove what was appended. This will preserve any changes a user may have made
5671# to these files after install/config ran.
5672sub restore_appended_files {
5673 my $list = '';
5674
5675 $list = db_get_answer_if_exists($cDBAppendString);
5676 if (not defined($list)) {
5677 return;
5678 }
5679
5680 foreach my $file (split(':', $list)) {
5681 if (-f $file) {
5682 block_restore($file, $cMarkerBegin, $cMarkerEnd);
5683 }
5684 }
5685}
5686
5687### Does the dstDir have enough space to hold srcDir
5688sub check_disk_space {
5689 my $srcDir = shift;
5690 my $dstDir = shift;
5691 my $srcSpace;
5692 my $dstSpace;
5693 my @parser;
5694
5695 # get the src usage
5696 open (OUTPUT, shell_string($gHelper{'du'}) . ' -sk ' . shell_string($srcDir)
5697 . ' 2>/dev/null|') or error("Failed to open 'du'.");
5698 $_ = <OUTPUT>;
5699 @parser = split(/\s+/);
5700 $srcSpace = $parser[0];
5701 close OUTPUT;
5702
5703 # Before we can check the space, $dst must exist. Walk up the directory path
5704 # until we find something that exists.
5705 while (! -d $dstDir) {
5706 $dstDir = internal_dirname($dstDir);
5707 }
5708 open (OUTPUT, shell_string($gHelper{'df'}) . ' -k ' . shell_string($dstDir)
5709 . ' 2>/dev/null|');
5710 while (<OUTPUT>) {
5711 @parser = split(/\s+/);
5712 if ($parser[0] ne 'Filesystem') {
5713 $dstSpace = $parser[3];
5714 }
5715 }
5716 close OUTPUT;
5717
5718 # Return the amount of space available in kbytes.
5719 return ($dstSpace - $srcSpace);
5720}
5721
5722
5723#
5724# Check to see that the product architecture is a mismatch for this os.
5725# Return an error string if there is a mismatch, otherwise return undef
5726#
5727sub product_os_match {
5728
5729 init_product_arch_hash();
5730 if (!defined($multi_arch_products{vmware_product()})) {
5731 return undef;
5732 }
5733
5734 if (is64BitUserLand() == (vmware_product_architecture() eq "x86_64")) {
5735 return undef;
5736 }
5737 if (is64BitUserLand() != (vmware_product_architecture() ne "x86_64")) {
5738 return undef;
5739 }
5740
5741 return sprintf('This version of "%s" is incompatible with this '
5742 . 'operating system. Please install the "%s" '
5743 . 'version of this program instead.'
5744 . "\n\n", vmware_product_name(),
5745 is64BitUserLand() ? 'x86_64' : 'i386');
5746}
5747
5748#
5749# Create a list of products that support both a 32bit and a 64bit
5750# architecture and thus should be matched to the running OS.
5751#
5752sub init_product_arch_hash {
5753 $multi_arch_products{'ws'} = 1;
5754 $multi_arch_products{'vix'} = 1;
5755 $multi_arch_products{'api'} = 1;
5756 $multi_arch_products{'vicli'} = 1;
5757}
5758
5759# Look for the location of an answer in a different database and return the
5760# the value or the empty string if no answer or file is found.
5761sub alt_db_get_answer {
5762 my $db_file = shift;
5763 my $key = shift;
5764 my $answer = '';
5765
5766 if (open(PLAYERINSTALLDB, '<' . $db_file)) {
5767 while (<PLAYERINSTALLDB>) {
5768 chomp;
5769 if (/^answer\s+$key\s+(.+)$/) {
5770 $answer = $1;
5771 } elsif (/^remove_answer\s+$key\s*$/) {
5772 $answer = '';
5773 }
5774 }
5775 close(PLAYERINSTALLDB);
5776 }
5777 return $answer;
5778}
5779
5780
5781# match the output of 'uname -s' to the product. These are compared without
5782# case sensitivity.
5783sub DoesOSMatchProduct {
5784
5785 my %osProductHash = (
5786 'tools-for-linux' => 'linux',
5787 'tools-for-solaris' => 'sunos',
5788 'tools-for-freebsd' => 'freebsd'
5789 );
5790
5791 my $OS = `uname -s`;
5792 chomp($OS);
5793
5794 return ($osProductHash{vmware_product()} =~ m/$OS/i) ? 1 : 0;
5795
5796}
5797
5798
5799##
5800# Checks to see if any of the package names in a given list
5801# are currently installed by RPM on the system.
5802# @param - A list of RPM packages to check for.
5803# @returns - A list of the installed RPM packages that this
5804# function checked for and found (if any).
5805#
5806sub checkRPMForPackages {
5807 my @pkgList = @_;
5808 my @instPkgs;
5809 my $bin = internal_which('rpm');
5810 my $cmd = join(' ', $bin, '-qa --queryformat \'%{NAME}\n\'');
5811
5812 if (-x $bin) {
5813 open(OUTPUT, "$cmd |");
5814 foreach my $instPkgName (<OUTPUT>) {
5815 chomp $instPkgName;
5816 foreach my $pkgName (@pkgList) {
5817 if ($pkgName eq $instPkgName) {
5818 push @instPkgs, $instPkgName;
5819 }
5820 }
5821 }
5822 close(OUTPUT);
5823 }
5824 return @instPkgs
5825}
5826
5827##
5828# Checks to see if any of the package names in a given list
5829# are currently installed by dpkg on the system.
5830# @param - A list of deb packages to check for.
5831# @returns - A list of the installed deb packages that this
5832# function checked for and found (if any).
5833#
5834sub checkDPKGForPackages {
5835 my @pkgList = @_;
5836 my @instPkgs;
5837 my $bin = internal_which('dpkg-query');
5838 my $cmd = join(' ', $bin, '--show --showformat=\'${Package}\n\'');
5839
5840 if (-x $bin) {
5841 open(OUTPUT, "$cmd |");
5842 foreach my $instPkgName (<OUTPUT>) {
5843 chomp $instPkgName;
5844 foreach my $pkgName (@pkgList) {
5845 if ($pkgName eq $instPkgName) {
5846 push @instPkgs, $instPkgName;
5847 }
5848 }
5849 }
5850 close(OUTPUT);
5851 }
5852 return @instPkgs
5853}
5854
5855
5856##
5857# Attempts to remove the given list of RPM packages
5858# @param - List of rpm packages to remove
5859# @returns - -1 if there was an internal error, otherwise
5860# the return value of RPM
5861#
5862sub removeRPMPackages {
5863 my @pkgList = @_;
5864 my $bin = internal_which('rpm');
5865 my @cmd = (("$bin", '-e'), @pkgList);
5866
5867 if (-x $bin) {
5868 return system(@cmd);
5869 } else {
5870 return -1;
5871 }
5872}
5873
5874
5875##
5876# Attempts to remove the given list of DEB packages
5877# @param - List of deb packages to remove
5878# @returns - -1 if there was an internal error, otherwise
5879# the return value of dpkg
5880#
5881sub removeDEBPackages {
5882 my @pkgList = @_;
5883 my $bin = internal_which('dpkg');
5884 my @cmd = (("$bin", '-r'), @pkgList);
5885
5886 if (-x $bin) {
5887 return system(@cmd);
5888 } else {
5889 return -1;
5890 }
5891}
5892
5893sub check_ovt_compatibility {
5894 # see bug #1460576:
5895 if (vmware_product() eq 'tools-for-linux') {
5896 if (getKernRelInteger() >= kernel_version_integer(4, 0, 0)) {
5897 my $vmtoolsd = internal_which('vmtoolsd');
5898
5899 my $vmtoolsd_version_string = direct_command(shell_string($vmtoolsd) . " -v 2> /dev/null");
5900 if (($vmtoolsd_version_string =~ /version ([\d+\.]+)/) and
5901 (dot_version_compare($1, '10.0.0') < 0)) {
5902
5903 my $ans;
5904 $ans = get_answer('For kernels >= 4.0.0, open-vm-tools need to be of ' .
5905 'version 10.0.0 or higher for VMware Host Guest Filessystem ' .
5906 '(vmhgfs) to function with VMware Tools. ' .
5907 'Please upgrade open-vm-tools and rerun this installer, ' .
5908 'or uninstall open-vm-tools. Alternatively, you can disable using ' .
5909 'the vmhgfs when VMware Tools are configured.' . "\n\n" .
5910 'Enter yes to proceed.', 'yesno', ($gOption{'force-install'} == 1) ? 'yes' : 'no');
5911 if ($ans ne 'yes') {
5912 error('');
5913 }
5914 return('no');
5915 }
5916 }
5917 }
5918 return('yes');
5919}
5920
5921# Program entry point
5922sub main {
5923 my (@setOption, $opt);
5924 my $chk_msg;
5925 my $originalPath;
5926 my $progpath = $0;
5927 my $scriptname = internal_basename($progpath);
5928 my $default_db_enable_hgfs;
5929
5930 if ((vmware_product() eq 'tools-for-linux' ||
5931 vmware_product() eq 'tools-for-freebsd' ||
5932 vmware_product() eq 'tools-for-solaris')
5933 && !DoesOSMatchProduct()) {
5934 error(vmware_longname() . ' will not install on the operating system you are ' .
5935 'running. Please be sure you install the version of ' .
5936 vmware_product_name() . ' that is appropriate for your operating system.' .
5937 "\n\n");
5938 }
5939
5940 $chk_msg = product_os_match();
5941 if (defined($chk_msg)) {
5942 error($chk_msg);
5943 }
5944
5945 if (!is_root()) {
5946 error('Please re-run this program as the super user.' . "\n\n");
5947 }
5948
5949 # Force the path to reduce the risk of using "modified" external helpers
5950 # If the user has a special system setup, he will will prompted for the
5951 # proper location anyway
5952 $originalPath = $ENV{'PATH'};
5953 $ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
5954
5955 initialize_globals(internal_dirname($0));
5956 initialize_external_helpers();
5957
5958 # List of questions answered with command-line arguments
5959 @setOption = ();
5960
5961 if (internal_basename($0) eq $cInstallerFileName or
5962 internal_basename($0) eq $cInstallerFileNameReal) {
5963 my $answer;
5964
5965 if ($#ARGV > -1) {
5966 # There are only two possible arguments
5967 while ($#ARGV != -1) {
5968 my $arg;
5969 $arg = shift(@ARGV);
5970
5971 if (lc($arg) =~ /^(-)?(-)?d(efault)?$/) {
5972 $gOption{'default'} = 1;
5973 } elsif (lc($arg) =~ /^(-)?(-)?r(egenerate-cert)?$/) {
5974 # force to regenerate server key and cert files:
5975 $gOption{'regenerate-cert'} = 1;
5976 } elsif (lc($arg) =~ /^(-)?(-)?f(orce-install)?$/) {
5977 # force install even though ovt is available:
5978 $gOption{'force-install'} = 1;
5979 } elsif (lc($arg) =~ /^--clobber-kernel-modules=([\w,]+)$/) {
5980 $gOption{'clobberKernelModules'} = "$1";
5981 } elsif (lc($arg) =~ /^-?-?prefix=.+/) {
5982 # repeat regex with non-transformed arg to preserve case:
5983 $arg =~ /^-?-?prefix=(.+)/;
5984 $gOption{'prefix'} = $1;
5985 } elsif ($arg =~ /=yes/ || $arg =~ /=no/) {
5986 push(@setOption, $arg);
5987 } elsif (lc($arg) =~ /^(-)?(-)?(no-create-shortcuts)$/) {
5988 $gOption{'create_shortcuts'} = 0;
5989 } else {
5990 send_rpc('toolinstall.end 0');
5991 install_usage();
5992 }
5993 }
5994 }
5995
5996 if (-e '/etc/vmware/database' && (vmware_product() eq 'ws')) {
5997 error("An incompatible VMware product is already installed on this " .
5998 "machine. You must uninstall it by running vmware-uninstall.\n\n");
5999 } elsif (-e '/etc/vmware-vix/database' && vmware_product() eq 'vix') {
6000 error("An incompatible VMware product is already installed on this " .
6001 "machine. You must uninstall it by running vmware-uninstall-vix.\n\n");
6002 }
6003
6004 # Other installers will be able to remove this installation cleanly only if
6005 # they find the uninstaller. That's why we:
6006 # . Install the uninstaller ASAP
6007 # . Prevent users from playing with Control-C while doing so
6008
6009 $gIsUninstallerInstalled = 0;
6010
6011 # Install the SIGINT handler. Don't bother resetting it, see
6012 # sigint_handler for details.
6013 $SIG{INT} = \&sigint_handler;
6014 $SIG{QUIT} = \&sigint_handler;
6015
6016 # Tell the Host that the installer for tools is now
6017 # active.
6018 if (vmware_product() eq 'tools-for-linux' ||
6019 vmware_product() eq 'tools-for-freebsd' ||
6020 vmware_product() eq 'tools-for-solaris') {
6021 send_rpc("toolinstall.installerActive 1");
6022 }
6023
6024 # Check for open-vm-tools and related packages before we install
6025 # tools-for-linux.
6026 if (vmware_product() eq 'tools-for-linux') {
6027 my @debPkgs = checkDPKGForPackages(@cOpenVMToolsDEBPackages);
6028 my @rpmPkgs = checkRPMForPackages(@cOpenVMToolsRPMPackages);
6029
6030 if (@debPkgs or @rpmPkgs) {
6031 my $pkg;
6032
6033 print wrap ('The installer has detected an existing ' .
6034 'installation of open-vm-tools on this system ' .
6035 'and will not attempt to remove and replace ' .
6036 'these user-space applications. It is recommended ' .
6037 'to use the open-vm-tools packages provided by ' .
6038 'the operating system. If you do not want to use ' .
6039 'the existing installation of open-vm-tools and ' .
6040 'attempt to install VMware Tools, you must ' .
6041 'uninstall the open-vm-tools packages and re-run ' .
6042 'this installer.' . "\n");
6043 print wrap ("The packages that need to be removed are:\n");
6044 foreach $pkg (@debPkgs, @rpmPkgs) {
6045 print $pkg . "\n";
6046 }
6047 my $ans = get_answer('The installer will next check if there are ' .
6048 'any missing kernel drivers. Type yes if you want ' .
6049 'to do this, otherwise type no', 'yesno', 'yes');
6050
6051 if ($ans ne 'yes') {
6052 error(
6053 "\n\nPlease manually remove open-vm-tools before " .
6054 "installing VMware Tools.\n\n");
6055 } else {
6056 if (check_ovt_compatibility() eq 'no') {
6057 # we need to set the default to 'no' but the db isn't setup yet,
6058 # so we need to remember this for later:
6059 $default_db_enable_hgfs = 'no';
6060 }
6061 $open_vm_compat = 1;
6062 }
6063 } else {
6064 my %os = identify_linux_variant();
6065 if (%os) {
6066 my $id = $os{"ID"};
6067 my $version_id;
6068
6069 if (defined $os{"VERSION_ID"}) {
6070 $version_id = $os{"VERSION_ID"};
6071 } else {
6072 # Assume Debian sid, the unstable distribution, has open-vm-tools.
6073 if ($id eq "debian") {
6074 $version_id = 7;
6075 } else {
6076 $version_id = 0;
6077 }
6078 }
6079
6080 $version_id =~ s/[^0-9.]//g;
6081 if (($id eq "rhel" && $version_id >= 7.0) ||
6082 ($id eq "centos" && $version_id >= 7.0) ||
6083 ($id eq "ol" && $version_id >= 7.0) ||
6084 ($id eq "fedora" && $version_id >= 19) ||
6085 ($id eq "sles" && $version_id >= 12) ||
6086 ($id eq "sled" && $version_id >= 12) ||
6087 ($id eq "opensuse" && $version_id >= 12.2) ||
6088 ($id eq "ubuntu" && $version_id >= 14.04) ||
6089 ($id eq "debian" && $version_id >= 7)) {
6090 # If installer db exists, user already made his choice to proceed.
6091 my $ans = get_answer(
6092 "open-vm-tools are available from the OS vendor and " .
6093 "VMware recommends using open-vm-tools. " .
6094 "See http://kb.vmware.com/kb/2073803 for more information.\n" .
6095 "Do you still want to proceed with this legacy installer?",
6096 'yesno', (-e $gInstallerMainDB) || ($gOption{'force-install'} == 1) ? 'yes' : 'no');
6097 if ($ans ne 'yes') {
6098 exit 0;
6099 }
6100 }
6101 }
6102 }
6103 }
6104
6105 # Don't allow installation of tools-for-solaris unless this is Solaris 9
6106 # or later and 32-bit (for now). Note that we only officially support
6107 # Solaris 10 Update 1 and higher, but we'll allow users to install on 9.
6108 if (vmware_product() eq 'tools-for-solaris') {
6109 my $solVersion = direct_command(shell_string($gHelper{'uname'}) . ' -r');
6110 chomp($solVersion);
6111 my ($major, $minor) = split /\./, $solVersion; # / Fix emacs fontification
6112
6113 if ($major != 5 || $minor < 9) {
6114 error('VMware Tools for Solaris is only supported on Solaris 10 and later.'
6115 . "\n\n");
6116 }
6117
6118 # Warn users that we don't support Solaris 9, but they can install
6119 if ($minor == 9) {
6120 if (get_answer('WARNING: VMware Tools for Solaris is officially supported '
6121 . 'on Solaris 10 and later, but you are running Solaris 9. '
6122 . 'Would you like to continue with the installation?',
6123 'yesno', 'yes') eq 'no') {
6124 error('You have selected to not install VMware Tools for Solaris on '
6125 . 'Solaris 9.' . "\n\n");
6126 }
6127 }
6128 }
6129 if (vmware_product() eq 'tools-for-solaris' ||
6130 vmware_product() eq 'tools-for-linux' ||
6131 vmware_product() eq 'tools-for-freebsd') {
6132 if (-e $dspMarkerFile) {
6133 error('VMware Tools cannot be installed, since they have already ' .
6134 'been installed using a package-based mechanism (rpm or deb) ' .
6135 'on this system. If you wish to continue, you must first ' .
6136 'remove the currently installed VMware Tools using the '.
6137 'appropriate packaged-based mechanism, and then restart this ' .
6138 'installer' . "\n\n");
6139 }
6140 }
6141
6142 if (vmware_product() ne 'tools-for-linux' &&
6143 vmware_product() ne 'tools-for-freebsd' &&
6144 vmware_product() ne 'tools-for-solaris') {
6145
6146 # If the product is not tools, we need to bail on detecting a xen kernel.
6147 if ( -d '/proc/xen' ) {
6148 error('You cannot install ' .
6149 vmware_product_name() .
6150 ' on a system running a xen kernel.');
6151 }
6152 }
6153
6154 # The uninstall of legacy tools must come before get_initial_database()
6155 if (vmware_product() eq 'tools-for-linux' ||
6156 vmware_product() eq 'tools-for-freebsd') {
6157 uninstall_content_legacy_tools();
6158 }
6159
6160 if ( $progpath =~ /(.*?)\/$scriptname/ ) {
6161 chdir($1);
6162 }
6163
6164 my $dstDir = $gRegistryDir;
6165 $gFirstCreatedDir = $dstDir;
6166 while (!-d $dstDir) {
6167 $gFirstCreatedDir = $dstDir;
6168 $dstDir = internal_dirname($dstDir);
6169 }
6170 get_initial_database();
6171
6172 if($open_vm_compat) {
6173 db_add_answer('OPEN_VM_COMPAT', 'yes');
6174 } else {
6175 db_add_answer('OPEN_VM_COMPAT', 'no');
6176 }
6177
6178 # Binary wrappers can be run by any user and need to read the
6179 # database.
6180 safe_chmod(0644, $gInstallerMainDB);
6181
6182 db_add_answer('INSTALL_CYCLE', 'yes');
6183
6184 foreach $opt (@setOption) {
6185 my ($key, $val);
6186 ($key, $val) = ($opt =~ /^([^=]*)=([^=]*)/);
6187 db_add_answer($key, $val);
6188 }
6189
6190 if (defined($default_db_enable_hgfs)) {
6191 db_add_answer('ENABLE_HGFS', $default_db_enable_hgfs);
6192 }
6193
6194 if (vmware_product() eq 'api') {
6195 my $previous = $gOption{'default'};
6196 $gOption{'default'} = 0;
6197 show_EULA();
6198 $gOption{'default'} = $previous;
6199 }
6200
6201 install_or_upgrade();
6202
6203 if (vmware_product() eq 'ws' || vmware_product() =~ 'tools-for-(linux|solaris)') {
6204 configure_gtk2();
6205 }
6206
6207 # Reset these answers in case we have installed new versions of these
6208 # documents.
6209 if (vmware_product() ne 'ws') {
6210 db_remove_answer('EULA_AGREED');
6211 db_remove_answer('ISC_COPYRIGHT_SEEN');
6212 }
6213 if (vmware_product() eq 'vix') {
6214 print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
6215 exit 0;
6216 }
6217
6218 if (vmware_product() ne 'api' &&
6219 vmware_product() ne 'nvdk' &&
6220 vmware_product() ne 'vix-disklib') {
6221 if (file_name_exist($gConfFlag)) {
6222 $answer = get_persistent_answer('Before running '
6223 . vmware_product_name()
6224 . ' for the first time, you need to '
6225 . 'configure it by invoking the '
6226 . 'following command: "'
6227 . db_get_answer('BINDIR')
6228 . '/' . "$gConfigurator" . '". Do you '
6229 . 'want this program to invoke the '
6230 . 'command for you now?'
6231 , 'RUN_CONFIGURATOR', 'yesno', 'yes');
6232 } else {
6233 if (vmware_product() ne 'vix') {
6234 print wrap('Before running ' . vmware_product_name() . ' for the '
6235 . 'first time, you need to configure it by invoking the'
6236 . ' following command: "' . db_get_answer('BINDIR')
6237 . '/' . "$gConfigurator" . '"' . "\n\n", 0);
6238 }
6239 $answer = 'no';
6240 }
6241 }
6242
6243 db_save();
6244
6245 my $configResult;
6246
6247 if ((vmware_product() ne 'api') &&
6248 (vmware_product() ne 'nvdk') &&
6249 ((vmware_product() ne 'vix-disklib')) &&
6250 ($answer eq 'yes')) {
6251 my $defaultOpt = ($gOption{'default'} == 1) ? ' --default' : '';
6252 $defaultOpt .= defined($gOption{'prefix'}) ? ' --prefix'
6253 . '=' . $gOption{'prefix'} : '';
6254
6255 # Pass in the clobber kernel modules option if necessary.
6256 if (defined $gOption{'clobberKernelModules'}) {
6257 $defaultOpt .= ' --clobber-kernel-modules=' .
6258 $gOption{'clobberKernelModules'};
6259 }
6260
6261 # If we're the tools installer, forego sending the end RPC and let
6262 # the configurator do it.
6263 my $rpcOpt = (vmware_product() eq 'tools-for-linux' ||
6264 vmware_product() eq 'tools-for-freebsd' ||
6265 vmware_product() eq 'tools-for-solaris') ?
6266 ' --rpc-on-end' : '';
6267
6268 my $shortcutOpt = $gOption{'create_shortcuts'} ? '' : ' --no-create-shortcuts';
6269
6270 my $certOpt = ($gOption{'regenerate-cert'} == 1) ? ' --regenerate-cert' : '';
6271
6272 # restore the user's original PATH before running the configurator
6273 $ENV{'PATH'} = $originalPath;
6274
6275 # Catch error result to see if configurator died abnormally.
6276 $configResult = system(shell_string(db_get_answer('BINDIR') .
6277 '/' . $gConfigurator) .
6278 $defaultOpt . $rpcOpt . $shortcutOpt . $certOpt . ' --preserve');
6279 } else {
6280 print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
6281 }
6282
6283 if (vmware_product() eq 'tools-for-linux') {
6284 # For the fix to bug 304998, we are removing the hard-coded vmhgfs
6285 # entry from /etc/fstab, and instead mounting/unmounting dynamically
6286 # from the tools init script at startup/shutdown respectively. This
6287 # allows the init script to check for certain conditions (e.g., not
6288 # running on ESX) before deciding to do the mount.
6289 block_restore('/etc/fstab', $cMarkerBegin, $cMarkerEnd);
6290 }
6291
6292 # Tell the Host that the installer for tools is now
6293 # active.
6294 if (vmware_product() eq 'tools-for-linux' ||
6295 vmware_product() eq 'tools-for-freebsd' ||
6296 vmware_product() eq 'tools-for-solaris') {
6297 send_rpc("toolinstall.installerActive 0");
6298 }
6299
6300 exit 0;
6301 }
6302
6303 #
6304 # Module updater.
6305 #
6306 # XXX This is not clean. We really need separate packages, managed
6307 # by the VMware package manager
6308 #
6309
6310 if (internal_basename($0) eq $cModuleUpdaterFileName) {
6311 my $installed_version;
6312 my $installed_kind;
6313 my $answer;
6314
6315 print wrap('Looking for a currently installed '
6316 . vmware_longname() . ' tar package.' . "\n\n", 0);
6317
6318 if (not (-e $cInstallerMainDB)) {
6319 error('Unable to find the ' . vmware_product_name() .
6320 ' installer database file (' . $cInstallerMainDB . ').' .
6321 "\n\n" . 'You may want to re-install the ' .
6322 vmware_longname() . ' package, then re-run this program.' . "\n\n");
6323 }
6324 db_load();
6325
6326 $installed_version = get_installed_version();
6327 $installed_kind = get_installed_kind();
6328
6329 if (not (($installed_version eq '10.0.6') and
6330 ($installed_kind eq 'tar'))) {
6331 error('This ' . vmware_product_name()
6332 . ' Kernel Modules package is intended to be used in conjunction '
6333 . 'with the ' . vmware_longname() . ' tar package only.' . "\n\n");
6334 }
6335
6336 # All module files are under LIBDIR
6337 if (not defined($gDBAnswer{'LIBDIR'})) {
6338 error('Unable to determine where the ' . vmware_longname()
6339 . ' package installed the library files.' . "\n\n"
6340 . 'You may want to re-install the ' . vmware_product_name() . ' '
6341 . vmware_version() . ' package, then re-run this program.' . "\n\n");
6342 }
6343
6344 db_append();
6345 uninstall_module();
6346 install_module();
6347
6348 print wrap('The installation of ' . vmware_product_name()
6349 . ' Kernel Modules '
6350 . vmware_version() . ' completed successfully.' . "\n\n", 0);
6351
6352 if (-e $cConfFlag) {
6353 $answer = get_persistent_answer('Before running the VMware software for '
6354 . 'the first time after this update, you'
6355 . ' need to configure it for your '
6356 . 'running kernel by invoking the '
6357 . 'following command: "'
6358 . db_get_answer('BINDIR')
6359 . '/' . $gConfigurator . '". Do you want this '
6360 . 'program to invoke the command for you now?',
6361 'RUN_CONFIGURATOR', 'yesno', 'yes');
6362 } else {
6363 $answer = 'no';
6364 }
6365
6366 db_save();
6367
6368 if ($answer eq 'yes') {
6369 system(shell_string(db_get_answer('BINDIR') . '/' . $gConfigurator));
6370 } else {
6371 print wrap('Enjoy,' . "\n\n" . ' --the VMware team' . "\n\n", 0);
6372 }
6373 exit 0;
6374 }
6375
6376 if (internal_basename($0) eq $gUninstallerFileName) {
6377 print wrap('Uninstalling the tar installation of ' .
6378 vmware_product_name() . '.' . "\n\n", 0);
6379
6380 if ($#ARGV > -1) {
6381 @setOption = ();
6382 # There are currently two options: --upgrade and --preserve-guest-proxy-data.
6383 while ($#ARGV != -1) {
6384 my $arg;
6385 $arg = shift(@ARGV);
6386 if (lc($arg) =~ /^(-)?(-)?u(pgrade)?$/) {
6387 $gOption{'upgrade'} = 1;
6388 } elsif (lc($arg) =~ /^(-)?(-)?p(reserve-guest-proxy-data)?$/) {
6389 $gOption{'preserve-guest-proxy-data'} = 1;
6390 } elsif ($arg =~ /=yes/ || $arg =~ /=no/) {
6391 push(@setOption, $arg);
6392 }
6393 }
6394 }
6395
6396 if (not (-e $gInstallerMainDB)) {
6397 error('Unable to find the tar installer database file (' .
6398 $gInstallerMainDB . ')' . "\n\n");
6399 }
6400 db_load();
6401
6402 db_append();
6403
6404 ### Begin check for non-VMware modules ###
6405 foreach $opt (@setOption) {
6406 my ($key, $val);
6407 ($key, $val) = ($opt =~ /^([^=]*)=([^=]*)/);
6408 delete $gDBAnswer{$key};
6409 db_add_answer($key, $val);
6410 }
6411
6412 if (vmware_product() eq 'tools-for-linux' ||
6413 vmware_product() eq 'tools-for-freebsd' ||
6414 vmware_product() eq 'tools-for-solaris') {
6415
6416 my %fileToRestore;
6417
6418 # Clean up the module loader config file from vmxnet.
6419 if (vmware_product() eq 'tools-for-freebsd' &&
6420 defined db_get_answer_if_exists('VMXNET_CONFED') &&
6421 db_get_answer('VMXNET_CONFED') eq 'yes') {
6422 my $loader_conf = '/boot/loader.conf';
6423 my $tmp_dir;
6424 my $tmp; # / unconfuse emacs fontification
6425 $tmp_dir = make_tmp_dir('vmware-installer');
6426 $tmp = $tmp_dir . '/loader.conf';
6427 if (block_remove($loader_conf, $tmp, $cMarkerBegin, $cMarkerEnd) >= 0) {
6428 system(shell_string($gHelper{'mv'}) . ' -f ' . shell_string($tmp)
6429 . ' '
6430 . shell_string($loader_conf));
6431 }
6432 remove_tmp_dir($tmp_dir);
6433 }
6434
6435 #
6436 # Legacy autostart hooks involved modifying system files, so we must manually
6437 # restore the VMware-added blocks.
6438 #
6439 if (vmware_product() =~ /^tools-for-(linux|freebsd|solaris)$/) {
6440 unconfigure_autostart_legacy($cMarkerBegin, $cMarkerEnd);
6441 }
6442
6443 # Get the file names before they disappear from the database.
6444 %fileToRestore = db_get_files_to_restore();
6445
6446 filter_out_bkp_changed_files(\%fileToRestore);
6447
6448 if (db_get_answer('OPEN_VM_COMPAT') eq 'yes') {
6449 $open_vm_compat = 1
6450 }
6451
6452 # Do the bulk of the file uninstallation. Pass in the (slightly)
6453 # different name for FreeBSD Tools so that they get stopped correctly.
6454 if (vmware_product() eq 'tools-for-freebsd') {
6455 uninstall('/vmware-tools.sh');
6456 } else {
6457 uninstall('/vmware-tools');
6458 }
6459
6460 # Clean up drivers with rem_drv(1M) (corresponds to add_drv(1M) calls in
6461 # configure_module_solaris() in configure script). This needs to happen
6462 # after the services are stopped in uninstall().
6463 if (vmware_product() eq 'tools-for-solaris') {
6464 if (defined db_get_answer_if_exists('VMXNET_CONFED') &&
6465 db_get_answer('VMXNET_CONFED') eq 'yes') {
6466
6467 system(shell_string($gHelper{'rem_drv'}) . ' vmxnet');
6468
6469 # Give pcn its claim on pci1022,2000 back
6470 if (direct_command(shell_string($gHelper{'uname'}) . ' -r') =~ 5.9) {
6471 # Try to add back the pcn driver we removed
6472 system(shell_string($gHelper{'add_drv'})
6473 . ' -i \'"pci103c,104c" "pci1022,2000"\' pcn >/dev/null 2>&1');
6474 } else {
6475 system(shell_string($gHelper{'update_drv'}) . ' -a -i \'"pci1022,2000"\' '
6476 . 'pcn >/dev/null 2>&1');
6477 }
6478 }
6479 if (defined db_get_answer_if_exists('VMXNET3S_CONFED') &&
6480 db_get_answer('VMXNET3S_CONFED') eq 'yes') {
6481 system(shell_string($gHelper{'rem_drv'}) . ' vmxnet3s');
6482 }
6483 if (defined db_get_answer_if_exists('VMHGFS_CONFED') &&
6484 db_get_answer('VMHGFS_CONFED') eq 'yes') {
6485 my $devLinkTable = "/etc/devlink.tab";
6486 my $searchString = "name=vmhgfs";
6487
6488 system(shell_string($gHelper{'rem_drv'}) . ' vmhgfs');
6489
6490 if (system(shell_string($gHelper{'grep'}) . ' ' . $searchString
6491 . ' ' . $devLinkTable . ' > /dev/null 2>&1') == 0) {
6492 # XXX There has to be a better way, but I don't know Perl
6493 my $tmpFile = "/tmp/VMware.devlink.tab";
6494 system(shell_string($gHelper{'cat'}) . ' ' . $devLinkTable . ' | '
6495 . shell_string($gHelper{'grep'}) . ' -v ' . $searchString
6496 . ' > ' . $tmpFile);
6497 system(shell_string($gHelper{'mv'}) . ' ' . $tmpFile . ' '
6498 . $devLinkTable);
6499 }
6500 }
6501 }
6502
6503 if (vmware_product() eq 'tools-for-linux') {
6504 if (defined db_get_answer_if_exists('VMHGFS_CONFED') &&
6505 db_get_answer('VMHGFS_CONFED') eq 'yes') {
6506 # remove the entries for the vmhgfs mount.
6507 block_restore('/etc/fstab', $cMarkerBegin, $cMarkerEnd);
6508 }
6509
6510 # If we modfified the ld.so cache during the install, we need to
6511 # run ldconfig here to ensure that the tools libraries are no
6512 # longer in the system library path.
6513 if (defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_ADDED_FILE') or
6514 defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_MODIFIED')) {
6515 #
6516 # Check to see if we modified ld.so.conf. If we did, then we need
6517 # to properly restore it.
6518 #
6519 if (defined db_get_answer_if_exists('LD_DOT_SO_DOT_CONF_MODIFIED')) {
6520 my $file = db_get_answer('LD_DOT_SO_DOT_CONF_MODIFIED');
6521 block_restore($file, $cMarkerBegin, $cMarkerEnd);
6522 }
6523
6524 if (internal_which('ldconfig') ne '') {
6525 system('ldconfig &> /dev/null');
6526 }
6527 }
6528
6529 # Call the prelink_restore function to fix that if it has been modified.
6530 prelink_restore();
6531 }
6532
6533 # remove the modules added to the list for the initrd.
6534 # Also restore the system Ramdisk (either initrd or initramfs)
6535 restore_appended_files();
6536 restore_backedup_files(\%fileToRestore);
6537 deconfigure_initmodfile();
6538 restore_kernel_initrd();
6539
6540 if (defined db_get_answer_if_exists('VMWGFX_CONFED') &&
6541 db_get_answer('VMWGFX_CONFED') eq 'yes' &&
6542 (internal_which('ldconfig') ne '')) {
6543 system('ldconfig &> /dev/null');
6544 }
6545
6546 deconfigure_updatedb();
6547 unset_kmod_db_entries();
6548
6549 # Check the DB to see if we need to restart HAL.
6550 if (defined db_get_answer_if_exists('HAL_RESTART_ON_UNINSTALL') and
6551 db_get_answer('HAL_RESTART_ON_UNINSTALL') eq 'yes') {
6552 restart_hal();
6553 }
6554
6555 # do not kill vmtoolsd on upgrade (see bug #838010)
6556 if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
6557 # Kill vmusr vmtoolsd instance before we exit.
6558 my $pkillBin = internal_which('pkill');
6559 if (-x $pkillBin) {
6560 system("$pkillBin -f 'vmtoolsd -n vmusr' >/dev/null 2>&1");
6561 }
6562 }
6563
6564 } elsif (vmware_product() eq 'vix') {
6565 uninstall_vix();
6566 } elsif (vmware_product() eq 'ws') {
6567 uninstall('/vmware');
6568 } elsif (vmware_product() eq 'vix-disklib') {
6569 uninstall('/vmware-vix-disklib');
6570 } elsif (vmware_product() eq 'nvdk') {
6571 uninstall('/nvdk');
6572 } else {
6573 uninstall('/vmware');
6574 }
6575
6576 db_save();
6577
6578 my $msg = 'The removal of ' . vmware_longname() . ' completed '
6579 . 'successfully.';
6580 if (!defined($gOption{'upgrade'}) || $gOption{'upgrade'} == 0) {
6581 $msg .= " Thank you for having tried this software.";
6582 }
6583 $msg .= "\n\n";
6584 print wrap($msg, 0);
6585
6586 system(internal_which('sync'));
6587
6588 exit 0;
6589 }
6590
6591 error('This program must be named ' . $cInstallerFileName . ' or '
6592 . $gUninstallerFileName . '.' . "\n\n");
6593}
6594
6595main();