#!/bin/sh # # Copyright 1998 VMware, Inc. All rights reserved. # # vmnet: Manages the services needed to run VMware networking # # description: Manages the services needed to run VMware networking # # chkconfig: 235 90 8 # # probe: true # hide: true subsys=vmnet driver=vmmon vnet=vmnet bridge=vmnet-bridge dhcpd=vmnet-dhcpd netifup=vmnet-netifup natd=vmnet-natd ping=vmware-ping smbd=vmware-smbd nmbd=vmware-nmbd # Source config files vmware_etc_dir=/etc/vmware vmnet_cfg="$vmware_etc_dir"/vmnet.conf VM_BINDIR=/usr/bin for f in $vmnet_cfg; do if [ -r $f ]; then . $f else echo "FATAL: Unable to read $f" exit 1 fi done # System wide functions . /etc/rc.d/init.d/functions # Create /dev/vmnetXX device vmware_create_vmnet() { local vHubNr="$1" # IN local vDevice="/dev/vmnet$vHubNr" if [ ! -e "$vDevice" ]; then mknod -m 600 "$vDevice" c 119 "$vHubNr" fi } # # Create a temporary directory # # They are a lot of small utility programs to create temporary files in a # secure way, but none of them is standard. So I wrote this --hpreg 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` if [ "`expr "$serial" % 200`" = '0' ]; then echo 'Warning: The "'"$tmp"'" directory may be under attack.' echo fi fi done eval "$dirname"'="$tmp"'"'"'/'"'"'"$prefix$serial"' } # # Utilities # # Compute the subnet address associated to a couple IP/netmask ipv4_subnet() { local ip="$1" local netmask="$2" # Split quad-dotted addresses into bytes # There is no double quote around the back-quoted expression on purpose # There is no double quote around $ip and $netmask on purpose set -- `IFS='.'; echo $ip $netmask` echo $(($1 & $5)).$(($2 & $6)).$(($3 & $7)).$(($4 & $8)) } # Compute the broadcast address associated to a couple IP/netmask ipv4_broadcast() { local ip="$1" local netmask="$2" # Split quad-dotted addresses into bytes # There is no double quote around the back-quoted expression on purpose # There is no double quote around $ip and $netmask on purpose set -- `IFS='.'; echo $ip $netmask` echo $(($1 | (255 - $5))).$(($2 | (255 - $6))).$(($3 | (255 - $7))).$(($4 | (255 - $8))) } # Count the number of running virtual machines by looking at the number of references # to the $driver module. countVMs() { # Beware of module dependancies here. An exact match is important /sbin/lsmod | awk 'BEGIN {n = 0;} {if ($1 == "'"$driver"'") n = $3;} END {print n;}' } # Check if there is an IP route for a given subnet via a given interface # Return true if there is _NO_ such route noRoutePresent() { local subnet="$1" # IN local intf="$2" # IN # Beware, there may be several identical routes [ "`/sbin/route -n | grep '^'"$subnet"'.*'"$intf"'$'`" = '' ] } # Macro definitions # # 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 if [ ! -d /proc/"$pid" ]; 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 } # Start the host-only network user service vmware_start_hostonly() { local vHubNr="$1" # IN local vHostIf="$2" # IN local ifIp="$3" # IN local ifMask="$4" # IN local run_dhcpd="$5" # IN local run_samba="$6" # IN local ifNet # Do a cursory check to see if the host-only network # configuration is still ok. We do this so that mobile # hosts don't get setup at install time and then moved to # a new locale where the host-only network config is no # longer valid. # # NB: This really needs to be done at power-on time when # VM is configured to use host-only networking so that # we aren't fooled by dynamic changes in the network. # # XXX ping takes 10 seconds to timeout if nobody answers # that slows boot too much so we do this bit in the # background. if "$VM_BINDIR"/"$ping" -q "$ifIp"; then echo 'Host-only networking disabled because '"$ifIp" echo 'appears to be a real, physical, existing address.' echo 'Please modify your host-only network configuration.' exit 1 fi cd "$VM_BINDIR" && "$VM_BINDIR"/"$netifup" \ -d /var/run/"$netifup"-"$vHostIf".pid /dev/vmnet"$vHubNr" "$vHostIf" [ "$?" -eq 0 ] || exit 1 # Configure the virtual host ethernet interface and define the private IP # network # # . We provide the broadcast address explicitly because versions of ifconfig # prior to 1.39 (1999-03-18) seem to miscompute it # . 2.0.x kernels don't install a route when the interface is marked up, but # 2.2.x kernel do. Since we want to see any errors from route we don't # just discard messages from route, but instead check if the route got # installed before manually adding one. ifNet=`ipv4_subnet "$ifIp" "$ifMask"` if ifconfig "$vHostIf" inet "$ifIp" netmask "$ifMask" \ broadcast "`ipv4_broadcast "$ifIp" "$ifMask"`" up \ && noRoutePresent "$ifNet" "$vHostIf"; then route add -net "$ifNet" netmask "$ifMask" "$vHostIf" fi if [ "$run_dhcpd" = 'yes' ]; then # Start a DHCP server on a private IP network # The daemon already logs its output in the system log, so we can safely # trash it cd "$VM_BINDIR" && "$VM_BINDIR"/"$dhcpd" \ -cf "$vmware_etc_dir"/"$vHostIf"/dhcpd/dhcpd.conf \ -lf "$vmware_etc_dir"/"$vHostIf"/dhcpd/dhcpd.leases \ -pf /var/run/"$dhcpd"-"$vHostIf".pid "$vHostIf" >/dev/null 2>&1 || exit 1 fi if [ "$run_samba" = 'yes' ]; then # Start a SMB name server on a private IP network # Disable logging to avoid the uncontrolled creation of unmanaged files cd "$VM_BINDIR" && "$VM_BINDIR"/"$nmbd" -D -l /dev/null \ -s "$vmware_etc_dir"/"$vHostIf"/smb/smb.conf \ -f /var/run/"$nmbd"-"$vHostIf".pid || exit 1 # Start a SMB share server on a private IP network # Disable logging to avoid the uncontrolled creation of unmanaged files cd "$VM_BINDIR" && "$VM_BINDIR"/"$smbd" -D -l /dev/null \ -s "$vmware_etc_dir"/"$vHostIf"/smb/smb.conf \ -f /var/run/"$smbd"-"$vHostIf".pid || exit 1 fi } # Stop the host-only network user service vmware_stop_hostonly() { local vHostIf="$1" # IN local ifIp="$2" # IN local ifMask="$3" # IN local ifNet # Terminate the private network ifNet=`ipv4_subnet "$ifIp" "$ifMask"` noRoutePresent "$ifNet" "$vHostIf" || route del -net "$ifNet" netmask "$ifMask" || exit 1 # To test if the interface exists, we can not just look at the exitcode # because old versions of ifconfig don't exit with 1 when invoked with a # non-existing interface if [ "`ifconfig "$vHostIf" 2>/dev/null`" != '' ]; then ifconfig "$vHostIf" down || exit 1 fi vmware_stop_pidfile /var/run/"$netifup"-"$vHostIf".pid || exit 1 } # See how we were called. case "$1" in start) if [ -f /var/lock/subsys/"$subsys" ]; then msg_already_running "VMware Workstation networking" fi # Try to load parport_pc. Failure is allowed as it does not exist # on kernels 2.0 /sbin/modprobe parport_pc >/dev/null 2>&1 msg_starting 'Virtual machine monitor' busy /sbin/modprobe $driver [ "$?" -eq "0" ] && ok || fail if [ "$VM_NETWORKING" = 'yes' ]; then msg_starting 'Virtual ethernet' busy /sbin/modprobe $vnet [ "$?" -eq 0 ] && ok || fail vHubNr=0 while [ $vHubNr -lt 9 ]; do eval 'interface="$VNET_'"$vHubNr"'_INTERFACE"' eval 'hostaddr="$VNET_'"$vHubNr"'_HOSTONLY_HOSTADDR"' eval 'netmask="$VNET_'"$vHubNr"'_HOSTONLY_NETMASK"' if [ -n "$interface" ]; then vmware_create_vmnet "$vHubNr" # Connect a physical host ethernet interface to a virtual ethernet hub msg_starting 'Bridged networking on /dev/vmnet'"$vHubNr" busy cd "$VM_BINDIR" && "$VM_BINDIR"/"$bridge" \ -d /var/run/"$bridge"-"$vHubNr".pid /dev/vmnet"$vHubNr" "$interface" [ "$?" -eq 0 ] && ok || fail elif [ -n "$hostaddr" -a -n "$netmask" ]; then vmware_create_vmnet "$vHubNr" eval 'samba="$VNET_'"$vHubNr"'_SAMBA"' msg_starting 'Host-only networking on /dev/vmnet'"$vHubNr" busy vmware_start_hostonly "$vHubNr" 'vmnet'"$vHubNr" "$hostaddr" \ "$netmask" 'yes' "$samba" [ "$?" -eq 0 ] && ok || fail eval 'nat="$VNET_'"$vHubNr"'_NAT"' if [ "$nat" = 'yes' ]; then # Start the NAT network user service msg_starting 'NAT networking on /dev/vmnet'"$vHubNr" busy cd "$VM_BINDIR" && "$VM_BINDIR"/"$natd" \ -d /var/run/"$natd"-"$vHubNr".pid \ -m /var/run/"$natd"-"$vHubNr".mac \ -c "$vmware_etc_dir"/vmnet"$vHubNr"/nat/nat.conf >/dev/null 2>&1 [ "$?" -eq 0 ] && ok || fail fi fi vHubNr=$(($vHubNr + 1)) done fi touch /var/lock/subsys/"$subsys" ;; stop) if [ "`countVMs`" -gt 0 ]; then echo 'At least one instance of VMware Workstation is still running.' echo 'Please stop all running instances of VMware Workstation first.' echo fi if [ ! -f /var/lock/subsys/"$subsys" ]; then msg_not_running "VMware Workstation networking" fi # Try to unload parport_pc. Failure is allowed as it does not exist # on kernels 2.0, and some other process could be using it. /sbin/modprobe -r parport_pc >/dev/null 2>&1 if [ "$VM_NETWORKING" = "yes" ]; then # NB: must kill off processes using vmnet before # unloading module vHubNr=0 while [ $vHubNr -lt 9 ]; do eval 'interface="$VNET_'"$vHubNr"'_INTERFACE"' eval 'hostaddr="$VNET_'"$vHubNr"'_HOSTONLY_HOSTADDR"' eval 'netmask="$VNET_'"$vHubNr"'_HOSTONLY_NETMASK"' if [ -n "$interface" ]; then # Disconnect a physical host ethernet interface from a virtual ethernet hub msg_stopping "Bridged networking on /dev/vmnet$vHubNr" busy vmware_stop_pidfile /var/run/"$bridge"-"$vHubNr".pid [ "$?" -eq 0 ] && ok || fail elif [ -n "$hostaddr" -a -n "$netmask" ]; then # Stop a DHCP server on a private IP network msg_stopping "DHCP server on /dev/vmnet$vHubNr" busy vmware_stop_pidfile /var/run/"$dhcpd"-"vmnet$vHubNr".pid [ "$?" -eq 0 ] && ok || fail eval 'samba="$VNET_'"$vHubNr"'_SAMBA"' if [ "$samba" = "yes" ]; then # Stop a SMB share server on a private IP network msg_stopping 'SMB share server on /dev/vmnet'"$vHubNr" busy vmware_stop_pidfile /var/run/"$smbd"-'vmnet'"$vHubNr".pid [ "$?" -eq 0 ] && ok || fail # Stop a SMB name server on a private IP network msg_stopping 'SMB name server on /dev/vmnet'"$vHubNr" busy vmware_stop_pidfile /var/run/"$nmbd"-'vmnet'"$vHubNr".pid [ "$?" -eq 0 ] && ok || fail fi eval 'nat="$VNET_'"$vHubNr"'_NAT"' if [ "$nat" = "yes" ]; then # Stop the NAT network user service msg_stopping 'NAT networking on /dev/vmnet'"$vHubNr" busy vmware_stop_pidfile /var/run/"$natd"-"$vHubNr".pid [ "$?" -eq 0 ] && ok || fail fi msg_stopping 'Host-only networking on /dev/vmnet'"$vHubNr" busy vmware_stop_hostonly 'vmnet'"$vHubNr" "$hostaddr" "$netmask" [ "$?" -eq 0 ] && ok || fail fi vHubNr=$(($vHubNr + 1)) done msg_stopping 'Virtual machine monitor' busy if /sbin/lsmod | grep -q ^"$driver"; then /sbin/rmmod "$driver" fi [ "$?" -eq "0" ] && ok || fail msg_stopping 'Virtual ethernet' busy if /sbin/lsmod | grep -q ^"$vnet"; then /sbin/rmmod "$vnet" fi [ "$?" -eq "0" ] && ok || fail fi rm -f /var/lock/subsys/"$subsys" ;; status) if [ "`countVMs`" -gt 0 ]; then echo 'At least one instance of VMware Workstation is still running.' echo fi if [ "$VM_NETWORKING" = "yes" ]; then status "$bridge" status "$dhcpd" status "$netifup" fi if [ "$VM_NETWORKING" = "yes" ]; then echo -n "Module $vnet " /sbin/modprobe "$vnet" >/dev/null 2>&1 && echo installed || echo "not installed" fi ;; restart) "$0" stop && "$0" start ;; *) echo "Usage: `basename "$0"` {start|stop|status|restart}" exit 3 esac exit 0