]>
Commit | Line | Data |
---|---|---|
29328d5b | 1 | #!/bin/sh |
36b33dd9 | 2 | |
29328d5b | 3 | # |
4 | # Copyright 1998 VMware, Inc. All rights reserved. | |
5 | # | |
6 | ||
d18baea8 | 7 | # vmnet: Manages the services needed to run VMware networking |
29328d5b | 8 | # |
d18baea8 | 9 | # description: Manages the services needed to run VMware networking |
a2c5e0b7 | 10 | # |
11 | # chkconfig: 5 90 8 | |
12 | # | |
13 | # probe: true | |
14 | # hide: true | |
15 | ||
a19ca04e | 16 | subsys=vmnet |
345c7964 | 17 | driver=vmmon |
18 | vnet=vmnet | |
19 | bridge=vmnet-bridge | |
20 | dhcpd=vmnet-dhcpd | |
21 | netifup=vmnet-netifup | |
22 | natd=vmnet-natd | |
23 | ping=vmware-ping | |
24 | smbd=vmware-smbd | |
25 | nmbd=vmware-nmbd | |
29328d5b | 26 | |
efe88284 | 27 | # Source config files |
36b33dd9 | 28 | vmware_etc_dir=/etc/vmware |
efe88284 | 29 | vmware_locations="$vmware_etc_dir"/locations |
2e3c2f73 | 30 | vmnet_cfg="$vmware_etc_dir"/vmnet.conf |
efe88284 | 31 | |
32 | for f in $vmware_locations $vmnet_cfg; do | |
33 | if [ -r $f ]; then | |
34 | . $f | |
35 | else | |
36 | echo "FATAL: Unable to read $f" | |
37 | exit 1 | |
38 | fi | |
39 | done | |
36b33dd9 | 40 | |
41 | # System wide functions | |
42 | . /etc/rc.d/init.d/functions | |
43 | ||
29328d5b | 44 | # |
345c7964 | 45 | # Create a temporary directory |
29328d5b | 46 | # |
47 | ||
345c7964 | 48 | # They are a lot of small utility programs to create temporary files in a |
49 | # secure way, but none of them is standard. So I wrote this --hpreg | |
50 | make_tmp_dir() { | |
51 | local dirname="$1" # OUT | |
52 | local prefix="$2" # IN | |
53 | local tmp | |
54 | local serial | |
55 | local loop | |
56 | ||
57 | tmp="${TMPDIR:-/tmp}" | |
345c7964 | 58 | # Don't overwrite existing user data |
59 | # -> Create a directory with a name that didn't exist before | |
60 | # | |
61 | # This may never succeed (if we are racing with a malicious process), but at | |
62 | # least it is secure | |
63 | serial=0 | |
64 | loop='yes' | |
65 | while [ "$loop" = 'yes' ]; do | |
66 | # Check the validity of the temporary directory. We do this in the loop | |
67 | # because it can change over time | |
68 | if [ ! -d "$tmp" ]; then | |
3e0d5b52 | 69 | echo 'Error: "'"$tmp"'" is not a directory.' |
70 | echo | |
71 | exit 1 | |
345c7964 | 72 | fi |
73 | if [ ! -w "$tmp" -o ! -x "$tmp" ]; then | |
3e0d5b52 | 74 | echo 'Error: "'"$tmp"'" should be writable and executable.' |
75 | echo | |
76 | exit 1 | |
345c7964 | 77 | fi |
78 | # Be secure | |
79 | # -> Don't give write access to other users (so that they can not use this | |
80 | # directory to launch a symlink attack) | |
81 | if mkdir -m 0755 "$tmp"'/'"$prefix$serial" >/dev/null 2>&1; then | |
3e0d5b52 | 82 | loop='no' |
345c7964 | 83 | else |
3e0d5b52 | 84 | serial=`expr "$serial" + 1` |
85 | if [ "`expr "$serial" % 200`" = '0' ]; then | |
86 | echo 'Warning: The "'"$tmp"'" directory may be under attack.' | |
87 | echo | |
88 | fi | |
345c7964 | 89 | fi |
90 | done | |
91 | eval "$dirname"'="$tmp"'"'"'/'"'"'"$prefix$serial"' | |
92 | } | |
29328d5b | 93 | |
29328d5b | 94 | # |
36b33dd9 | 95 | # Utilities |
29328d5b | 96 | # |
345c7964 | 97 | |
29328d5b | 98 | # Compute the subnet address associated to a couple IP/netmask |
99 | ipv4_subnet() { | |
345c7964 | 100 | local ip="$1" |
101 | local netmask="$2" | |
29328d5b | 102 | |
345c7964 | 103 | # Split quad-dotted addresses into bytes |
104 | # There is no double quote around the back-quoted expression on purpose | |
105 | # There is no double quote around $ip and $netmask on purpose | |
106 | set -- `IFS='.'; echo $ip $netmask` | |
107 | echo $(($1 & $5)).$(($2 & $6)).$(($3 & $7)).$(($4 & $8)) | |
29328d5b | 108 | } |
109 | ||
110 | # Compute the broadcast address associated to a couple IP/netmask | |
111 | ipv4_broadcast() { | |
345c7964 | 112 | local ip="$1" |
113 | local netmask="$2" | |
29328d5b | 114 | |
345c7964 | 115 | # Split quad-dotted addresses into bytes |
116 | # There is no double quote around the back-quoted expression on purpose | |
117 | # There is no double quote around $ip and $netmask on purpose | |
118 | set -- `IFS='.'; echo $ip $netmask` | |
119 | echo $(($1 | (255 - $5))).$(($2 | (255 - $6))).$(($3 | (255 - $7))).$(($4 | (255 - $8))) | |
29328d5b | 120 | } |
121 | ||
36b33dd9 | 122 | # Count the number of running virtual machines by looking at the number of references |
123 | # to the $driver module. | |
29328d5b | 124 | countVMs() { |
345c7964 | 125 | # Beware of module dependancies here. An exact match is important |
126 | /sbin/lsmod | awk 'BEGIN {n = 0;} {if ($1 == "'"$driver"'") n = $3;} END {print n;}' | |
29328d5b | 127 | } |
128 | ||
29328d5b | 129 | # Check if there is an IP route for a given subnet via a given interface |
130 | # Return true if there is _NO_ such route | |
131 | noRoutePresent() { | |
345c7964 | 132 | local subnet="$1" # IN |
133 | local intf="$2" # IN | |
29328d5b | 134 | |
345c7964 | 135 | # Beware, there may be several identical routes |
136 | [ "`/sbin/route -n | grep '^'"$subnet"'.*'"$intf"'$'`" = '' ] | |
29328d5b | 137 | } |
138 | ||
29328d5b | 139 | |
29328d5b | 140 | # Macro definitions |
141 | # | |
142 | # Note: | |
143 | # . Each daemon must be started from its own directory to avoid busy devices | |
144 | # . Each PID file doesn't need to be added to the installer database, because | |
145 | # it is going to be automatically removed when it becomes stale (after a | |
146 | # reboot). It must go directly under /var/run, or some distributions | |
147 | # (RedHat 6.0) won't clean it | |
148 | # | |
149 | ||
150 | # Terminate a process synchronously | |
151 | vmware_synchrone_kill() { | |
345c7964 | 152 | local pid="$1" # IN |
153 | local signal="$2" # IN | |
154 | local second | |
155 | ||
156 | kill -"$signal" "$pid" | |
157 | # Wait a bit to see if the dirty job has really been done | |
158 | for second in 0 1 2 3 4 5 6 7 8 9 10; do | |
159 | if [ ! -d /proc/"$pid" ]; then | |
3e0d5b52 | 160 | # Success |
161 | return 0 | |
345c7964 | 162 | fi |
163 | sleep 1 | |
164 | done | |
3e0d5b52 | 165 | # Timeout |
345c7964 | 166 | return 1 |
29328d5b | 167 | } |
168 | ||
169 | # Kill the process associated to a pidfile | |
170 | vmware_stop_pidfile() { | |
345c7964 | 171 | local pidfile="$1" # IN |
172 | local pid | |
29328d5b | 173 | |
345c7964 | 174 | pid=`cat "$pidfile" 2>/dev/null` |
175 | if [ "$pid" = '' ]; then | |
176 | # The file probably does not exist or is empty. Success | |
177 | return 0 | |
178 | fi | |
179 | # Keep only the first number we find, because some Samba pid files are really | |
180 | # trashy: they end with NUL characters | |
181 | # There is no double quote around $pid on purpose | |
182 | set -- $pid | |
183 | pid="$1" | |
184 | # First try a nice SIGTERM | |
185 | if vmware_synchrone_kill "$pid" 15; then | |
186 | return 0 | |
187 | fi | |
188 | # Then send a strong SIGKILL | |
189 | if vmware_synchrone_kill "$pid" 9; then | |
190 | return 0 | |
191 | fi | |
192 | return 1 | |
29328d5b | 193 | } |
194 | ||
29328d5b | 195 | # Start the host-only network user service |
196 | vmware_start_hostonly() { | |
345c7964 | 197 | local vHubNr="$1" # IN |
198 | local vHostIf="$2" # IN | |
199 | local ifIp="$3" # IN | |
200 | local ifMask="$4" # IN | |
201 | local run_dhcpd="$5" # IN | |
202 | local run_samba="$6" # IN | |
203 | local ifNet | |
204 | ||
205 | # Do a cursory check to see if the host-only network | |
206 | # configuration is still ok. We do this so that mobile | |
207 | # hosts don't get setup at install time and then moved to | |
208 | # a new locale where the host-only network config is no | |
209 | # longer valid. | |
210 | # | |
211 | # NB: This really needs to be done at power-on time when | |
212 | # VM is configured to use host-only networking so that | |
213 | # we aren't fooled by dynamic changes in the network. | |
214 | # | |
215 | # XXX ping takes 10 seconds to timeout if nobody answers | |
216 | # that slows boot too much so we do this bit in the | |
217 | # background. | |
efe88284 | 218 | if "$VM_BINDIR"/"$ping" -q "$ifIp"; then |
345c7964 | 219 | echo 'Host-only networking disabled because '"$ifIp" |
220 | echo 'appears to be a real, physical, existing address.' | |
36b33dd9 | 221 | echo 'Please modify your host-only network configuration.' |
345c7964 | 222 | exit 1 |
223 | fi | |
efe88284 | 224 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$netifup" \ |
3e0d5b52 | 225 | -d /var/run/"$netifup"-"$vHostIf".pid /dev/vmnet"$vHubNr" "$vHostIf" |
345c7964 | 226 | [ "$?" -eq 0 ] || exit 1 |
227 | # Configure the virtual host ethernet interface and define the private IP | |
228 | # network | |
229 | # | |
230 | # . We provide the broadcast address explicitly because versions of ifconfig | |
231 | # prior to 1.39 (1999-03-18) seem to miscompute it | |
232 | # . 2.0.x kernels don't install a route when the interface is marked up, but | |
233 | # 2.2.x kernel do. Since we want to see any errors from route we don't | |
234 | # just discard messages from route, but instead check if the route got | |
235 | # installed before manually adding one. | |
236 | ifNet=`ipv4_subnet "$ifIp" "$ifMask"` | |
3e0d5b52 | 237 | if ifconfig "$vHostIf" inet "$ifIp" netmask "$ifMask" \ |
238 | broadcast "`ipv4_broadcast "$ifIp" "$ifMask"`" up \ | |
239 | && noRoutePresent "$ifNet" "$vHostIf"; then | |
240 | route add -net "$ifNet" netmask "$ifMask" "$vHostIf" | |
241 | fi | |
242 | if [ "$run_dhcpd" = 'yes' ]; then | |
243 | # Start a DHCP server on a private IP network | |
244 | # The daemon already logs its output in the system log, so we can safely | |
245 | # trash it | |
246 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$dhcpd" \ | |
247 | -cf "$vmware_etc_dir"/"$vHostIf"/dhcpd/dhcpd.conf \ | |
248 | -lf "$vmware_etc_dir"/"$vHostIf"/dhcpd/dhcpd.leases \ | |
249 | -pf /var/run/"$dhcpd"-"$vHostIf".pid "$vHostIf" >/dev/null 2>&1 || exit 1 | |
250 | fi | |
251 | if [ "$run_samba" = 'yes' ]; then | |
252 | # Start a SMB name server on a private IP network | |
253 | # Disable logging to avoid the uncontrolled creation of unmanaged files | |
254 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$nmbd" -D -l /dev/null \ | |
255 | -s "$vmware_etc_dir"/"$vHostIf"/smb/smb.conf \ | |
256 | -f /var/run/"$nmbd"-"$vHostIf".pid || exit 1 | |
257 | # Start a SMB share server on a private IP network | |
258 | # Disable logging to avoid the uncontrolled creation of unmanaged files | |
259 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$smbd" -D -l /dev/null \ | |
260 | -s "$vmware_etc_dir"/"$vHostIf"/smb/smb.conf \ | |
261 | -f /var/run/"$smbd"-"$vHostIf".pid || exit 1 | |
262 | fi | |
29328d5b | 263 | } |
264 | ||
265 | # Stop the host-only network user service | |
266 | vmware_stop_hostonly() { | |
345c7964 | 267 | local vHostIf="$1" # IN |
268 | local ifIp="$2" # IN | |
269 | local ifMask="$3" # IN | |
270 | local ifNet | |
271 | ||
272 | # Terminate the private network | |
273 | ifNet=`ipv4_subnet "$ifIp" "$ifMask"` | |
3e0d5b52 | 274 | noRoutePresent "$ifNet" "$vHostIf" || route del -net "$ifNet" netmask "$ifMask" || exit 1 |
345c7964 | 275 | # To test if the interface exists, we can not just look at the exitcode |
276 | # because old versions of ifconfig don't exit with 1 when invoked with a | |
277 | # non-existing interface | |
278 | if [ "`ifconfig "$vHostIf" 2>/dev/null`" != '' ]; then | |
279 | ifconfig "$vHostIf" down || exit 1 | |
280 | fi | |
281 | vmware_stop_pidfile /var/run/"$netifup"-"$vHostIf".pid || exit 1 | |
29328d5b | 282 | } |
283 | ||
29328d5b | 284 | # See how we were called. |
285 | case "$1" in | |
286 | start) | |
2e3c2f73 | 287 | if [ -f /var/lock/subsys/"$subsys" ]; then |
288 | msg_already_running "VMware Workstation networking" | |
2e3c2f73 | 289 | fi |
3e0d5b52 | 290 | # Try to load parport_pc. Failure is allowed as it does not exist |
291 | # on kernels 2.0 | |
292 | /sbin/modprobe parport_pc >/dev/null 2>&1 | |
2e3c2f73 | 293 | if [ "$VM_NETWORKING" = 'yes' ]; then |
a5a25ae1 | 294 | msg_starting 'Virtual ethernet' |
295 | busy | |
345c7964 | 296 | /sbin/modprobe $vnet |
a5a25ae1 | 297 | [ "$?" -eq 0 ] && ok || fail |
a5a25ae1 | 298 | vHubNr=0 |
3c42bb59 | 299 | while [ $vHubNr -lt 8 ]; do |
3e0d5b52 | 300 | eval 'interface="$VNET_'"$vHubNr"'_INTERFACE"' |
301 | eval 'hostaddr="$VNET_'"$vHubNr"'_HOSTONLY_HOSTADDR"' | |
302 | eval 'netmask="$VNET_'"$vHubNr"'_HOSTONLY_NETMASK"' | |
a5a25ae1 | 303 | if [ -n "$interface" ]; then |
345c7964 | 304 | # Connect a physical host ethernet interface to a virtual ethernet hub |
3e0d5b52 | 305 | msg_starting 'Bridged networking on /dev/vmnet'"$vHubNr" |
a5a25ae1 | 306 | busy |
efe88284 | 307 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$bridge" \ |
3e0d5b52 | 308 | -d /var/run/"$bridge"-"$vHubNr".pid /dev/vmnet"$vHubNr" "$interface" |
a5a25ae1 | 309 | [ "$?" -eq 0 ] && ok || fail |
a5a25ae1 | 310 | elif [ -n "$hostaddr" -a -n "$netmask" ]; then |
2e3c2f73 | 311 | eval 'samba="$VNET_'"$vHubNr"'_SAMBA"' |
3e0d5b52 | 312 | msg_starting 'Host-only networking on /dev/vmnet'"$vHubNr" |
345c7964 | 313 | busy |
3e0d5b52 | 314 | daemon vmware_start_hostonly "$vHubNr" 'vmnet'"$vHubNr" "$hostaddr" \ |
315 | "$netmask" 'yes' "$samba" | |
345c7964 | 316 | [ "$?" -eq 0 ] && ok || fail |
2e3c2f73 | 317 | eval 'nat="$VNET_'"$vHubNr"'_NAT"' |
3e0d5b52 | 318 | if [ "$nat" = 'yes' ]; then |
36b33dd9 | 319 | # Start the NAT network user service |
345c7964 | 320 | msg_starting 'NAT networking on /dev/vmnet'"$vHubNr" |
321 | busy | |
efe88284 | 322 | cd "$VM_BINDIR" && "$VM_BINDIR"/"$natd" \ |
3e0d5b52 | 323 | -d /var/run/"$natd"-"$vHubNr".pid \ |
324 | -m /var/run/"$natd"-"$vHubNr".mac \ | |
325 | -c "$vmware_etc_dir"/vmnet"$vHubNr"/nat/nat.conf | |
345c7964 | 326 | [ "$?" -eq 0 ] && ok || fail |
3e0d5b52 | 327 | fi |
a5a25ae1 | 328 | fi |
3e0d5b52 | 329 | vHubNr=$(($vHubNr + 1)) |
a5a25ae1 | 330 | done |
29328d5b | 331 | fi |
29328d5b | 332 | touch /var/lock/subsys/"$subsys" |
333 | ;; | |
334 | ||
335 | stop) | |
3e0d5b52 | 336 | if [ "`countVMs`" -gt 0 ]; then |
337 | echo 'At least one instance of VMware Workstation is still running.' | |
36b33dd9 | 338 | echo 'Please stop all running instances of VMware Workstation first.' |
345c7964 | 339 | echo |
29328d5b | 340 | fi |
2e3c2f73 | 341 | if [ ! -f /var/lock/subsys/"$subsys" ]; then |
342 | msg_not_running "VMware Workstation networking" | |
2e3c2f73 | 343 | fi |
3e0d5b52 | 344 | # Try to unload parport_pc. Failure is allowed as it does not exist |
345 | # on kernels 2.0, and some other process could be using it. | |
346 | /sbin/modprobe -r parport_pc >/dev/null 2>&1 | |
2e3c2f73 | 347 | if [ "$VM_NETWORKING" = "yes" ]; then |
a5a25ae1 | 348 | # NB: must kill off processes using vmnet before |
349 | # unloading module | |
350 | vHubNr=0 | |
3c42bb59 | 351 | while [ $vHubNr -lt 8 ]; do |
3e0d5b52 | 352 | eval 'interface="$VNET_'"$vHubNr"'_INTERFACE"' |
353 | eval 'hostaddr="$VNET_'"$vHubNr"'_HOSTONLY_HOSTADDR"' | |
354 | eval 'netmask="$VNET_'"$vHubNr"'_HOSTONLY_NETMASK"' | |
a5a25ae1 | 355 | if [ -n "$interface" ]; then |
345c7964 | 356 | # Disconnect a physical host ethernet interface from a virtual ethernet hub |
3e0d5b52 | 357 | msg_stopping "Bridged networking on /dev/vmnet$vHubNr" |
a5a25ae1 | 358 | busy |
345c7964 | 359 | vmware_stop_pidfile /var/run/"$bridge"-"$vHubNr".pid |
a5a25ae1 | 360 | [ "$?" -eq 0 ] && ok || fail |
a5a25ae1 | 361 | elif [ -n "$hostaddr" -a -n "$netmask" ]; then |
36b33dd9 | 362 | # Stop a DHCP server on a private IP network |
345c7964 | 363 | msg_stopping "DHCP server on /dev/vmnet$vHubNr" |
364 | busy | |
36b33dd9 | 365 | vmware_stop_pidfile /var/run/"$dhcpd"-"vmnet$vHubNr".pid |
345c7964 | 366 | [ "$?" -eq 0 ] && ok || fail |
2e3c2f73 | 367 | eval 'samba="$VNET_'"$vHubNr"'_SAMBA"' |
3e0d5b52 | 368 | if [ "$samba" = "yes" ]; then |
36b33dd9 | 369 | # Stop a SMB share server on a private IP network |
3e0d5b52 | 370 | msg_stopping 'SMB share server on /dev/vmnet'"$vHubNr" |
345c7964 | 371 | busy |
36b33dd9 | 372 | vmware_stop_pidfile /var/run/"$smbd"-'vmnet'"$vHubNr".pid |
345c7964 | 373 | [ "$?" -eq 0 ] && ok || fail |
36b33dd9 | 374 | # Stop a SMB name server on a private IP network |
3e0d5b52 | 375 | msg_stopping 'SMB name server on /dev/vmnet'"$vHubNr" |
345c7964 | 376 | busy |
36b33dd9 | 377 | vmware_stop_pidfile /var/run/"$nmbd"-'vmnet'"$vHubNr".pid |
345c7964 | 378 | [ "$?" -eq 0 ] && ok || fail |
a5a25ae1 | 379 | fi |
2e3c2f73 | 380 | eval 'nat="$VNET_'"$vHubNr"'_NAT"' |
3e0d5b52 | 381 | if [ "$nat" = "yes" ]; then |
382 | # Stop the NAT network user service | |
383 | msg_stopping 'NAT networking on /dev/vmnet'"$vHubNr" | |
345c7964 | 384 | busy |
3e0d5b52 | 385 | vmware_stop_pidfile /var/run/"$natd"-"$vHubNr".pid |
345c7964 | 386 | [ "$?" -eq 0 ] && ok || fail |
3e0d5b52 | 387 | fi |
388 | msg_stopping 'Host-only networking on /dev/vmnet'"$vHubNr" | |
389 | busy | |
390 | vmware_stop_hostonly 'vmnet'"$vHubNr" "$hostaddr" "$netmask" | |
391 | [ "$?" -eq 0 ] && ok || fail | |
a5a25ae1 | 392 | |
393 | fi | |
3e0d5b52 | 394 | vHubNr=$(($vHubNr + 1)) |
a5a25ae1 | 395 | done |
396 | msg_stopping 'Virtual ethernet' | |
397 | busy | |
36b33dd9 | 398 | if /sbin/lsmod | grep -q ^"$vnet"; then |
3e0d5b52 | 399 | /sbin/rmmod "$vnet" |
345c7964 | 400 | fi |
a5a25ae1 | 401 | [ "$?" -eq "0" ] && ok || fail |
3e0d5b52 | 402 | fi |
29328d5b | 403 | rm -f /var/lock/subsys/"$subsys" |
404 | ;; | |
29328d5b | 405 | status) |
3e0d5b52 | 406 | if [ "`countVMs`" -gt 0 ]; then |
407 | echo 'At least one instance of VMware Workstation is still running.' | |
408 | echo | |
29328d5b | 409 | fi |
2e3c2f73 | 410 | if [ "$VM_NETWORKING" = "yes" ]; then |
3e0d5b52 | 411 | status "$bridge" |
412 | status "$dhcpd" | |
413 | status "$netifup" | |
414 | fi | |
2e3c2f73 | 415 | if [ "$VM_NETWORKING" = "yes" ]; then |
3e0d5b52 | 416 | echo -n "Module $vnet " |
417 | /sbin/modprobe "$vnet" >/dev/null 2>&1 && echo installed || echo "not installed" | |
418 | fi | |
29328d5b | 419 | ;; |
29328d5b | 420 | restart) |
421 | "$0" stop && "$0" start | |
422 | ;; | |
29328d5b | 423 | *) |
424 | echo "Usage: `basename "$0"` {start|stop|status|restart}" | |
3e0d5b52 | 425 | exit 3 |
29328d5b | 426 | esac |
427 | ||
428 | exit 0 |