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