]> sourceware.org Git - systemtap.git/blob - stap-server
Version bumps for 0.9.6 release
[systemtap.git] / stap-server
1 #!/bin/bash
2
3 # Compile server for systemtap
4 #
5 # Copyright (C) 2008, 2009 Red Hat Inc.
6 #
7 # This file is part of systemtap, and is free software. You can
8 # redistribute it and/or modify it under the terms of the GNU General
9 # Public License (GPL); either version 2, or (at your option) any
10 # later version.
11
12 # This script unpacks the tar file provided on stdin and uses the information
13 # contained in the unpacked tree to build the requested systemtap kernel module.
14 # This module is then written to stdout.
15
16 # Catch ctrl-c and other termination signals
17 trap 'terminate' SIGTERM SIGINT
18
19 #-----------------------------------------------------------------------------
20 # Helper functions.
21 #-----------------------------------------------------------------------------
22 # function: configuration
23 function configuration {
24 # INSTALL-HOOK These settings work for running the client from the source tree
25 # INSTALL-HOOK using the dejagnu test harness and will be overridden at install
26 # INSTALL-HOOK time.
27 exec_prefix=
28 sysconfdir=`pwd`/net
29
30 # Configuration
31 tmpdir_prefix_client=stap.client
32 tmpdir_prefix_server=stap.server
33 }
34
35 # function: initialization
36 function initialization {
37 # Initialization
38 stap_rc=0
39 wd=`pwd`
40
41 # Default options settings
42 p_phase=5
43 keep_temps=0
44
45 # Request file name.
46 zip_client=$1
47 test "X$zip_client" != "X" || \
48 fatal "Client request file not specified"
49 test -f $zip_client || \
50 fatal "Unable to find request file $zip_client"
51
52 # Temp directory we will be working in
53 tmpdir_server=$2
54 test "X$tmpdir_server" != "X" || \
55 fatal "Server temporary directory not specified"
56 test -d $tmpdir_server || \
57 fatal "Unable to find temporary directory $tmpdir_server"
58 tmpdir_env=`dirname $tmpdir_server`
59
60 # Signed reponse file name.
61 zip_server=$3
62 test "X$zip_server" != "X" || \
63 fatal ".zip archive file not specified"
64 # Make sure the specified .zip file exists.
65 test -f $zip_server || \
66 fatal "Unable to find .zip archive file $zip_server"
67
68 # Where is the ssl certificate/key database?
69 ssl_db=$4
70 test "X$ssl_db" != "X" || \
71 fatal "SSL certificate database not specified"
72 test -d $ssl_db || \
73 fatal "Unable to find SSL certificate database $ssl_db"
74 nss_pw=$ssl_db/pw
75 test -f $nss_pw || \
76 fatal "Unable to find SSL certificate database password file $nss_pw"
77 nss_cert=stap-server
78
79 touch $tmpdir_server/stdout
80 touch $tmpdir_server/stderr
81 }
82
83 # function: unpack_request
84 #
85 # Unpack the zip file received from the client and make the contents
86 # available for use when running 'stap'
87 function unpack_request {
88 cd $tmpdir_server
89
90 # Unpack the zip file.
91 unzip $zip_client > /dev/null || \
92 fatal "Cannot unpack zip archive $zip_client"
93
94 # Identify the client's request tree. The zip file should have expanded
95 # into a single directory named to match $tmpdir_prefix_client.??????
96 # which should now be the only item in the current directory.
97 test "`ls | wc -l`" = 3 || \
98 fatal "Wrong number of files after expansion of client's zip file"
99
100 tmpdir_client=`ls | grep $tmpdir_prefix_client.......\$`
101
102 test "X$tmpdir_client" != "X" || \
103 fatal "Client zip file did not expand as expected"
104
105 # Move the client's temp directory to a local temp location
106 local local_tmpdir_client=`mktemp -dt $tmpdir_prefix_server.client.XXXXXX` || \
107 fatal "Cannot create temporary client request directory " $local_tmpdir_client
108 mv $tmpdir_client/* $local_tmpdir_client
109 rm -fr $tmpdir_client
110 tmpdir_client=$local_tmpdir_client
111 }
112
113 # function: check_request
114 #
115 # Examine the contents of the request to make sure that they are valid.
116 function check_request {
117 # Work in the temporary directory provided by the client
118 cd $tmpdir_client
119
120 # Add the necessary info from files in our temporary directory.
121 cmdline=`read_data_file cmdline`
122 test "X$cmdline" != "X" || exit 1
123
124 eval parse_options "$cmdline"
125
126 client_sysinfo=`read_data_file sysinfo`
127 test "X$client_sysinfo" != "X" || exit 1
128
129 check_compatibility "$client_sysinfo" "`server_sysinfo`"
130 }
131
132 # function server_sysinfo
133 #
134 # Generate the server's sysinfo and echo it to stdout
135 function server_sysinfo {
136 if test "X$sysinfo_server" = "X"; then
137 # Add some info from uname
138 sysinfo_server="`uname -rvm`"
139 fi
140 echo "$sysinfo_server"
141 }
142
143 # function check_compaibility SYSINFO1 SYSINFO2
144 #
145 # Make sure that systemtap as described by SYSINFO1 and SYSINFO2 are compaible
146 function check_compatibility {
147 # Compatibility is irrelevant if the request is not for phase 5 activity.
148 test $p_phase -lt 5 && return
149
150 # TODO: This needs work
151 # - Make sure the linux kernel matches exactly
152 local sysinfo1=$1
153 local sysinfo2=$2
154
155 if test "$sysinfo1" != "$sysinfo2"; then
156 error "System configuration mismatch"
157 error " client: $sysinfo1"
158 fatal " server: $sysinfo2"
159 fi
160 }
161
162 # function: read_data_file PREFIX
163 #
164 # Find a file whose name is '$1' and whose first line
165 # contents are '$1: .*'. Read and echo the data.
166 function read_data_file {
167 test -f $1 || \
168 fatal "Data file $1 not found"
169
170 # Open the file
171 exec 3< $1
172
173 # Verify the first line of the file.
174 read <&3
175 line="$REPLY"
176 data=`expr "$line" : "$1: \\\(.*\\\)"`
177 if test "X$data" = "X"; then
178 fatal "Data in file $1 is incorrect"
179 return
180 fi
181
182 # Close the file
183 exec 3<&-
184
185 # Now read the entire file.
186 cat $1 | sed "s/$1: //"
187 }
188
189 # function: parse_options [ STAP-OPTIONS ]
190 #
191 # Examine the command line. We need not do much checking, but we do need to
192 # parse all options in order to discover the ones we're interested in.
193 function parse_options {
194 while test $# != 0
195 do
196 advance_p=0
197 dash_seen=0
198
199 # Start of a new token.
200 first_token=$1
201 until test $advance_p != 0
202 do
203 # Identify the next option
204 first_char=`expr "$first_token" : '\(.\).*'`
205 if test $dash_seen = 0; then
206 if test "$first_char" = "-"; then
207 if test "$first_token" != "-"; then
208 # It's not a lone dash, so it's an option. Remove the dash.
209 first_token=`expr "$first_token" : '-\(.*\)'`
210 dash_seen=1
211 first_char=`expr "$first_token" : '\(.\).*'`
212 fi
213 fi
214 if test $dash_seen = 0; then
215 # The dash has not been seen. This is either the script file
216 # name or an arument to be passed to the probe module.
217 # If this is the first time, and -e has not been specified,
218 # then it could be the name of the script file.
219 if test "X$e_script" = "X" -a "X$script_file" = "X"; then
220 script_file=$first_token
221 fi
222 advance_p=$(($advance_p + 1))
223 break
224 fi
225 fi
226
227 # We are at the start of an option. Look at the first character.
228 case $first_char in
229 c)
230 get_arg $first_token "$2"
231 ;;
232 D)
233 get_arg $first_token $2
234 ;;
235 e)
236 get_arg $first_token "$2"
237 process_e "$stap_arg"
238 ;;
239 I)
240 get_arg $first_token $2
241 ;;
242 k)
243 keep_temps=1
244 ;;
245 l)
246 get_arg $first_token $2
247 ;;
248 m)
249 get_arg $first_token $2
250 ;;
251 o)
252 get_arg $first_token $2
253 ;;
254 p)
255 get_arg $first_token $2
256 process_p $stap_arg
257 ;;
258 r)
259 get_arg $first_token $2
260 ;;
261 R)
262 get_arg $first_token $2
263 ;;
264 s)
265 get_arg $first_token $2
266 ;;
267 x)
268 get_arg $first_token $2
269 ;;
270 *)
271 # An unknown flag. Ignore it.
272 ;;
273 esac
274
275 if test $advance_p = 0; then
276 # Just another flag character. Consume it.
277 first_token=`expr "$first_token" : '.\(.*\)'`
278 if test "X$first_token" = "X"; then
279 advance_p=$(($advance_p + 1))
280 fi
281 fi
282 done
283
284 # Consume the arguments we just processed.
285 while test $advance_p != 0
286 do
287 shift
288 advance_p=$(($advance_p - 1))
289 done
290 done
291 }
292
293 # function: get_arg FIRSTWORD SECONDWORD
294 #
295 # Collect an argument to the given option
296 function get_arg {
297 # Remove first character. Advance to the next token, if the first one
298 # is exhausted.
299 local first=`expr "$1" : '.\(.*\)'`
300 if test "X$first" = "X"; then
301 shift
302 advance_p=$(($advance_p + 1))
303 first=$1
304 fi
305
306 stap_arg="$first"
307 advance_p=$(($advance_p + 1))
308 }
309
310 # function: process_e ARGUMENT
311 #
312 # Process the -e flag.
313 function process_e {
314 if test "X$e_script" = "X"; then
315 e_script="$1"
316 script_file=
317 fi
318 }
319
320 # function: process_p ARGUMENT
321 #
322 # Process the -p flag.
323 function process_p {
324 if test $1 -ge 1 -a $1 -le 5; then
325 p_phase=$1
326 fi
327 }
328
329 # function: call_stap
330 #
331 # Call 'stap' with the options provided. Don't run past phase 4.
332 function call_stap {
333 # Invoke systemtap.
334 # Use -k so we can return results to the client
335 # Limit to -p4. i.e. don't run the module
336 cd $tmpdir_client
337 if test $p_phase -gt 4; then
338 server_p_phase=4
339 else
340 server_p_phase=$p_phase
341 fi
342
343 eval ${exec_prefix}stap "$cmdline" -k -p $server_p_phase \
344 >> $tmpdir_server/stdout \
345 2>> $tmpdir_server/stderr
346
347 stap_rc=$?
348 }
349
350 # function: create_response
351 #
352 # Add information to the server's temp directory representing the response
353 # to the client.
354 function create_response {
355 cd $tmpdir_server
356
357 # Get the name of the stap temp directory, which was kept, from stderr.
358 tmpdir_line=`cat stderr | grep "Keeping temp"`
359 tmpdir_stap=`expr "$tmpdir_line" : '.*"\(.*\)".*'`
360
361 # Remove the message about keeping the stap temp directory from stderr, unless
362 # the user did request to keep it.
363 if test "X$tmpdir_stap" != "X"; then
364 if test $keep_temps != 1; then
365 sed -i "/^Keeping temp/d" stderr
366 fi
367
368 # Add the contents of the stap temp directory to the server output directory
369 ln -s $tmpdir_stap `basename $tmpdir_stap`
370 fi
371
372 # If the user specified -p5, remove the name of the kernel module from stdout.
373 if test $p_phase = 5; then
374 sed -i '/\.ko$/d' stdout
375 fi
376
377 # The return status of the stap command.
378 echo -n $stap_rc > rc
379 }
380
381 # function: package_response
382 #
383 # Package the server's temp directory into a form suitable for sending to the
384 # client.
385 function package_response {
386 cd $tmpdir_env
387
388 # Compress the server's temporary directory into a .zip archive.
389 (rm $zip_server && zip -r $zip_server `basename $tmpdir_server` > /dev/null) || \
390 fatal "zip of request tree, $tmpdir_server, failed"
391 }
392
393 # function: fatal [ MESSAGE ]
394 #
395 # Fatal error
396 # Prints its arguments to stderr and exits
397 function fatal {
398 echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr
399 echo -n 1 > $tmpdir_server/rc
400 package_response
401 cleanup
402 exit 1
403 }
404
405 # Non fatal error
406 # Prints its arguments to stderr but does not exit
407 function error {
408 echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr
409 }
410
411 # function cleanup
412 #
413 # Cleanup work files unless asked to keep them.
414 function cleanup {
415 # Clean up.
416 cd $tmpdir_env
417 if test $keep_temps != 1; then
418 rm -fr $tmpdir_server
419 rm -fr $tmpdir_client
420 rm -fr $tmpdir_stap
421 fi
422 }
423
424 # function: terminate
425 #
426 # Terminate gracefully.
427 function terminate {
428 # Clean up
429 cleanup
430 exit 1
431 }
432
433 #-----------------------------------------------------------------------------
434 # Beginning of main line execution.
435 #-----------------------------------------------------------------------------
436 configuration
437 initialization "$@"
438 unpack_request
439 check_request
440 call_stap
441 create_response
442 package_response
443 cleanup
444
445 exit 0
This page took 0.057707 seconds and 5 git commands to generate.