#!/bin/sh
# Tar installer object
#
# This file is saved on the disk when the .tar package is installed by
# vmware-install.pl. It can be invoked by any installer.
#
# Tools
#
# BEGINNING_OF_UTIL_DOT_SH
#!/bin/sh
#
# Copyright (c) 2005-2015 VMware, Inc. All rights reserved.
#
# A few utility functions used by our shell scripts. Some expect the settings
# database to already be loaded and evaluated.
vmblockmntpt="/proc/fs/vmblock/mountPoint"
vmblockfusemntpt="/var/run/vmblock-fuse"
vmware_failed() {
if [ "`type -t 'echo_failure' 2>/dev/null`" = 'function' ]; then
echo_failure
else
echo -n "$rc_failed"
fi
}
vmware_success() {
if [ "`type -t 'echo_success' 2>/dev/null`" = 'function' ]; then
echo_success
else
echo -n "$rc_done"
fi
}
# Execute a macro
vmware_exec() {
local msg="$1" # IN
local func="$2" # IN
shift 2
echo -n ' '"$msg"
# On Caldera 2.2, SIGHUP is sent to all our children when this script exits
# I wanted to use shopt -u huponexit instead but their bash version
# 1.14.7(1) is too old
#
# Ksh does not recognize the SIG prefix in front of a signal name
if [ "$VMWARE_DEBUG" = 'yes' ]; then
(trap '' HUP; "$func" "$@")
else
(trap '' HUP; "$func" "$@") >/dev/null 2>&1
fi
if [ "$?" -gt 0 ]; then
vmware_failed
echo
return 1
fi
vmware_success
echo
return 0
}
# Execute a macro in the background
vmware_bg_exec() {
local msg="$1" # IN
local func="$2" # IN
shift 2
if [ "$VMWARE_DEBUG" = 'yes' ]; then
# Force synchronism when debugging
vmware_exec "$msg" "$func" "$@"
else
echo -n ' '"$msg"' (background)'
# On Caldera 2.2, SIGHUP is sent to all our children when this script exits
# I wanted to use shopt -u huponexit instead but their bash version
# 1.14.7(1) is too old
#
# Ksh does not recognize the SIG prefix in front of a signal name
(trap '' HUP; "$func" "$@") 2>&1 | logger -t 'VMware[init]' -p daemon.err &
vmware_success
echo
return 0
fi
}
# This is a function in case a future product name contains language-specific
# escape characters.
vmware_product_name() {
echo 'VMware Tools'
exit 0
}
# This is a function in case a future product contains language-specific
# escape characters.
vmware_product() {
echo 'tools-for-linux'
exit 0
}
is_dsp()
{
# This is the current way of indicating it is part of a
# distribution-specific install. Currently only applies to Tools.
[ -e "$vmdb_answer_LIBDIR"/dsp ]
}
# They are a lot of small utility programs to create temporary files in a
# secure way, but none of them is standard. So I wrote this
make_tmp_dir() {
local dirname="$1" # OUT
local prefix="$2" # IN
local tmp
local serial
local loop
tmp="${TMPDIR:-/tmp}"
# Don't overwrite existing user data
# -> Create a directory with a name that didn't exist before
#
# This may never succeed (if we are racing with a malicious process), but at
# least it is secure
serial=0
loop='yes'
while [ "$loop" = 'yes' ]; do
# Check the validity of the temporary directory. We do this in the loop
# because it can change over time
if [ ! -d "$tmp" ]; then
echo 'Error: "'"$tmp"'" is not a directory.'
echo
exit 1
fi
if [ ! -w "$tmp" -o ! -x "$tmp" ]; then
echo 'Error: "'"$tmp"'" should be writable and executable.'
echo
exit 1
fi
# Be secure
# -> Don't give write access to other users (so that they can not use this
# directory to launch a symlink attack)
if mkdir -m 0755 "$tmp"'/'"$prefix$serial" >/dev/null 2>&1; then
loop='no'
else
serial=`expr $serial + 1`
serial_mod=`expr $serial % 200`
if [ "$serial_mod" = '0' ]; then
echo 'Warning: The "'"$tmp"'" directory may be under attack.'
echo
fi
fi
done
eval "$dirname"'="$tmp"'"'"'/'"'"'"$prefix$serial"'
}
# Removes "stale" device node
# On udev-based systems, this is never needed.
# On older systems, after an unclean shutdown, we might end up with
# a stale device node while the kernel driver has a new major/minor.
vmware_rm_stale_node() {
local node="$1" # IN
if [ -e "/dev/$node" -a "$node" != "" ]; then
local node_major=`ls -l "/dev/$node" | awk '{print \$5}' | sed -e s/,//`
local node_minor=`ls -l "/dev/$node" | awk '{print \$6}'`
if [ "$node_major" = "10" ]; then
local real_minor=`cat /proc/misc | grep "$node" | awk '{print \$1}'`
if [ "$node_minor" != "$real_minor" ]; then
rm -f "/dev/$node"
fi
else
local node_name=`echo $node | sed -e s/[0-9]*$//`
local real_major=`cat /proc/devices | grep "$node_name" | awk '{print \$1}'`
if [ "$node_major" != "$real_major" ]; then
rm -f "/dev/$node"
fi
fi
fi
}
# Checks if the given pid represents a live process.
# Returns 0 if the pid is a live process, 1 otherwise
vmware_is_process_alive() {
local pid="$1" # IN
ps -p $pid | grep $pid > /dev/null 2>&1
}
# Check if the process associated to a pidfile is running.
# Return 0 if the pidfile exists and the process is running, 1 otherwise
vmware_check_pidfile() {
local pidfile="$1" # IN
local pid
pid=`cat "$pidfile" 2>/dev/null`
if [ "$pid" = '' ]; then
# The file probably does not exist or is empty. Failure
return 1
fi
# Keep only the first number we find, because some Samba pid files are really
# trashy: they end with NUL characters
# There is no double quote around $pid on purpose
set -- $pid
pid="$1"
vmware_is_process_alive $pid
}
# Note:
# . Each daemon must be started from its own directory to avoid busy devices
# . Each PID file doesn't need to be added to the installer database, because
# it is going to be automatically removed when it becomes stale (after a
# reboot). It must go directly under /var/run, or some distributions
# (RedHat 6.0) won't clean it
#
# Terminate a process synchronously
vmware_synchrone_kill() {
local pid="$1" # IN
local signal="$2" # IN
local second
kill -"$signal" "$pid"
# Wait a bit to see if the dirty job has really been done
for second in 0 1 2 3 4 5 6 7 8 9 10; do
vmware_is_process_alive "$pid"
if [ "$?" -ne 0 ]; then
# Success
return 0
fi
sleep 1
done
# Timeout
return 1
}
# Kill the process associated to a pidfile
vmware_stop_pidfile() {
local pidfile="$1" # IN
local pid
pid=`cat "$pidfile" 2>/dev/null`
if [ "$pid" = '' ]; then
# The file probably does not exist or is empty. Success
return 0
fi
# Keep only the first number we find, because some Samba pid files are really
# trashy: they end with NUL characters
# There is no double quote around $pid on purpose
set -- $pid
pid="$1"
# First try a nice SIGTERM
if vmware_synchrone_kill "$pid" 15; then
return 0
fi
# Then send a strong SIGKILL
if vmware_synchrone_kill "$pid" 9; then
return 0
fi
return 1
}
# Determine if SELinux is enabled
isSELinuxEnabled() {
if [ "`cat /selinux/enforce 2> /dev/null`" = "1" ]; then
echo "yes"
else
echo "no"
fi
}
# Runs a command and retries under the provided SELinux context if it fails
vmware_exec_selinux() {
local command="$1"
# XXX We should probably ask the user at install time what context to use
# when we retry commands. unconfined_t is the correct choice for Red Hat.
local context="unconfined_t"
local retval
$command
retval=$?
if [ $retval -ne 0 -a "`isSELinuxEnabled`" = 'yes' ]; then
runcon -t $context -- $command
retval=$?
fi
return $retval
}
# Start the blocking file system. This consists of loading the module and
# mounting the file system.
vmware_start_vmblock() {
mkdir -p -m 1777 /tmp/VMwareDnD
# Try FUSE first, fall back on in-kernel module.
vmware_start_vmblock_fuse && return 0
vmware_exec 'Loading module' vmware_load_module $vmblock
exitcode=`expr $exitcode + $?`
# Check to see if the file system is already mounted.
if grep -q " $vmblockmntpt vmblock " /etc/mtab; then
# If it is mounted, do nothing
true;
else
# If it's not mounted, mount it
vmware_exec_selinux "mount -t vmblock none $vmblockmntpt"
fi
}
# Stop the blocking file system
vmware_stop_vmblock() {
# Check if the file system is mounted and only unmount if so.
# Start with FUSE-based version first, then legacy one.
#
# Vmblock-fuse dev path could be /var/run/vmblock-fuse,
# or /run/vmblock-fuse. Bug 758526.
if grep -q "/run/vmblock-fuse fuse\.vmware-vmblock " /etc/mtab; then
# if it's mounted, then unmount it
vmware_exec_selinux "umount $vmblockfusemntpt"
fi
if grep -q " $vmblockmntpt vmblock " /etc/mtab; then
# if it's mounted, then unmount it
vmware_exec_selinux "umount $vmblockmntpt"
fi
# Unload the kernel module
vmware_unload_module $vmblock
}
# This is necessary to allow udev time to create a device node. If we don't
# wait then udev will override the permissions we choose when it creates the
# device node after us.
vmware_delay_for_node() {
local node="$1"
local delay="$2"
while [ ! -e $node -a ${delay} -gt 0 ]; do
delay=`expr $delay - 1`
sleep 1
done
}
vmware_real_modname() {
# modprobe might be old and not understand the --resolve-alias option, or
# there might not be an alias. In both cases we assume
# that the module is not upstreamed.
mod=$1
mod_alias=$2
modname=$(/sbin/modprobe --resolve-alias ${mod_alias} 2>/dev/null)
if [ $? = 0 -a "$modname" != "" ] ; then
echo $modname
else
echo $mod
fi
}
vmware_is_upstream() {
modname=$1
vmware_exec_selinux "$vmdb_answer_LIBDIR/sbin/vmware-modconfig-console \
--install-status" | grep -q "${modname}: other"
if [ $? = 0 ]; then
echo "yes"
else
echo 'no'
fi
}
# starts after vmci is loaded
vmware_start_vsock() {
real_vmci=$(vmware_real_modname $vmci $vmci_alias)
if [ "`isLoaded "$real_vmci"`" = 'no' ]; then
# vsock depends on vmci
return 1
fi
real_vsock=$(vmware_real_modname $vsock $vsock_alias)
vmware_load_module $real_vsock
vmware_rm_stale_node vsock
# Give udev 5 seconds to create our node
vmware_delay_for_node "/dev/vsock" 5
if [ ! -e /dev/vsock ]; then
local minor=`cat /proc/misc | grep vsock | awk '{print $1}'`
mknod --mode=666 /dev/vsock c 10 "$minor"
else
chmod 666 /dev/vsock
fi
return 0
}
# unloads before vmci
vmware_stop_vsock() {
# Nothing to do if module is upstream
if [ "`vmware_is_upstream $vsock`" = 'yes' ]; then
return 0
fi
real_vsock=$(vmware_real_modname $vsock $vsock_alias)
vmware_unload_module $real_vsock
rm -f /dev/vsock
}
is_ESX_running() {
if [ ! -f "$vmdb_answer_SBINDIR"/vmware-checkvm ] ; then
echo no
return
fi
if "$vmdb_answer_SBINDIR"/vmware-checkvm -p | grep -q ESX; then
echo yes
else
echo no
fi
}
#
# Start vmblock only if ESX is not running and the config script
# built/loaded it (kernel is >= 2.4.0 and product is tools-for-linux).
# Also don't start when in open-vm compat mode
#
is_vmblock_needed() {
if [ "`is_ESX_running`" = 'yes' -o "$vmdb_answer_OPEN_VM_COMPAT" = 'yes' ]; then
echo no
else
if [ "$vmdb_answer_VMBLOCK_CONFED" = 'yes' ]; then
echo yes
else
echo no
fi
fi
}
VMUSR_PATTERN="(vmtoolsd.*vmusr|vmware-user)"
vmware_signal_vmware_user() {
# Signal all running instances of the user daemon.
# Our pattern ensures that we won't touch the system daemon.
pkill -$1 -f "$VMUSR_PATTERN"
return 0
}
# A USR1 causes vmware-user to release any references to vmblock or
# /proc/fs/vmblock/mountPoint, allowing vmblock to unload, but vmware-user
# to continue running. This preserves the user context vmware-user is
# running within.
vmware_unblock_vmware_user() {
vmware_signal_vmware_user 'USR1'
}
# A USR2 causes vmware-user to relaunch itself, picking up vmblock anew.
# This preserves the user context vmware-user is running within.
vmware_restart_vmware_user() {
vmware_signal_vmware_user 'USR2'
}
# Checks if there an instance of vmware-user process exists in the system.
is_vmware_user_running() {
if pgrep -f "$VMUSR_PATTERN" > /dev/null 2>&1; then
echo yes
else
echo no
fi
}
wrap () {
AMSG="$1"
while [ `echo $AMSG | wc -c` -gt 75 ] ; do
AMSG1=`echo $AMSG | sed -e 's/\(.\{1,75\} \).*/\1/' -e 's/ [ ]*/ /'`
AMSG=`echo $AMSG | sed -e 's/.\{1,75\} //' -e 's/ [ ]*/ /'`
echo " $AMSG1"
done
echo " $AMSG"
echo " "
}
#---------------------------------------------------------------------------
#
# load_settings
#
# Load VMware Installer Service settings
#
# Returns:
# 0 on success, otherwise 1.
#
# Side Effects:
# vmdb_* variables are set.
#---------------------------------------------------------------------------
load_settings() {
local settings=`$DATABASE/vmis-settings`
if [ $? -eq 0 ]; then
eval "$settings"
return 0
else
return 1
fi
}
#---------------------------------------------------------------------------
#
# launch_binary
#
# Launch a binary with resolved dependencies.
#
# Returns:
# None.
#
# Side Effects:
# Process is replaced with the binary if successful,
# otherwise returns 1.
#---------------------------------------------------------------------------
launch_binary() {
local component="$1" # IN: component name
shift
local binary="$2" # IN: binary name
shift
local args="$@" # IN: arguments
shift
# Convert -'s in component name to _ and lookup its libdir
local component=`echo $component | tr '-' '_'`
local libdir="vmdb_$component_libdir"
exec "$libdir"'/bin/launcher.sh' \
"$libdir"'/lib' \
"$libdir"'/bin/'"$binary" \
"$libdir"'/libconf' "$args"
return 1
}
# END_OF_UTIL_DOT_SH
# BEGINNING_OF_DB_DOT_SH
#!/bin/sh
#
# Manage an installer database
#
# Add an answer to a database in memory
db_answer_add() {
local dbvar="$1" # IN/OUT
local id="$2" # IN
local value="$3" # IN
local answers
local i
eval "$dbvar"'_answer_'"$id"'="$value"'
eval 'answers="$'"$dbvar"'_answers"'
# There is no double quote around $answers on purpose
for i in $answers; do
if [ "$i" = "$id" ]; then
return
fi
done
answers="$answers"' '"$id"
eval "$dbvar"'_answers="$answers"'
}
# Remove an answer from a database in memory
db_answer_remove() {
local dbvar="$1" # IN/OUT
local id="$2" # IN
local new_answers
local answers
local i
eval 'unset '"$dbvar"'_answer_'"$id"
new_answers=''
eval 'answers="$'"$dbvar"'_answers"'
# There is no double quote around $answers on purpose
for i in $answers; do
if [ "$i" != "$id" ]; then
new_answers="$new_answers"' '"$i"
fi
done
eval "$dbvar"'_answers="$new_answers"'
}
# Load all answers from a database on stdin to memory (