1 |
#!/bin/sh
|
2 |
#
|
3 |
# Copyright (c) 2002, Valve LLC. All rights reserved.
|
4 |
#
|
5 |
# a wrapper script for the main hl dedicated server binary.
|
6 |
# Performs auto-restarting of the server on crash. You can
|
7 |
# extend this to log crashes and more.
|
8 |
#
|
9 |
|
10 |
# setup the libraries, local dir first!
|
11 |
export LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH"
|
12 |
|
13 |
init() {
|
14 |
# Initialises the various variables
|
15 |
# Set up the defaults
|
16 |
GAME="valve"
|
17 |
DEBUG=0
|
18 |
RESTART="yes"
|
19 |
HL=./hlds_i486
|
20 |
HL_DETECT=1
|
21 |
TIMEOUT=10 # time to wait after a crash (in seconds)
|
22 |
CRASH_DEBUG_MSG="email debug.log to linux@valvesoftware.com"
|
23 |
GDB="gdb" # the gdb binary to run
|
24 |
DEBUG_LOG="debug.log"
|
25 |
PID_FILE=""
|
26 |
STEAM=""
|
27 |
STEAMERR=""
|
28 |
SIGINT_ACTION="quit 0" # exit normally on sig int
|
29 |
NO_TRAP=0
|
30 |
AUTO_UPDATE=""
|
31 |
BETA_VERSION=""
|
32 |
PARAMS=$*
|
33 |
|
34 |
# Remove any old default pid files
|
35 |
# Cant do this as they may be still running
|
36 |
#rm -f hlds.*.pid
|
37 |
|
38 |
# use the $FORCE environment variable if its set
|
39 |
if test -n "$FORCE" ; then
|
40 |
# Note: command line -binary will override this
|
41 |
HL=$FORCE
|
42 |
HL_DETECT=0
|
43 |
fi
|
44 |
|
45 |
while test $# -gt 0; do
|
46 |
case "$1" in
|
47 |
"-game")
|
48 |
GAME="$2"
|
49 |
shift ;;
|
50 |
"-debug")
|
51 |
DEBUG=1
|
52 |
# Ensure that PID_FILE is set
|
53 |
if test -z "$PID_FILE"; then
|
54 |
PID_FILE="hlds.$$.pid"
|
55 |
fi ;;
|
56 |
"-norestart")
|
57 |
RESTART="" ;;
|
58 |
"-pidfile")
|
59 |
PID_FILE="$2"
|
60 |
shift ;;
|
61 |
"-binary")
|
62 |
HL="$2"
|
63 |
HL_DETECT=0
|
64 |
shift ;;
|
65 |
"-timeout")
|
66 |
TIMEOUT="$2"
|
67 |
shift ;;
|
68 |
"-gdb")
|
69 |
GDB="$2"
|
70 |
shift ;;
|
71 |
"-debuglog")
|
72 |
DEBUG_LOG="$2"
|
73 |
shift ;;
|
74 |
"-autoupdate")
|
75 |
AUTO_UPDATE="yes"
|
76 |
STEAM="./steam"
|
77 |
RESTART="yes" ;;
|
78 |
"-steamerr")
|
79 |
STEAMERR=1 ;;
|
80 |
"-ignoresigint")
|
81 |
SIGINT_ACTION="" ;;
|
82 |
"-notrap")
|
83 |
NO_TRAP=1 ;;
|
84 |
"-beta")
|
85 |
BETA_VERSION="$2";
|
86 |
shift ;;
|
87 |
"-help")
|
88 |
# quit with syntax
|
89 |
quit 2
|
90 |
;;
|
91 |
esac
|
92 |
shift
|
93 |
done
|
94 |
|
95 |
# Ensure we have a game specified
|
96 |
if test -z "$GAME"; then
|
97 |
echo "Unable to determine game type from command line."
|
98 |
quit 1
|
99 |
elif test ! -d "$GAME"; then
|
100 |
echo "Invalid game type '$GAME' sepecified."
|
101 |
quit 1
|
102 |
fi
|
103 |
|
104 |
if test 0 -eq "$NO_TRAP"; then
|
105 |
# Set up the int handler
|
106 |
# N.B. Dont use SIGINT symbolic value
|
107 |
# as its just INT under ksh
|
108 |
trap "$SIGINT_ACTION" 2
|
109 |
fi
|
110 |
|
111 |
# Only detect the CPU if it hasnt been set with
|
112 |
# either environment or command line
|
113 |
if test "$HL_DETECT" -eq 1; then
|
114 |
detectcpu
|
115 |
fi
|
116 |
|
117 |
if test ! -f "$HL"; then
|
118 |
echo "Half-life binary '$HL' not found, exiting"
|
119 |
quit 1
|
120 |
elif test ! -x "$HL"; then
|
121 |
# Could try chmod but dont know what we will be
|
122 |
# chmoding so just fail.
|
123 |
echo "Half-life binary '$HL' not executable, exiting"
|
124 |
quit 1
|
125 |
fi
|
126 |
|
127 |
# Setup debugging
|
128 |
if test "$DEBUG" -eq 1; then
|
129 |
#turn on core dumps :) (if possible)
|
130 |
echo "Enabling debug mode"
|
131 |
if test "`ulimit -c`" -eq 0 ; then
|
132 |
ulimit -c 2000
|
133 |
fi
|
134 |
GDB_TEST=`$GDB -v`
|
135 |
if test -z "$GDB_TEST"; then
|
136 |
echo "Please install gdb first."
|
137 |
echo "goto http://www.gnu.org/software/gdb/ "
|
138 |
DEBUG=0 # turn off debugging cause gdb isn't installed
|
139 |
fi
|
140 |
fi
|
141 |
|
142 |
PID_IN_PARAMS="`echo $PARAMS | grep -e -pidfile`"
|
143 |
|
144 |
if test -z "$PID_IN_PARAMS" && test -n "$PID_FILE"; then
|
145 |
HL_CMD="$HL $PARAMS -pidfile $PID_FILE"
|
146 |
else
|
147 |
HL_CMD="$HL $PARAMS"
|
148 |
fi
|
149 |
}
|
150 |
|
151 |
syntax () {
|
152 |
# Prints script syntax
|
153 |
|
154 |
echo "Syntax:"
|
155 |
echo "$0 [-game <game>] [-debug] [-norestart] [-pidfile]"
|
156 |
echo " [-binary [hlds_i486|hlds_i686|hlds_amd]"
|
157 |
echo " [-timeout <number>] [-gdb <gdb>] [-autoupdate]"
|
158 |
echo " [-steamerr] [-ignoresigint] [-beta <version>]"
|
159 |
echo " [-debuglog <logname>]"
|
160 |
echo "Params:"
|
161 |
echo "-game <game> Specifies the <game> to run."
|
162 |
echo "-debug Run debugging on failed servers if possible."
|
163 |
echo "-debuglog <logname> Log debug output to this file."
|
164 |
echo "-norestart Don't attempt to restart failed servers."
|
165 |
echo "-pidfile <pidfile> Use the specified <pidfile> to store the server pid."
|
166 |
echo "-binary <binary> Use the specified binary ( no auto detection )."
|
167 |
echo "-timeout <number> Sleep for <number> seconds before restarting"
|
168 |
echo " a failed server."
|
169 |
echo "-gdb <gdb> Use <dbg> as the debugger of failed servers."
|
170 |
echo "-steamerr Quit on steam update failure."
|
171 |
echo "-ignoresigint Ignore signal INT ( prevents CTRL+C quitting"
|
172 |
echo " the script )."
|
173 |
echo "-notrap Don't use trap. This prevents automatic"
|
174 |
echo " removal of old lock files."
|
175 |
echo "-beta <version> Use the specified beta version for autoupdate."
|
176 |
echo ""
|
177 |
echo "Note: All parameters specified are passed through to the server"
|
178 |
echo "including any not listed."
|
179 |
}
|
180 |
|
181 |
debugcore () {
|
182 |
# Debugs any core file if DEBUG is set and
|
183 |
# the exitcode is none 0
|
184 |
|
185 |
exitcode=$1
|
186 |
|
187 |
if test $exitcode -ne 0; then
|
188 |
if test "$DEBUG" -eq 1; then
|
189 |
echo "bt" > debug.cmds;
|
190 |
echo "info locals" >> debug.cmds;
|
191 |
echo "info sharedlibrary" >> debug.cmds
|
192 |
echo "info frame" >> debug.cmds; # works, but gives an error... must be last
|
193 |
echo "----------------------------------------------" >> $DEBUG_LOG
|
194 |
echo "CRASH: `date`" >> $DEBUG_LOG
|
195 |
echo "Start Line: $HL_CMD" >> $DEBUG_LOG
|
196 |
|
197 |
# check to see if a core was dumped
|
198 |
if test -f core ; then
|
199 |
CORE="core"
|
200 |
elif test -f core.`cat $PID_FILE`; then
|
201 |
CORE=core.`cat $PID_FILE`
|
202 |
elif test -f "$HL.core" ; then
|
203 |
CORE="$HL.core"
|
204 |
fi
|
205 |
|
206 |
if test -n "$CORE"; then
|
207 |
$GDB $HL $CORE -x debug.cmds -batch >> $DEBUG_LOG
|
208 |
fi
|
209 |
|
210 |
echo "End of crash report" >> $DEBUG_LOG
|
211 |
echo "----------------------------------------------" >> $DEBUG_LOG
|
212 |
echo $CRASH_DEBUG_MSG
|
213 |
rm debug.cmds
|
214 |
else
|
215 |
echo "Add \"-debug\" to the $0 command line to generate a debug.log to help with solving this problem"
|
216 |
fi
|
217 |
fi
|
218 |
}
|
219 |
|
220 |
detectcpu() {
|
221 |
# Attempts to auto detect the CPU
|
222 |
echo "Auto detecting CPU"
|
223 |
|
224 |
if test "FreeBSD" = `uname`; then
|
225 |
PROC="/usr/compat/linux/proc"
|
226 |
else
|
227 |
PROC="/proc"
|
228 |
fi
|
229 |
|
230 |
if test -e $PROC/cpuinfo; then
|
231 |
CPU_VERSION="`grep "cpu family" $PROC/cpuinfo | cut -f2 -d":" | tr -d " " | uniq`";
|
232 |
if test $CPU_VERSION -lt 4; then
|
233 |
echo "Error: hlds_l REQUIRES a 486 CPU or better";
|
234 |
quit 1
|
235 |
elif test $CPU_VERSION -ge 15; then
|
236 |
# Core 2 or greater
|
237 |
echo "Using AMD Optimised binary."
|
238 |
HL=./hlds_amd
|
239 |
elif test $CPU_VERSION -ge 6; then
|
240 |
AMD="`grep AMD $PROC/cpuinfo`";
|
241 |
if test -n "$AMD"; then
|
242 |
echo "Using AMD Optimised binary."
|
243 |
HL=./hlds_amd
|
244 |
else
|
245 |
echo "Using Pentium II Optimised binary."
|
246 |
|
247 |
# there is a CPU manufactured by VIA that
|
248 |
# doesn't support some PII instructions...
|
249 |
# detect this.
|
250 |
VIACHIP=`grep CentaurHauls $PROC/cpuinfo`
|
251 |
|
252 |
if test -z "$VIACHIP"; then
|
253 |
HL=./hlds_i686
|
254 |
fi
|
255 |
fi
|
256 |
else
|
257 |
echo "Using default binary."
|
258 |
fi
|
259 |
elif test "FreeBSD" = `uname`; then
|
260 |
CPU="`grep 'CPU:' /var/run/dmesg.boot`"
|
261 |
AMD="`echo $CPU |grep AMD`"
|
262 |
K8="`echo $CPU |grep K8`"
|
263 |
I686="`echo $CPU |grep 686`"
|
264 |
if test -n "$AMD"; then
|
265 |
echo "Using AMD Optimised binary."
|
266 |
HL=./hlds_amd
|
267 |
elif test -n "$K8" ; then
|
268 |
echo "Using AMD Optimised binary."
|
269 |
HL=./hlds_amd
|
270 |
elif test -n "$I686" ; then
|
271 |
echo "Using Pentium II Optimised binary."
|
272 |
HL=./hlds_i686
|
273 |
else
|
274 |
echo "Using default binary."
|
275 |
fi
|
276 |
else
|
277 |
echo "Using default binary."
|
278 |
fi
|
279 |
}
|
280 |
|
281 |
update() {
|
282 |
updatesingle
|
283 |
}
|
284 |
|
285 |
updatesingle() {
|
286 |
# Run the steam update
|
287 |
# exits on failure if STEAMERR is set
|
288 |
|
289 |
if test -n "$AUTO_UPDATE"; then
|
290 |
if test -f "$STEAM"; then
|
291 |
echo "Updating server using Steam."
|
292 |
CMD="$STEAM -command update -game $GAME -dir .";
|
293 |
if test -n "$BETA_VERSION"; then
|
294 |
CMD="$CMD -beta $BETA_VERSION";
|
295 |
fi
|
296 |
|
297 |
$CMD
|
298 |
if test $? -ne 0; then
|
299 |
if test -n "$STEAMERR"; then
|
300 |
echo "`date`: Steam Update failed, exiting."
|
301 |
quit 1
|
302 |
else
|
303 |
echo "`date`: Steam Update failed, ignoring."
|
304 |
return 0
|
305 |
fi
|
306 |
fi
|
307 |
else
|
308 |
if test -n "$STEAMERR"; then
|
309 |
echo "Could not locate steam binary:$STEAM, exiting.";
|
310 |
quit 1
|
311 |
else
|
312 |
echo "Could not locate steam binary:$STEAM, ignoring.";
|
313 |
return 0
|
314 |
fi
|
315 |
fi
|
316 |
fi
|
317 |
|
318 |
return 1
|
319 |
}
|
320 |
|
321 |
run() {
|
322 |
# Runs the steam update and server
|
323 |
# Loops if RESTART is set
|
324 |
# Debugs if server failure is detected
|
325 |
# Note: if RESTART is not set then
|
326 |
# 1. DEBUG is set then the server is NOT exec'd
|
327 |
# 2. DEBUG is not set the the server is exec'd
|
328 |
|
329 |
if test -n "$RESTART" ; then
|
330 |
echo "Auto-restarting the server on crash"
|
331 |
|
332 |
#loop forever
|
333 |
while true
|
334 |
do
|
335 |
# Update if needed
|
336 |
update
|
337 |
|
338 |
# Run the server
|
339 |
$HL_CMD
|
340 |
retval=$?
|
341 |
if test $retval -eq 0 && test -z "$AUTO_UPDATE"; then
|
342 |
break; # if 0 is returned then just quit
|
343 |
fi
|
344 |
|
345 |
debugcore $retval
|
346 |
|
347 |
echo "`date`: Server restart in $TIMEOUT seconds"
|
348 |
|
349 |
# don't thrash the hard disk if the server dies, wait a little
|
350 |
sleep $TIMEOUT
|
351 |
done # while true
|
352 |
else
|
353 |
# Update if needed
|
354 |
update
|
355 |
|
356 |
# Run the server
|
357 |
if test "$DEBUG" -eq 0; then
|
358 |
# debug not requested we can exec
|
359 |
exec $HL_CMD
|
360 |
else
|
361 |
# debug requested we can't exec
|
362 |
$HL_CMD
|
363 |
debugcore $?
|
364 |
fi
|
365 |
fi
|
366 |
}
|
367 |
|
368 |
quit() {
|
369 |
# Exits with the give error code, 1
|
370 |
# if none specified.
|
371 |
# exit code 2 also prints syntax
|
372 |
exitcode="$1"
|
373 |
|
374 |
# default to failure
|
375 |
if test -z "$exitcode"; then
|
376 |
exitcode=1
|
377 |
fi
|
378 |
|
379 |
case "$exitcode" in
|
380 |
0)
|
381 |
echo "`date`: Server Quit" ;;
|
382 |
2)
|
383 |
syntax ;;
|
384 |
*)
|
385 |
echo "`date`: Server Failed" ;;
|
386 |
esac
|
387 |
|
388 |
# Remove pid file
|
389 |
if test -n "$PID_FILE" && test -f "$PID_FILE" ; then
|
390 |
# The specified pid file
|
391 |
rm -f $PID_FILE
|
392 |
fi
|
393 |
|
394 |
# reset SIGINT and then kill ourselves properly
|
395 |
trap - 2
|
396 |
kill -2 $$
|
397 |
}
|
398 |
|
399 |
# Initialise
|
400 |
init $*
|
401 |
|
402 |
# Run
|
403 |
run
|
404 |
|
405 |
# Quit normally
|
406 |
quit 0
|