diff options
author | Tim Moore <timoore@redhat.com> | 2009-12-23 09:14:02 +0100 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2009-12-23 09:14:02 +0100 |
commit | 69ce6c79dbcb2cec2d1245935ef20bf832ffe70a (patch) | |
tree | 0b6aea71ef4f3ca5c797494d062819bfba63e7f7 /stap-server-request | |
parent | 72195f6b17c0ed2e508c58bf3cadd5b9dc4e28ac (diff) | |
parent | 0ee3adb42f2f6d8bffe177e77a415b3a74f3a777 (diff) | |
download | systemtap-steved-69ce6c79dbcb2cec2d1245935ef20bf832ffe70a.tar.gz systemtap-steved-69ce6c79dbcb2cec2d1245935ef20bf832ffe70a.tar.xz systemtap-steved-69ce6c79dbcb2cec2d1245935ef20bf832ffe70a.zip |
Merge remote branch 'origin/master'
Diffstat (limited to 'stap-server-request')
-rwxr-xr-x | stap-server-request | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/stap-server-request b/stap-server-request new file mode 100755 index 00000000..d1731895 --- /dev/null +++ b/stap-server-request @@ -0,0 +1,512 @@ +#!/bin/bash + +# Compile server for systemtap +# +# Copyright (C) 2008, 2009 Red Hat Inc. +# +# This file is part of systemtap, and is free software. You can +# redistribute it and/or modify it under the terms of the GNU General +# Public License (GPL); either version 2, or (at your option) any +# later version. + +# This script unpacks the tar file provided on stdin and uses the information +# contained in the unpacked tree to build the requested systemtap kernel module. +# This module is then written to stdout. + +# Catch ctrl-c and other termination signals +trap 'terminate' SIGTERM SIGINT + +# Initialize the environment +. ${PKGLIBEXECDIR}stap-env + +#----------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------- +# function: initialization +function initialization { + # Initialization + stap_rc=0 + wd=`pwd` + + # Default options settings + p_phase=5 + keep_temps=0 + unprivileged=0 + stap_options= + + zip_client=$1 + tmpdir_server=$2 + zip_server=$3 + ssl_db=$4 + server_options="$5" + + # This script is not intended to be called directly, so if the arguments + # aren't specified correctly, just exit with non-zero + test "X$tmpdir_server" != "X" || exit 2 + test -d $tmpdir_server || exit 3 + tmpdir_env=`dirname $tmpdir_server` + + # Response file name. + test "X$zip_server" != "X" || exit 4 + # Make sure the specified .zip file exists. + test -f $zip_server || exit 5 + + # Request file name. + test "X$zip_client" != "X" || exit 6 + test -f $zip_client || exit 7 + + # Where is the ssl certificate/key database? + test "X$ssl_db" != "X" || exit 8 + test -d $ssl_db || exit 9 + nss_pw=$ssl_db/pw + test -f $nss_pw || exit 10 + + # What are the options that the server was started with? + eval parse_options "$server_options" + + nss_cert=stap-server + + touch $tmpdir_server/stdout + touch $tmpdir_server/stderr +} + +# function: unpack_request +# +# Unpack the zip file received from the client and make the contents +# available for use when running 'stap' +function unpack_request { + cd $tmpdir_server + + # Unpack the zip file. + unzip $zip_client > /dev/null || \ + fatal "Cannot unpack zip archive $zip_client" + + # Identify the client's request tree. The zip file should have expanded + # into a single directory named to match $stap_tmpdir_prefix_client.?????? + # which should now be the only item in the current directory. + test "`ls | wc -l`" = 3 || \ + fatal "Wrong number of files after expansion of client's zip file" + + tmpdir_client=`ls | grep $stap_tmpdir_prefix_client.......\$` + + test "X$tmpdir_client" != "X" || \ + fatal "Client zip file did not expand as expected" + + # Move the client's temp directory to a local temp location + local local_tmpdir_client=`mktemp -dt $stap_tmpdir_prefix_server.client.XXXXXX` || \ + fatal "Cannot create temporary client request directory " $local_tmpdir_client + mv $tmpdir_client/* $local_tmpdir_client + rm -fr $tmpdir_client + tmpdir_client=$local_tmpdir_client +} + +# function: check_request +# +# Examine the contents of the request to make sure that they are valid. +function check_request { + # Work in the temporary directory provided by the client + cd $tmpdir_client + + # Add the necessary info from files in our temporary directory. + cmdline=`read_data_file cmdline` + test "X$cmdline" != "X" || exit 1 + + eval parse_options "$cmdline" + + client_sysinfo=`read_data_file sysinfo` + test "X$client_sysinfo" != "X" || exit 1 + + check_compatibility "$client_sysinfo" "`server_sysinfo`" +} + +# function server_sysinfo +# +# Generate the server's sysinfo and echo it to stdout +function server_sysinfo { + if test "X$sysinfo_server" = "X"; then + # Add some info from uname + sysinfo_server="`uname -r` `stap_get_arch`" + fi + echo "$sysinfo_server" +} + +# function check_compaibility SYSINFO1 SYSINFO2 +# +# Make sure that systemtap as described by SYSINFO1 and SYSINFO2 are compaible +function check_compatibility { + # Compatibility is irrelevant. The client can choose any server + # it sees fit + return +} + +# function: read_data_file PREFIX +# +# Find a file whose name is '$1' and whose first line +# contents are '$1: .*'. Read and echo the data. +function read_data_file { + test -f $1 || \ + fatal "Data file $1 not found" + + # Open the file + exec 3< $1 + + # Verify the first line of the file. + read <&3 + line="$REPLY" + data=`expr "$line" : "$1: \\\(.*\\\)"` + if test "X$data" = "X"; then + fatal "Data in file $1 is incorrect" + return + fi + + # Close the file + exec 3<&- + + # Now read the entire file. + cat $1 | sed "s/$1: //" +} + +# function: parse_options [ STAP-OPTIONS ] +# +# Examine the command line. We need not do much checking, but we do need to +# parse all options in order to discover the ones we're interested in. +function parse_options { + # We need to know in advance if --unprivileged was specified. + all_options=" ""$@"" " + token=`expr "$all_options" : '.* \(--unprivileged\) .*'` + if test "X$token" = "X--unprivileged"; then + unprivileged=1 + fi + + while test $# != 0 + do + advance_p=0 + dash_seen=0 + + # Start of a new token. + first_token=$1 + + # Process the option. + until test $advance_p != 0 + do + # Identify the next option + first_char=`expr "$first_token" : '\(.\).*'` + if test $dash_seen = 0; then + if test "$first_char" = "-"; then + if test "$first_token" != "-"; then + # It's not a lone dash, so it's an option. + # Is it a long option (i.e. --option)? + second_char=`expr "$first_token" : '.\(.\).*'` + if test "X$second_char" = "X-"; then + advance_p=$(($advance_p + 1)) + stap_options="$stap_options $first_token" + break + fi + # It's not a lone dash, or a long option, so it's a short option string. + # Remove the dash. + first_token=`expr "$first_token" : '-\(.*\)'` + dash_seen=1 + first_char=`expr "$first_token" : '\(.\).*'` + fi + fi + if test $dash_seen = 0; then + # The dash has not been seen. This is either the script file + # name or an arument to be passed to the probe module. + # If this is the first time, and -e has not been specified, + # then it could be the name of the script file. + if test "X$e_script" = "X" -a "X$script_file" = "X"; then + script_file="$first_token" + fi + if test "$first_char" != "'"; then + stap_options="$stap_options '$first_token'" + else + stap_options="$stap_options $first_token" + fi + advance_p=$(($advance_p + 1)) + break + fi + fi + + # We are at the start of an option. Look at the first character. + case $first_char in + a) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + B) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + d) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + ;; + D) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + e) + get_arg $first_token "$2" + stap_options="$stap_options -$first_char '$stap_arg'" + process_e "$stap_arg" + ;; + I) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + k) + keep_temps=1 + ;; + l) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + process_p 2 + ;; + L) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + process_p 2 + ;; + m) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + o) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + ;; + p) + get_arg $first_token $2 + process_p $stap_arg + ;; + r) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + R) + get_arg $first_token $2 + if test $unprivileged = 1; then + fatal "You can't specify -$first_char and --unprivileged together." + else + stap_options="$stap_options -$first_char $stap_arg" + fi + ;; + s) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + ;; + S) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + ;; + x) + get_arg $first_token $2 + stap_options="$stap_options -$first_char $stap_arg" + ;; + *) + # An unknown flag. Ignore it. + ;; + esac + + if test $advance_p = 0; then + # Just another flag character. Consume it. + stap_options="$stap_options -$first_char" + first_token=`expr "$first_token" : '.\(.*\)'` + if test "X$first_token" = "X"; then + advance_p=$(($advance_p + 1)) + fi + fi + done + + # Consume the arguments we just processed. + while test $advance_p != 0 + do + shift + advance_p=$(($advance_p - 1)) + done + done +} + +# function: get_arg FIRSTWORD SECONDWORD +# +# Collect an argument to the given option +function get_arg { + # Remove first character. Advance to the next token, if the first one + # is exhausted. + local first=`expr "$1" : '.\(.*\)'` + if test "X$first" = "X"; then + shift + advance_p=$(($advance_p + 1)) + first=$1 + fi + stap_arg="$first" + advance_p=$(($advance_p + 1)) +} + +# function: process_e ARGUMENT +# +# Process the -e flag. +function process_e { + if test "X$e_script" = "X"; then + e_script="$1" + script_file= + fi +} + +# function: process_p ARGUMENT +# +# Process the -p flag. +function process_p { + if test $1 -ge 1 -a $1 -le 5; then + p_phase=$1 + fi +} + +# function: call_stap +# +# Call 'stap' with the options provided. Don't run past phase 4. +function call_stap { + # Invoke systemtap. + # Use -k so we can return results to the client + # Limit to -p4. i.e. don't run the module + cd $tmpdir_client + if test $p_phase -gt 4; then + server_p_phase=4 + else + server_p_phase=$p_phase + fi + + eval ${stap_exec_prefix}stap "$stap_options" -k -p $server_p_phase \ + >> $tmpdir_server/stdout \ + 2>> $tmpdir_server/stderr + + stap_rc=$? +} + +# function: create_response +# +# Add information to the server's temp directory representing the response +# to the client. +function create_response { + cd $tmpdir_server + + # Get the name of the stap temp directory, which was kept, from stderr. + tmpdir_line=`cat stderr | grep "Keeping temp"` + tmpdir_stap=`expr "$tmpdir_line" : '.*"\(.*\)".*'` + + # Remove the message about keeping the stap temp directory from stderr, unless + # the user did request to keep it. + if test "X$tmpdir_stap" != "X"; then + if test $keep_temps != 1; then + sed -i "/^Keeping temp/d" stderr + fi + + # Add the contents of the stap temp directory to the server output directory + ln -s $tmpdir_stap `basename $tmpdir_stap` + + # Sign the resulting module if --unprivileged was specified. + if test $unprivileged = 1 -a $p_phase -ge 4 -a $stap_rc = 0; then + modname=$tmpdir_stap/`grep -m1 '^.*\.ko$' stdout` + if test "X$modname" != "X"; then + ${stap_pkglibexecdir}stap-sign-module $modname $ssl_db + fi + fi + fi + + # If the user specified -p5, remove the name of the kernel module from stdout. + if test $p_phase = 5; then + sed -i '/\.ko$/d' stdout + fi + + # The return status of the stap command. + echo -n $stap_rc > rc +} + +# function: package_response +# +# Package the server's temp directory into a form suitable for sending to the +# client. +function package_response { + cd $tmpdir_env + + # Compress the server's temporary directory into a .zip archive. + (rm $zip_server && zip -r $zip_server `basename $tmpdir_server` > /dev/null) + return $? +} + +# function: fatal [ MESSAGE ] +# +# Fatal error +# Prints its arguments to stderr and exits +function fatal { + echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr + echo -n 1 > $tmpdir_server/rc + package_response + cleanup + exit 1 +} + +# Non fatal error +# Prints its arguments to stderr but does not exit +function error { + echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr +} + +# function cleanup +# +# Cleanup work files unless asked to keep them. +function cleanup { + # Clean up. + cd $tmpdir_env + if test $keep_temps != 1; then + rm -fr $tmpdir_server + rm -fr $tmpdir_client + rm -fr $tmpdir_stap + fi +} + +# function: terminate +# +# Terminate gracefully. +function terminate { + # Clean up + cleanup + exit 1 +} + +#----------------------------------------------------------------------------- +# Beginning of main line execution. +#----------------------------------------------------------------------------- +initialization "$@" +unpack_request +check_request +call_stap +create_response +package_response +cleanup + +exit 0 |