From: Dave Brolley Date: Thu, 3 Jul 2008 17:10:44 +0000 (-0400) Subject: client/server take 2. See bz6565. X-Git-Tag: release-0.7-rc1~12^2~1 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=66e1a139060be3caac7733ba745b225ce775ca97;p=systemtap.git client/server take 2. See bz6565. --- diff --git a/ChangeLog b/ChangeLog index 7c34f2238..697f4e0d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2008-07-03 + + * stap-serverd: New script. + * stap-client (client_sysinfo): Client sysinfo is stripped down to + the output of `uname -r` for now. + (package_request): Don't create temporary server tar file here. + (send_request): Communication protocol simplified. Use nc to send + the tar file. + (receive_response): Communication protocol eliminated. Simply wait + for the file from the server using nc. + (unpack_response): Create temporary server tar file here. Verify the + contents of the server's response. + (find_and_connect_to_server): Obtain server address and port from + avahi-browse. + (server_fatal): New function. + (check_server_error): Call server_fatal. + * stap-server (configuration): port is now provided as an argument. + Default to port 65001. + (initialization): Don't create temp work directory here. + (receive_request): Communication protocol simplified. Receive the + request file using nc. + (unpack_request): Make temp work directory here. Verify the contents + of the request. + (server_sysinfo): New function. + (check_compatibility): Exact match required. + (package_response): Don't use -p on tar command. + (send_response): Communication protocol eliminated. Simply send the + file using nc. + (main line): Pass "$@" to configuration. + 2008-07-01 Frank Ch. Eigler * main.cxx (main): In -vv mode, also dump out session arch/release diff --git a/stap-client b/stap-client index 42402a27a..515cab92b 100755 --- a/stap-client +++ b/stap-client @@ -314,12 +314,8 @@ function create_request { # Generate the client's sysinfo and echo it to stdout function client_sysinfo { if test "X$sysinfo_client" = "X"; then - # Get the stap version - stap_version=`stap -V 2>&1 | grep version` - # Remove the number before the first slash - stap_version=`expr "$stap_version" : '.*version [^/]*/\([0-9./]*\).*'` # Add some info from uname - sysinfo_client="stap $stap_version `uname -sr`" + sysinfo_client="`uname -r`" fi echo $sysinfo_client } @@ -338,67 +334,50 @@ function package_request { tar -czhf $tar_client $tmpdir_client_base || \ fatal "ERROR: tar of request tree, $tmpdir_client, failed" - - tar_server=$tmpdir_env/`mktemp $tmpdir_prefix_server.tgz.XXXXXX` || \ - fatal "ERROR: cannot create temporary file " $tar_server } # function: send_request # -# Notify the server and then send $tar_client to the server as $tar_server +# Notify the server and then send $tar_client to the server # The protocol is: -# client -> "request: $tmpdir_client" -# server -> "send: $tar_server" -# client: rsync local:$tar_client server:$tar_server -# client -> "waiting:" +# client -> "request:" +# server -> "ready:" +# client -> $tar_client # # $tmpdir_client is provided on the request so that the server knows what # the tar file will expand to. function send_request { - echo "request: `basename $tmpdir_client`" >&3 + echo "request:" >&3 + # Get the server's response. read <&3 local line=$REPLY check_server_error $line - local tar_dest=`expr "$line" : 'send: \([^ ]*\)$'` - test "X$tar_dest" == "X" && \ - fatal "ERROR: destination tar file not provided" - - rsync -essh -a --delete $tar_client root@$server:$tar_dest || \ - fatal "ERROR: rsync of client request, $tar_client to $server:$tar_dest, failed" + # Check for the proper response. + test "$line" = "ready:" || \ + fatal "ERROR: server response, '$line', is incorrect" - echo "waiting:" >&3 + # Send the request file. + until nc $server $(($port + 1)) < $tar_client + do + sleep 1 + done } # function: receive_response # # Wait for a response from the server indicating the results of our request. -# The protocol is: -# server -> "sending: remote-tar-name server-tempdir-name stap-tempdir-name" -# client -> "OK" function receive_response { - read <&3 - local line=$REPLY - check_server_error $line - - tar_dest=`expr "$line" : 'sending: \([^ ]*\) [^ ]* [^ ]*$'` - test "X$tar_dest" == "X" && \ - fatal "ERROR: server response remote file is missing" - - tmpdir_server=`expr "$line" : 'sending: [^ ]* \([^ ]*\) [^ ]*$'` - test "X$tmpdir_server" == "X" && \ - fatal "ERROR: server response temp dir is missing" - - tmpdir_stap=`expr "$line" : 'sending: [^ ]* [^ ]* \([^ ]*\)$'` - test "X$tmpdir_stap" == "X" && \ - fatal "ERROR: server response stap temp dir is missing" - + # Make a place to receive the response file. + tar_server=`mktemp -t $tmpdir_prefix_client.server.tgz.XXXXXX` || \ + fatal "ERROR: cannot create temporary file " $tar_server # Retrieve the file - rsync -essh -a --delete root@$server:$tar_dest $tar_server || \ - fatal "ERROR: rsync of server response, $server:$tar_dest to $tar_server, failed" - echo "OK" >&3 + until nc $server $(($port + 1)) > $tar_server + do + sleep 1 + done } # function: unpack_response @@ -406,17 +385,45 @@ function receive_response { # Unpack the tar file received from the server and make the contents available # for printing the results and/or running 'staprun'. function unpack_response { + tmpdir_server=`mktemp -dt $tmpdir_prefix_client.server.XXXXXX` || \ + fatal "ERROR: cannot create temporary file " $tmpdir_server + # Unpack the server output directory - cd $tmpdir_client + cd $tmpdir_server tar -xzf $tar_server || \ fatal "ERROR: Unpacking of server response, $tar_server, failed" - # Create a local location for the server response. - local local_tmpdir_server_base=`basename $tar_server | sed 's,\.tgz,,'` - local local_tmpdir_server=`mktemp -dt $local_tmpdir_server_base.XXXXXX` || \ - fatal "ERROR: cannot create temporary directory " $local_tmpdir_server - - # Move the systemtap temp directory to our a local temp location, if -k + # Identify the server's request tree. The tar file should have expanded + # into a single directory named to match $tmpdir_prefix_server.?????? + # which should now be the only item in the current directory. + test "`ls | wc -l`" = 1 || \ + fatal "ERROR: Wrong number of files after expansion of server's tar file" + + tmpdir_server=`ls` + tmpdir_server=`expr "$tmpdir_server" : "\\\($tmpdir_prefix_server\\\\.......\\\)"` + + test "X$tmpdir_server" != "X" || \ + fatal "ERROR: server tar file did not expand as expected" + + # Check the contents of the expanded directory. It should contain: + # 1) a file called stdout + # 2) a file called stderr + # 3) a directory named to match stap?????? + test "`ls $tmpdir_server | wc -l`" = 3 || \ + fatal "ERROR: Wrong number of files after expansion of server's tar file" + test -f $tmpdir_server/stdout || \ + fatal "ERROR: `pwd`/$tmpdir_server/stdout does not exist or is not a regular file" + test -f $tmpdir_server/stderr || \ + fatal "ERROR: `pwd`/$tmpdir_server/stderr does not exist or is not a regular file" + + tmpdir_stap=`ls $tmpdir_server | grep stap` + tmpdir_stap=`expr "$tmpdir_stap" : "\\\(stap......\\\)"` + test "X$tmpdir_stap" = "X" && \ + fatal "ERROR: `pwd`/$tmpdir_server/stap?????? does not exist" + test -d $tmpdir_server/$tmpdir_stap || \ + fatal "ERROR: `pwd`/$tmpdir_server/$tmpdir_stap is not a directory" + + # Move the systemtap temp directory to a local temp location, if -k # was specified. if test $keep_temps = 1; then local local_tmpdir_stap=`mktemp -dt stapXXXXXX` || \ @@ -428,13 +435,17 @@ function unpack_response { sed -i "s,^Keeping temporary directory.*,Keeping temporary directory \"$local_tmpdir_stap\"," $tmpdir_server/stderr tmpdir_stap=$local_tmpdir_stap else - tmpdir_stap=$local_tmpdir_server/$tmpdir_stap + tmpdir_stap=`pwd`/$tmpdir_stap fi - # Move the extracted tree to our local location - mv $tmpdir_server/* $local_tmpdir_server + # Move the contents of the server's tmpdir down one level to the + # current directory (our local server tmpdir) + mv $tmpdir_server/* . 2>/dev/null rm -fr $tmpdir_server - tmpdir_server=$local_tmpdir_server + tmpdir_server=`pwd` + + # Make sure we own the systemtap temp directory if we are root. + test $EUID = 0 && chown $EUID:$EUID $tmpdir_stap } # function: find_and_connect_to_server @@ -443,11 +454,14 @@ function unpack_response { function find_and_connect_to_server { # Find a server server=`avahi-browse $avahi_service_tag --terminate -r 2>/dev/null | match_server` + port=`expr "$server" : '[^/]*/\(.*\)'` + server=`expr "$server" : '\([^/]*\)/.*'` + test "X$server" != "X" || \ fatal "ERROR: cannot find a server" - port=`expr "$server" : '[^/]*/\(.*\)'` - server=`expr "$server" : '\([^/]*\)/.*'` + test "X$port" != "X" || \ + fatal "ERROR: server port not provided" # Open a connection to the server if ! exec 3<> /dev/tcp/$server/$port; then @@ -500,7 +514,6 @@ function match_server { ;; txt ) sysinfo_server=`expr "$service_data" : '\[\"\([^]]*\)\"\]'` - sysinfo_server=`expr "$sysinfo_server" : '[^/]*/\(.*\)'` ;; * ) break ;; @@ -508,7 +521,6 @@ function match_server { done # It is a stap server, but is it compatible? - sysinfo_server="stap $sysinfo_server" if test "$sysinfo_server" != "`client_sysinfo`"; then continue fi @@ -534,9 +546,9 @@ function disconnect_from_server { # Write the stdout and stderr from the server to stdout and stderr respectively. function stream_output { # Output stdout and stderr as directed - cd $local_tmpdir_server - cat ${tmpdir_server}/stderr >&2 - eval cat ${tmpdir_server}/stdout $stdout_redirection + cd $tmpdir_server + cat stderr >&2 + eval cat stdout $stdout_redirection } # function: maybe_call_staprun @@ -558,7 +570,7 @@ function maybe_call_staprun { # Check the given server response for an error message. function check_server_error { echo $1 | grep -q "^ERROR:" && \ - fatal "Server:" "$@" + server_fatal "Server:" "$@" } # function: fatal [ MESSAGE ] @@ -566,6 +578,16 @@ function check_server_error { # Fatal error # Prints its arguments to stderr and exits function fatal { + echo $0: "$@" >&2 + cleanup + exit 1 +} + +# function: server_fatal [ MESSAGE ] +# +# Fatal error +# Prints its arguments to stderr and exits +function server_fatal { echo $0: "$@" >&2 cat <&3 >&2 cleanup diff --git a/stap-server b/stap-server index 1a2e7918f..11d6d81d9 100755 --- a/stap-server +++ b/stap-server @@ -21,6 +21,8 @@ function configuration { # Configuration tmpdir_prefix_client=stap.client tmpdir_prefix_server=stap.server + port=$1 + test "X$port" = "X" && port=65001 } # function: initialization @@ -31,54 +33,33 @@ function initialization { # Default options settings p_phase=5 keep_temps=0 - - # Make a temp directory to work in. - tmpdir_server=`mktemp -dt $tmpdir_prefix_server.XXXXXX` || \ - fatal "ERROR: cannot create temporary directory " $tmpdir_server - tmpdir_env=`dirname $tmpdir_server` } # function: receive_request # # Receive a tar file representing the request from the client: # The protocol is: -# client -> "request: $tmpdir_client" -# server -> "send: $tar_client" -# client: copies file to server:$tar_client -# client -> "waiting:" -# -# $tmpdir_client is provided on the request so that we know what -# the tar file will expand to. +# client -> "request:" +# server -> "ready:" +# client -> $tar_client function receive_request { - cd $tmpdir_server - # Request from the client is on stdin read line=$REPLY - # Extract the name of the client's temp directory. - tmpdir_client=`expr "$line" : 'request: \([^ ]*\)$'` - test "X$tmpdir_client" == "X" && \ - fatal "ERROR: client request temp dir name is missing" $tmpdir_server - tmpdir_client=$tmpdir_server/$tmpdir_client - - # Create the client's temp dir now to guarantee that it won't clash with - # any files we need to create later. - mkdir $tmpdir_client || \ - fatal "ERROR: cannot create client temp dir" $tmpdir_client + # Check to see that it is a client request + test "$line" = "request:" || \ + fatal "ERROR: client request, '$line' is incorrect" # Create a place to receive the client's tar file - tar_client=`mktemp -t $tmpdir_prefix_client.tgz.XXXXXX` || \ + tar_client=`mktemp -t $tmpdir_prefix_server.client.tgz.XXXXXX` || \ fatal "ERROR: cannot create temporary tar file " $tar_client # Request that the file be sent. - echo "send: $tar_client" + echo "ready:" - # Wait for confirmation that the tar file has arrived via rysnc - read - line=$REPLY - test "X$line" = "Xwaiting:" || \ - fatal "ERROR: client send confirmation, '$line', is incorrect" + # Receive the file. + nc -l $port < /dev/null > $tar_client } # function: unpack_request @@ -86,15 +67,31 @@ function receive_request { # Unpack the tar file received from the client and make the contents # available for use when running 'stap' function unpack_request { + # Make a temp directory to work in. + tmpdir_server=`mktemp -dt $tmpdir_prefix_server.XXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $tmpdir_server + tmpdir_env=`dirname $tmpdir_server` + cd $tmpdir_server # Unpack the tar file. tar -xzf $tar_client || \ fatal "ERROR: cannot unpack tar archive $tar_client" + # Identify the client's request tree. The tar file should have expanded + # into a single directory named to match $tmpdir_prefix_client.?????? + # which should now be the only item in the current directory. + test "`ls | wc -l`" = 1 || \ + fatal "ERROR: Wrong number of files after expansion of client's tar file" + + tmpdir_client=`ls` + tmpdir_client=`expr "$tmpdir_client" : "\\\($tmpdir_prefix_client\\\\.......\\\)"` + + test "X$tmpdir_client" != "X" || \ + fatal "ERROR: client tar file did not expand as expected" + # Move the client's temp directory to a local temp location - local tmpdir_client_base=`basename $tar_client | sed 's,\.tgz,,'` - local local_tmpdir_client=`mktemp -dt $tmpdir_client_base.XXXXXX` || \ + local local_tmpdir_client=`mktemp -dt $tmpdir_prefix_server.client.XXXXXX` || \ fatal "ERROR: cannot create temporary tar file " $local_tmpdir_client mv $tmpdir_client/* $local_tmpdir_client rm -fr $tmpdir_client @@ -114,19 +111,18 @@ function check_request { client_sysinfo=`read_data_file sysinfo` test "X$client_sysinfo" != "X" || exit 1 - # Extract the client's config info. - client_name=`expr "$client_sysinfo" : 'stap [^ ]* [^ ]* \([^ ]*\).*'` - client_sysinfo=`echo $client_sysinfo | sed s,$client_name,,` - - # Extract the server's config info. - server_sysinfo=`uname -sr` - server_name=`expr "$server_sysinfo" : '[^ ]* \([^ ]*\).*'` - server_sysinfo=`echo $server_sysinfo | sed s,$server_name,,` - local stap_version=`stap -V 2>&1 | grep version` - stap_version=`expr "$stap_version" : '.*version \([0-9./]*\).*'` - server_sysinfo="stap $stap_version $server_sysinfo" + check_compatibility "$client_sysinfo" `server_sysinfo` +} - 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`" + fi + echo $sysinfo_server } # function check_compaibility SYSINFO1 SYSINFO2 @@ -134,10 +130,9 @@ function check_request { # Make sure that systemtap as described by SYSINFO1 and SYSINFO2 are compaible function check_compatibility { # TODO: This needs work - # - In stap version x/y, require that the y matches # - Make sure the linux kernel matches exactly - local sysinfo1=`echo $1 | sed 's,stap [^/]*/,stap ,'` - local sysinfo2=`echo $2 | sed 's,stap [^/]*/,stap ,'` + local sysinfo1=$1 + local sysinfo2=$2 if test "$sysinfo1" != "$sysinfo2"; then error "ERROR: system configuration mismatch" @@ -361,7 +356,7 @@ function package_response { chmod +r $tar_server # Generate the tar file - tar -czphf $tar_server `basename $tmpdir_server` || \ + tar -czhf $tar_server `basename $tmpdir_server` || \ fatal "ERROR: tar of $tmpdir_server failed" } @@ -370,21 +365,11 @@ function package_response { # Notify the client that $tar_server is ready and wait for the client to take # it. # The protocol is: -# server -> "sending: $tar_server $tmpdir_server $tmpdir_stap" -# client: copies file from server:$tar_server -# client -> "OK" +# server -> "sending: $tmpdir_server $tmpdir_stap" +# server -> $tar_server function send_response { - # TODO needed for rsync from client to work - chmod +r $tmpdir_server - - # Tell the client where to get it. - echo "sending: $tar_server `basename $tmpdir_server` `basename $tmpdir_stap`" - - # Wait for the confirmation - read - line=$REPLY - test $line = "OK" || \ - fatal "ERROR: client final confirmation, '$line' is incorrect" + # Now send it + nc -l $port < $tar_server > /dev/null } # function: fatal [ MESSAGE ] @@ -421,7 +406,7 @@ function cleanup { #----------------------------------------------------------------------------- # Beginning of main line execution. #----------------------------------------------------------------------------- -configuration +configuration "$@" initialization receive_request unpack_request diff --git a/stap-serverd b/stap-serverd new file mode 100755 index 000000000..2c0743c08 --- /dev/null +++ b/stap-serverd @@ -0,0 +1,93 @@ +#!/bin/bash + +# Compile server manager for systemtap +# +# Copyright (C) 2008 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 publishes its presence on the network and then listens for +# incoming connections. When a connection is detected, the stap-server script +# is run to handle the request. + +# Catch ctrl-c +trap 'handle_sigint' SIGINT + +#----------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------- +# function: initialization PORT +function initialization { + # Default settings. + tmpdir_prefix_serverd=stap.serverd + avahi_type=_stap._tcp + port=$1 + test "X$port" = "X" && port=65000 +} + +# function: advertise_presence +# +# Advertise the availability of the server on the network. +function advertise_presence { + # Build up a string representing our server's properties. + # TODO: this needs fleshing out. + + local sysinfo=`uname -r` + local txt="$sysinfo" + + # Call avahi-publish-service to advertise our presence. + avahi-publish-service "Systemtap Compile Server on `uname -n`" \ + $avahi_type $port $txt > /dev/null 2>&1 & + + echo "Systemtap Compile Server on `uname -n` listening on port $port" +} + +# function: listen +# +# Listen for and handle requests to the server. +function listen { + # Work in a temporary directory + tmpdir=`mktemp -dt $tmpdir_prefix_serverd.XXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $tmpdir + cd $tmpdir + + # Create a fifo for communicating with the server + local fifo_name=$tmpdir_prefix_serverd.fifo + mknod $fifo_name p || \ + fatal "ERROR: cannot create temporary fifo " $tmpdir/$fifo_name + + # Loop forever accepting requests + while true + do + nc -l $port < $fifo_name | stap-server $((port + 1)) > $fifo_name 2>&1 + done +} + +# function: fatal [ MESSAGE ] +# +# Fatal error +# Prints its arguments to stderr and exits +function fatal { + echo "$@" >&2 + exit 1 +} + +# function: handle_sigint +# +# Terminate gracefully when SIGINT is received. +function handle_sigint { + echo "$0: received SIGINT. Exiting." + cd `dirname $tmpdir` + rm -fr $tmpdir + exit +} + +#----------------------------------------------------------------------------- +# Beginning of main line execution. +#----------------------------------------------------------------------------- +initialization "$@" +advertise_presence +listen