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