diff options
author | Dave Brolley <brolley@redhat.com> | 2009-12-21 19:26:16 -0500 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-12-21 19:26:16 -0500 |
commit | 600450900a5e98404c91104d2cb20cddce42838e (patch) | |
tree | e0a54b23be5755ec80c72f8b16a6281b5540c661 /stap-server | |
parent | d12a5be645d7036e7834308e714496f57adda852 (diff) | |
download | systemtap-steved-600450900a5e98404c91104d2cb20cddce42838e.tar.gz systemtap-steved-600450900a5e98404c91104d2cb20cddce42838e.tar.xz systemtap-steved-600450900a5e98404c91104d2cb20cddce42838e.zip |
PR 10905: initscript improvements.
Make the stap-server initscript available as $bindir/stap-server
Reimplement the stap-server initscript as a thin wrapper around
$bindir/stap-server.
Diffstat (limited to 'stap-server')
-rw-r--r--[-rwxr-xr-x] | stap-server | 1291 |
1 files changed, 846 insertions, 445 deletions
diff --git a/stap-server b/stap-server index d1731895..85e5bf19 100755..100644 --- a/stap-server +++ b/stap-server @@ -1,6 +1,6 @@ #!/bin/bash - -# Compile server for systemtap +# +# stap-server script for managing the systemtap compile server # # Copyright (C) 2008, 2009 Red Hat Inc. # @@ -8,505 +8,906 @@ # 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 provides management of systemtap compile servers as a service. +# See stap-server(8) for more information. -# 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 +. /etc/rc.d/init.d/functions -# Initialize the environment +# Systemtap function library . ${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" +prog=stap-server + +# Commands +STAP_START_SERVER=${stap_pkglibexecdir}stap-start-server +STAP_STOP_SERVER=${stap_pkglibexecdir}stap-stop-server +UNAME=/bin/uname + +# Default Global Configuration +CONFIG_FILE=$stap_sysconfdir/sysconfig/stap-server +CONFIG_PATH=$stap_sysconfdir/stap-server/conf.d +STAT_PATH=$stap_localstatedir/run/stap-server +LOG_FILE=$stap_localstatedir/log/stap-server.log + +# Default option settings +# Optional global config file +OPT_CONFIG_FILE= + +echo_usage () { + echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|status} [options]" + echo $"Options:" + echo $" -c configfile : specify additional global configuration file." + echo $" -a arch : specify the target architecture." + echo $" -r release : specify the kernel release." + echo $" -I path : augment the search path for tapsets." + echo $" -R path : specify the location of the systemtap runtime." + echo $" -B options : specify 'make' options for building systemtap modules." + echo $" -u username : specify the user who will run the server(s)." + echo $" -i : specify a server for each installed kernel release." + echo $" -n nickname : specify a server configuration by nickname." + echo $" -p pid : specify a server or server configuration by process id." + echo $"" + echo $"All options, may be specified more than once." + echo $"" + echo $"If -a is not specified, the default architecture is that of the host" + echo $"platform." + echo $"" + echo $"If -r is not specified, the default kernel release is that currently" + echo $"running on the host platform." + echo $"" + echo $"If -u is not specified, the default user is 'stap-server'" + echo $"" + echo $"Each -I and -B option specifies an additional path or option" + echo $"respectively. For other options, each new instance overrides the" + echo $"previous setting." + echo $"" + echo $"The -i option is a shortcut which specifies one server for each kernel" + echo $"release installed in /lib/modules/. Previous -I, -R, -B and -u" + echo $"options will be applied to each server, however previous -a options" + echo $"are ignored and the default architecture is used." + echo $"" + echo $"The -n option allows the specification of a server configuration by" + echo $"nickname. When -n is specified, a currently running server with the" + echo $"given nickname will be searched for. If no currently running server" + echo $"with the given nickname is found, a server configuration with the" + echo $"given nickname will be searched for in $stap_sysconfdir/stap-server/conf.d/*.conf." + echo $"If a server configuration for the given nickname is found, the -a, -r," + echo $"-I, -R, -B and -u options for that server will be used as if they were" + echo $"specified on the command line. If no configuration with the given" + echo $"nickname is found, and the action is 'start' (or an action behaving" + echo $"like 'start' (see below), the server will be started with the given" + echo $"nickname. If no configuration with the given nickname is found, and" + echo $"the action is not 'start' (or an action behaving" "like 'start'," + echo $"it is an error. If a nickname is not specified for a server, its" + echo $"nickname will be its process id." + echo $"" + echo $"The -p option allows the specification of a server configuration by" + echo $"process id. When -p is specified, a currently running server with the" + echo $"given process id will be searched for. If no such server is found," + echo $"it is an error. If a server with the given pid is found, the -a, -r," + echo $"-I, -R, -B and -u options for that server will be used as if they were" + echo $"specified on the command line." + echo $"" + echo $"The specified action is performed for the server(s) specified on the" + echo $"command line. If no servers are specified on the command line, the" + echo $"behavior is as follows:" + echo $"" + echo $" start: Start the servers configured in $stap_sysconfdir/stap-server/conf.d/*.conf." + echo $" If none are configured, start a server for the kernel release" + echo $" and architecture of the host platform." + echo $"" + echo $" stop: Stop all currently running servers." + echo $"" + echo $" restart: Restart all currently running servers. If no servers are running," + echo $" behave as if 'start' was specified." + echo $"" + echo $" condrestart: Restart all currently running servers. If no servers are running," + echo $" do nothing." + echo $"" + echo $" try-restart: Same as condrestart." + echo $"" + echo $" force-reload: Stop all currently running servers and behave as if 'start'" + echo $" was specified." + echo $"" + echo $" status: Report the status of all current running servers." + echo $"" +} - # 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" +#----------------------------------------------------------------- +# Helper functions +#----------------------------------------------------------------- +log () { # message + echo `LC_ALL=en date +"%b %e %T"`": $1" >> "$LOG_FILE" +} +clog () { # message [-n] + echo $2 "$1" + log "$1" +} +slog () { # message + logger "$1" # if syslogd is running, this message will be sent to syslog. + log "$1" +} +logex () { # command + eval log \"Exec: $@\" + "$@" >> "$LOG_FILE" 2>&1 + return $? +} +do_failure () { # message + slog "Error: $1" + failure "$1" +} +do_success () { # message + log "Pass: $1" + success "$1" +} - tmpdir_client=`ls | grep $stap_tmpdir_prefix_client.......\$` +#------------------------------------------------------------------ +# Parameter parsing and setup options +#------------------------------------------------------------------ +parse_args () { # arguments + local rc=0 + while [ -n "$1" ]; do + case "$1" in + -a) + OPT_SERVER_CMDS="$OPT_SERVER_CMDS ARCH='$2'" + shift 1 + ;; + -B) + OPT_SERVER_CMDS="$OPT_SERVER_CMDS BUILD='$2'" + shift 1 + ;; + -c) + OPT_CONFIG_FILE=$2 + shift 1 + ;; + -i) + process_i + ;; + -I) + OPT_SERVER_CMDS="$OPT_SERVER_CMDS INCLUDE='$2'" + shift 1 + ;; + -n) + process_n $2 + shift 1 + ;; + -p) + process_p $2 + test $? = 0 || rc=1 + shift 1 + ;; + -r) + process_r $2 + test $? = 0 || rc=1 + shift 1 + ;; + -R) + OPT_SERVER_CMDS="$OPT_SERVER_CMDS RUNTIME='$2'" + shift 1 + ;; + -u) + OPT_SERVER_CMDS="$OPT_SERVER_CMDS USER='$2'" + shift 1 + ;; + --) + ;; + *) + rc=1 + ;; + esac + shift 1 + done + + # Add an EXEC command to the end if any server options were specified + test -n "$OPT_SERVER_CMDS" && OPT_SERVER_CMDS="$OPT_SERVER_CMDS EXEC" + + test $rc != 0 && echo_usage + return $rc +} - test "X$tmpdir_client" != "X" || \ - fatal "Client zip file did not expand as expected" +# Process the -i flag. +process_i () { + cd /lib/modules + local release + for release in `ls`; do + test -n "$OPT_SERVER_CMDS" && OPT_SERVER_CMDS="$OPT_SERVER_CMDS EXEC" + process_r $release + done - # 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 + return 0 } -# 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 +# Process the -n flag. +process_n () { + local target_NICKNAME="$1" + + # Is there a running server with this nickname? + local pid=`get_server_pid_by_nickname "$target_NICKNAME"` + if [ -n "$pid" ]; then + # Read the configuration and add it to the configuration commands. + . $STAT_PATH/$pid + OPT_SERVER_CMDS="$OPT_SERVER_CMDS `echo_server_commands`" + return + fi + + # Is there a server configuration with this nickname? + for f in "$CONFIG_PATH"/*.conf; do + if [ -f "$f" ]; then + . "$f" + test "X$NICKNAME" = "X$target_NICKNAME" || continue + OPT_SERVER_CMDS="$OPT_SERVER_CMDS `echo_server_commands`" + return + fi + done - # Add the necessary info from files in our temporary directory. - cmdline=`read_data_file cmdline` - test "X$cmdline" != "X" || exit 1 + # No server configuration could be found for this nickname. Add a + # NICKNAME_NOT_FOUND=... command to the configuration commands. + OPT_SERVER_CMDS="$OPT_SERVER_CMDS NICKNAME_NOT_FOUND='$target_NICKNAME'" +} + +# Process the -p flag. +process_p () { + local pid="$1" - eval parse_options "$cmdline" + # Are we managing a server with the given pid? + test ! -f $STAT_PATH/$pid && echo "No stap-server running as pid $pid" && \ + exit 1 - client_sysinfo=`read_data_file sysinfo` - test "X$client_sysinfo" != "X" || exit 1 + # Add the configuration of the server running as $pid to OPT_SERVER_CMDS + . $STAT_PATH/$pid + OPT_SERVER_CMDS="$CONFIG_SERVER_CMDS `echo_server_commands`" - check_compatibility "$client_sysinfo" "`server_sysinfo`" + return 0 } -# 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`" +# Process the -r flag. +process_r () { + local first_char=`expr "$1" : '\(.\).*'` + + if test "$first_char" = "/"; then # fully specified path + local kernel_build_tree=$1 + local version_file_name="$kernel_build_tree/include/config/kernel.release" + # The file include/config/kernel.release within the kernel + # build tree is used to pull out the version information + local kernel_release=`cat $version_file_name 2>/dev/null` + if test "X$kernel_release" = "X"; then + echo "Missing $version_file_name" + return 1 + fi + OPT_SERVER_CMDS="$OPT_SERVER_CMDS RELEASE='$kernel_release'" + return 0 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 + # kernel release specified directly + OPT_SERVER_CMDS="$OPT_SERVER_CMDS RELEASE='$1'" + return 0 } -# 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 +load_config () { + # Include configs + if [ -f "$CONFIG_FILE" ]; then + . "$CONFIG_FILE" + fi + if [ -f "$OPT_CONFIG_FILE" ]; then + . "$OPT_CONFIG_FILE" + fi +} - # Close the file - exec 3<&- +# Default to the currently running kernel release +get_release () { + $UNAME -r +} - # Now read the entire file. - cat $1 | sed "s/$1: //" +# Default to the currently running kernel release +get_arch () { + stap_get_arch } -# 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 +echo_server_commands () { + # Echo the configuration command string. + echo -n "ARCH='$ARCH'" + echo -n " RELEASE='$RELEASE'" + echo -n " RUNTIME='$RUNTIME'" + for i in $INCLUDE; do + echo -n " INCLUDE='$i'" + done + for b in $BUILD; do + echo -n " BUILD='$b'" + done + echo -n " USER='$USER'" + echo -n " NICKNAME='$NICKNAME'" + echo +} - 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 +echo_server_options () { + # Echo the configuration options. + echo -n "-a '$ARCH'" + echo -n " -r '$RELEASE'" + test -n "$RUNTIME" && echo -n " -R '$RUNTIME'" + for i in $INCLUDE; do + echo -n " -I '$i'" + done + for b in $BUILD; do + echo -n " -B '$b'" done + test -n "$USER" && echo -n " -u '$USER'" + echo -n " -n '$NICKNAME'" + echo } -# 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 +load_server_config () { + CONFIG_SERVER_CMDS= + for f in "$CONFIG_PATH"/*.conf; do + if [ -f "$f" ]; then + # Obtain a configuration from each config file. + # Ensure that we get the correct defaults for items not specified. + local ARCH= + local BUILD= + local INCLUDE= + local RUNTIME= + local USER= + local RELEASE= + . "$f" + # Other options default to empty. These ones don't. + [ -z "$ARCH" ] && ARCH=`get_arch` + [ -z "$RELEASE" ] && RELEASE=`get_release` + [ -z "$USER" ] && USER=$STAP_USER + CONFIG_SERVER_CMDS="$CONFIG_SERVER_CMDS `echo_server_commands` EXEC" fi - stap_arg="$first" - advance_p=$(($advance_p + 1)) + done } -# function: process_e ARGUMENT -# -# Process the -e flag. -function process_e { - if test "X$e_script" = "X"; then - e_script="$1" - script_file= - fi +prepare_stat_dir () { + if [ ! -d "$STAT_PATH" ]; then + logex mkdir -p "$STAT_PATH" + [ $? -ne 0 ] && return 1 + fi + return 0 } -# 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 +prepare_log_dir () { + local log_path=`dirname "$LOG_FILE"` + if [ ! -d "$log_path" ]; then + mkdir -p "$log_path" + [ $? -ne 0 ] && return 1 + fi + return 0 } -# 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 +stat_file () { # server-spec + echo $STAT_PATH/$1 +} - eval ${stap_exec_prefix}stap "$stap_options" -k -p $server_p_phase \ - >> $tmpdir_server/stdout \ - 2>> $tmpdir_server/stderr +default_server_cmds () { + echo "EXEC" +} - stap_rc=$? +init_server_opts () { + ARCH=`get_arch` + RELEASE=`get_release` + BUILD= + INCLUDE= + NICKNAME= + NICKNAME_NOT_FOUND= + RUNTIME= + USER=$STAP_USER } -# 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 +server_still_running () { # PID + (ps -e | grep stap-serverd | grep -q $1) && return 0 # Still running + + rm -f $STAT_PATH/$1 + return 1 # Not running +} + +get_server_pid_by_config () { + # Need to save the config, since the process of checking the running + # servers alters it. + local target_ARCH="$ARCH" + local target_RELEASE="$RELEASE" + local target_INCLUDE="$INCLUDE" + local target_RUNTIME="$RUNTIME" + local target_BUILD="$BUILD" + local target_USER="$USER" + local target_NICKNAME="$NICKNAME" + + # Check the status file for each running server to see if it matches + # the one currently configured. We're checking for a given configuration, + # so don't compare the nickname. + for f in $STAT_PATH/*; do + test ! -e $f && continue + . $f + test "X$ARCH" = "X$target_ARCH" || continue + test "X$RELEASE" = "X$target_RELEASE" || continue + test "X$INCLUDE" = "X$target_INCLUDE" || continue + test "X$RUNTIME" = "X$target_RUNTIME" || continue + test "X$BUILD" = "X$target_BUILD" || continue + test "X$USER" = "X$target_USER" || continue + echo `basename $f` # Server has a pid + return + done + + ARCH="$target_ARCH" + RELEASE="$target_RELEASE" + INCLUDE="$target_INCLUDE" + RUNTIME="$target_RUNTIME" + BUILD="$target_BUILD" + USER="$target_USER" + NICKNAME="$target_NICKNAME" +} + +get_server_pid_by_nickname () { + # No need to save the current configuration. This function is not called + # in a context requiring it. + local target_NICKNAME="$1" + + # Check the status file for each running server to see if the nickname + # matches the one we want. + for f in $STAT_PATH/*; do + test ! -e $f && continue + . $f + test "X$NICKNAME" = "X$target_NICKNAME" || continue + echo `basename $f` # Server with nickname was found + return + done +} + +managed_servers () { + if [ ! -d $STAT_PATH ]; then + echo "" + return 1 + fi + cd $STAT_PATH + local list=`ls` + if [ -z "$list" ]; then + echo "" + return 1 + fi + + echo "$list" +} + +eval_server_command () { + local cmd="$1" + + # Accumulate the results of BUILD and INCLUDE commands. + if echo $cmd | grep -q ^BUILD; then + local prevBUILD="$BUILD" + eval $cmd + BUILD="$prevBUILD $BUILD" + BUILD=`echo $BUILD | sed 's/^ //'` + elif echo $cmd | grep -q ^INCLUDE; then + local prevINCLUDE="$INCLUDE" + eval $cmd + INCLUDE="$prevINCLUDE $INCLUDE" + INCLUDE=`echo $INCLUDE | sed 's/^ //'` + else + eval $cmd + fi +} - # Add the contents of the stap temp directory to the server output directory - ln -s $tmpdir_stap `basename $tmpdir_stap` +start_server () { + clog $"Starting $prog for $RELEASE $ARCH: " -n - # 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 + # Is there already a server running for the requested kernel release + # and arch? + local server_pid=`get_server_pid_by_config` + if test -n "$server_pid"; then + if server_still_running $server_pid; then + do_success $"$prog start `echo_server_options`" + return 0 # Success 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 + # Construct the server start command. + local server_cmd="$STAP_START_SERVER -r '$RELEASE' -a '$ARCH'" + for b in $BUILD; do + server_cmd="$server_cmd -B '$b'" + done + for i in $INCLUDE; do + server_cmd="$server_cmd -I '$i'" + done + test -n "$RUNTIME" && server_cmd="$server_cmd -R '$RUNTIME'" + server_cmd="$server_cmd --log=$LOG_FILE" + + # Start the server here. + local pid + if [ -n "$USER" ]; then + pid=`runuser -s /bin/bash - $USER -c "$server_cmd"` + else + pid=`eval $server_cmd` + fi + if [ $? != 0 -o -z "$pid" ]; then + if [ -n "$pid" ]; then + rm -f $STAT_PATH/$pid + fi + do_failure $"$prog start `echo_server_options`" + return 1 # Failure fi - # The return status of the stap command. - echo -n $stap_rc > rc -} + # Nickname defaults to the pid. + test -z "$NICKNAME" && NICKNAME="$pid" -# function: package_response -# -# Package the server's temp directory into a form suitable for sending to the -# client. -function package_response { - cd $tmpdir_env + # Write the configuration to the status file. + local server_status_file=$STAT_PATH/$pid + echo "ARCH='$ARCH'" > $server_status_file + echo "USER='$USER'" >> $server_status_file + echo "BUILD='$BUILD'" >> $server_status_file + echo "INCLUDE='$INCLUDE'" >> $server_status_file + echo "NICKNAME='$NICKNAME'" >> $server_status_file + echo "RUNTIME='$RUNTIME'" >> $server_status_file + echo "RELEASE='$RELEASE'" >> $server_status_file - # Compress the server's temporary directory into a .zip archive. - (rm $zip_server && zip -r $zip_server `basename $tmpdir_server` > /dev/null) - return $? + do_success $"$prog start `echo_server_options`" } -# 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 +start () { # server-cmds + prepare_stat_dir + if [ $? -ne 0 ]; then + do_failure $"Failed to make stat directory ($STAT_PATH)" + return 1 + fi + + # Start the specified servers + server_cmds="$1" + # If none specified, start the configured servers + if [ -z "$server_cmds" ]; then + load_server_config + server_cmds="$CONFIG_SERVER_CMDS" + + # If none configured, start the default servers + [ -z "$server_cmds" ] && server_cmds=`default_server_cmds` + fi + + # Start each requested server in turn + local rc=0 + local first=1 + init_server_opts + local cmd + local prevCmd + for cmd in $server_cmds; do + prevCmd=$cmd + # Evaluate commands until the EXEC command is found. + if test "$cmd" != "EXEC"; then + eval_server_command $cmd + # A specified nickname only sticks if it is the final command. + # Otherwise, we have a configuration based on a nicknamed + # configuration. + echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME="" + continue + fi + # If a nickname was specified, but the corresponding config was not found, + # then it is the nickname for this new configuration. + if test -n "$NICKNAME_NOT_FOUND"; then + NICKNAME="$NICKNAME_NOT_FOUND" + NICKNAME_NOT_FOUND= + fi + + # Start the configured server + test $first = 0 && echo + first=0 + start_server || rc=1 + + # Don't use the same nickname for the next server. + NICKNAME= + done + + return $rc } -# Non fatal error -# Prints its arguments to stderr but does not exit -function error { - echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr +stop () { # server-cmds + local first=1 + local server_list= + server_cmds="$1" + if [ -n "$server_cmds" ]; then + # Get the pids of all the requested servers. + init_server_opts + local cmd + local prevCmd + for cmd in $server_cmds; do + prevCmd=$cmd + # Evaluate commands until the EXEC command is found. + if test "$cmd" != "EXEC"; then + eval_server_command $cmd + # A specified nickname only sticks if it is the final command. + # Otherwise, we have a configuration based on a nicknamed + # configuration. + echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME="" + continue + fi + # If a nickname was specified, but the corresponding config was not + # found, it is an error. + if test -n "$NICKNAME_NOT_FOUND"; then + clog "No configuration found for the nickname '$NICKNAME_NOT_FOUND'" -n + NICKNAME="$NICKNAME_NOT_FOUND" + do_failure $"$prog stop `echo_server_options`" + NICKNAME_NOT_FOUND= + rc=1 + continue + fi + + # Get the pid for this server, if it's running + local server_pid=`get_server_pid_by_config` + if test -n "$server_pid"; then + server_list="$server_list $server_pid" + continue + fi + + # This server is not running, but give a success stop status anyway. + test $first = 0 && echo + first=0 + clog $"Stopping $prog for $RELEASE $ARCH: " -n + do_success $"$prog stop `echo_server_options`" + done + else + server_list=`managed_servers` + if [ -z "$server_list" ]; then + clog $"Stopping $prog: " -n + do_success $"$prog: No managed servers to stop" + return 0 + fi + fi + + # Stop each server in turn + local rc=0 + local pid + for pid in $server_list; do + . $STAT_PATH/$pid + + test $first = 0 && echo + first=0 + clog $"Stopping $prog for $RELEASE $ARCH: " -n + + local this_rc=0 + if server_still_running $pid; then + if [ -n "$USER" ]; then + runuser -s /bin/bash - $USER -c "$STAP_STOP_SERVER $pid" + else + eval $STAP_STOP_SERVER $pid + fi + if [ $? != 0 ]; then + do_failure $"$prog stop `echo_server_options`" + this_rc=1 + rc=1 + fi + fi + if [ $this_rc = 0 ]; then + rm -f $STAT_PATH/$pid + do_success $"$prog stop `echo_server_options`" + fi + done + + return $rc } -# 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 +status () { # server-list + local rc=0 + + # Report status for the specified servers or all running servers, if none + # specified. + local server_list= + server_cmds="$1" + if [ -n "$server_cmds" ]; then + # Get the pids of all the requested servers. + init_server_opts + local cmd + local prevCmd + for cmd in $server_cmds; do + prevCmd=$cmd + # Evaluate commands until the EXEC command is found. + if test "$cmd" != "EXEC"; then + eval_server_command $cmd + # A specified nickname only sticks if it is the final command. + # Otherwise, we have a configuration based on a nicknamed + # configuration. + echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME="" + continue + fi + # If a nickname was specified, but the corresponding config was not + # found, say so. + if test -n "$NICKNAME_NOT_FOUND"; then + echo "No configuration found for the nickname '$NICKNAME_NOT_FOUND'" + NICKNAME_NOT_FOUND= + rc=3 + continue + fi + + # Get the pid for this server, if it's running + local server_pid=`get_server_pid_by_config` + if test -n "$server_pid"; then + server_list="$server_list $server_pid" + continue + fi + # This server is not running + echo "stap-server `echo_server_options`" + rc=3 + done + else + server_list=`managed_servers` + if [ -z "$server_list" ]; then + echo "No managed stap-server is running" + return 3 + fi + fi + + # Get status of each server in turn + local pid + for pid in $server_list; do + . $STAT_PATH/$pid + if ! server_still_running $pid; then + echo "stap-server `echo_server_options` started as PID $pid is no longer running" + rc=1 + continue + fi + echo "stap-server `echo_server_options` running as PID $pid" + done + + return $rc } -# function: terminate -# -# Terminate gracefully. -function terminate { - # Clean up - cleanup - exit 1 +# Restart or start if not running +function restart () { # server-cmds + # Restart the specified servers or all servers, if none specified. + local server_cmds="$1" + if [ -z "$server_cmds" ]; then + local server_list=`managed_servers` + local pid + for pid in $server_list; do + . $STAT_PATH/$pid + server_cmds="$server_cmds `echo_server_commands` EXEC" + done + fi + + # Stop the specified servers, or all if none specified + stop "$server_cmds" + local rc=$? + echo + + # Restart the same servers. If none were specified then + # start the configured or default server(s)). + start "$server_cmds" + local this_rc=$? + [ $this_rc != 0 ] && rc=$this_rc + + return $rc } -#----------------------------------------------------------------------------- -# Beginning of main line execution. -#----------------------------------------------------------------------------- -initialization "$@" -unpack_request -check_request -call_stap -create_response -package_response -cleanup +# Restart only if running +function condrestart () { # server-list + # Restart the specified servers or all servers, if none specified, + # but only if they are already running. + local server_cmds="$1" + if [ -z "$server_cmds" ]; then + local server_list=`managed_servers` + local pid + for pid in $server_list; do + . $STAT_PATH/$pid + server_cmds="$server_cmds `echo_server_commands` EXEC" + done + # No server specified or running? + if [ -z "$server_cmds" ]; then + clog "No managed stap-server is running" -n + do_success "No managed stap-server is running" + return 0 + fi + fi + + # For each server in the list, stop it if it is running + local start_cmds= + local first=1 + local server_cmd= + local cmd + for cmd in $server_cmds; do + # Execute and collect commands until the EXEC command is found. + server_cmd="$server_cmd $cmd" + if test "$cmd" != "EXEC"; then + eval_server_command $cmd + continue + fi + + test $first = 0 && echo + first=0 + + # Now see if this server is running + if ! status "$server_cmd" >/dev/null 2>&1; then + clog $"$prog for $RELEASE $ARCH is not running" -n + do_success "$prog `echo_server_options` is not running" + server_cmd= + continue + fi + + start_cmds="$start_cmds $server_cmd" + + stop "$server_cmd" + this_rc=$? + [ $this_rc != 0 ] && rc=$this_rc + + server_cmd= + done + + # Now restart the servers that were running + if [ "X$start_cmds" != "X" ]; then + echo + start "$start_cmds" + local this_rc=$? + [ $this_rc != 0 ] && rc=$this_rc + fi + + return $rc +} -exit 0 +#------------------------------------------------------------------ +# Mainline script +#------------------------------------------------------------------ +CMD=$1 +shift 1 + +prepare_log_dir +if [ $? -ne 0 ]; then + echo $"Failed to make log directory (`dirname $LOG_FILE`)" >&2 + exit 1 +fi + +OPTS=`getopt -s bash -u -o 'a:B:c:iI:n:p:r:R:u:' -- $@` +if [ $? -ne 0 ]; then + echo "Error: Argument parse error: $@" >&2 + echo_usage + exit 2 +fi + +# Initialize server specs +OPT_SERVER_CMDS= +parse_args $OPTS || exit 2 +load_config + +RETVAL=0 + +case $CMD in + start) + # Start specified servers. If none specified, start configured servers + start "$OPT_SERVER_CMDS" + RETVAL=$? + ;; + stop) + # Stop specified servers + stop "$OPT_SERVER_CMDS" + RETVAL=$? + ;; + # Restart specified servers + restart) + restart "$OPT_SERVER_CMDS" + RETVAL=$? + ;; + # Restart specified servers if they are running + condrestart|try-restart) + condrestart "$OPT_SERVER_CMDS" + RETVAL=$? + ;; + # Give status on specified servers + status) + status "$OPT_SERVER_CMDS" + exit $? + ;; + # Reloading config without stop/restart is not supported + reload) + RETVAL=3 + ;; + # Reload config with stop/start + force-reload) + # stop all running servers + stop + echo + # Restart specified servers + # If none specified, restart configured servers + start "$OPT_SERVER_CMDS" + RETVAL=$? + ;; + usage|*) + echo_usage + RETVAL=0 + ;; +esac + +echo +exit $RETVAL |