#!/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 and other termination signals trap 'terminate' SIGTERM 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 port2=$(($port + 1)) if netstat -atn | awk '{print $4}' | cut -f2 -d: | egrep -q "^($port|$port2)\$"; then # Whoops, the port is busy; try another one. initialization $((1024+($port + $RANDOM)%64000)) fi } # 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 -rvm` local txt="sysinfo=$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 first=1 set -o pipefail # We want the status of 'nc' not 'stap-server'. while true do # Run this in the background and wait for it. This way any signals # received (i.e. SIGTERM) will be processed. Make sure we don't # advertise our presence until we're actually listening. for ((attempt=0; $attempt < 5; ++attempt)) do nc -l $port < $fifo_name | stap-server $((port + 1)) > $fifo_name 2>&1 & if test $first = 1; then advertise_presence first=0 fi wait %nc rc=$? if test $rc = 127 -o $rc = 0; then break; # success fi sleep 1 done if test $attempt = 5; then fatal "ERROR: cannot listen on port $port. rc==$rc" fi done set +o pipefail # restore } # function: fatal [ MESSAGE ] # # Fatal error # Prints its arguments to stderr and exits function fatal { echo "$@" >&2 terminate exit 1 } # function: terminate # # Terminate gracefully. function terminate { echo "$0: Exiting" # Kill the running 'avahi-publish-service' job kill -s SIGTERM %avahi-publish-service 2> /dev/null wait %avahi-publish-service 2> /dev/null # Kill any running 'nc -l' job. kill -s SIGTERM "%nc -l" 2> /dev/null wait "%nc - l" 2> /dev/null # Clean up cd `dirname $tmpdir` rm -fr $tmpdir exit } #----------------------------------------------------------------------------- # Beginning of main line execution. #----------------------------------------------------------------------------- initialization "$@" listen