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 | |
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.
-rw-r--r-- | Makefile.am | 14 | ||||
-rw-r--r-- | Makefile.in | 10 | ||||
-rw-r--r-- | initscript/stap-server.in | 879 | ||||
-rwxr-xr-x | stap-env | 1 | ||||
-rw-r--r--[-rwxr-xr-x] | stap-server | 1291 | ||||
-rw-r--r-- | stap-server-connect.c | 6 | ||||
-rwxr-xr-x | stap-server-request | 512 | ||||
-rw-r--r-- | stap-server.8.in | 31 | ||||
-rw-r--r-- | systemtap.spec | 3 |
9 files changed, 1402 insertions, 1345 deletions
diff --git a/Makefile.am b/Makefile.am index 5f02c4e5..4d0f2e1e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,8 +42,8 @@ pkglibexec_SCRIPTS += stap-gen-cert stap-authorize-cert if BUILD_SERVER man_MANS += stap-client.8 stap-server.8 stap-authorize-server-cert.8 pkglibexec_PROGRAMS += stap-client-connect stap-server-connect -bin_SCRIPTS += stap-client stap-authorize-server-cert -pkglibexec_SCRIPTS += stap-serverd stap-server stap-find-servers \ +bin_SCRIPTS += stap-client stap-server stap-authorize-server-cert +pkglibexec_SCRIPTS += stap-serverd stap-server-request stap-find-servers \ stap-start-server stap-find-or-start-server stap-stop-server endif endif @@ -121,7 +121,7 @@ install-scripts: install-binSCRIPTS install-pkglibexecSCRIPTS sed -i -e "s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(bindir)/$$f; \ done for f in $(pkglibexec_SCRIPTS); do \ - sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir),;s,pkglibexecdir=.*,pkglibexecdir=$(pkglibexecdir)/,;s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(pkglibexecdir)/$$f; \ + sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir),;s,pkglibexecdir=.*,pkglibexecdir=$(pkglibexecdir)/,;s,localstatedir=.*,localstatedir=$(localstatedir),;s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(pkglibexecdir)/$$f; \ done endif endif @@ -259,6 +259,10 @@ install-data-local: i_cmd="$(INSTALL_DATA)"; fi; \ $$i_cmd -D $$f $(DESTDIR)$(docdir)/examples/$$f; done) test -e $(DESTDIR)$(sysconfdir)/systemtap || mkdir -p $(DESTDIR)$(sysconfdir)/systemtap +if BUILD_SERVER + test -e $(DESTDIR)$(localstatedir)/run/stap-server || mkdir -p $(DESTDIR)$(localstatedir)/run/stap-server + test -e $(DESTDIR)$(localstatedir)/log || mkdir -p $(DESTDIR)$(localstatedir)/log +endif TEST_COV_DIR = coverage @@ -302,6 +306,10 @@ uninstall-local: done rm -rf $(DESTDIR)$(sysconfdir)/systemtap rm -rf $(DESTDIR)$(docdir)/examples +if BUILD_SERVER + rm -rf $(DESTDIR)$(localstatedir)/run/stap-server + rm -f $(DESTDIR)$(localstatedir)/log/stap-server.log +endif SUBDIRS = doc grapher DIST_SUBDIRS = testsuite $(SUBDIRS) diff --git a/Makefile.in b/Makefile.in index 2d1fe5df..538698d7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -45,8 +45,8 @@ pkglibexec_PROGRAMS = stapio$(EXEEXT) $(am__EXEEXT_2) $(am__EXEEXT_3) @BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_7 = stap-gen-cert stap-authorize-cert @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_8 = stap-client.8 stap-server.8 stap-authorize-server-cert.8 @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_9 = stap-client-connect stap-server-connect -@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_10 = stap-client stap-authorize-server-cert -@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_11 = stap-serverd stap-server stap-find-servers \ +@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_10 = stap-client stap-server stap-authorize-server-cert +@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_11 = stap-serverd stap-server-request stap-find-servers \ @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ stap-start-server stap-find-or-start-server stap-stop-server @BUILD_TRANSLATOR_FALSE@stap_DEPENDENCIES = @@ -1839,7 +1839,7 @@ cscope: @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ sed -i -e "s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(bindir)/$$f; \ @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ done @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ for f in $(pkglibexec_SCRIPTS); do \ -@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir),;s,pkglibexecdir=.*,pkglibexecdir=$(pkglibexecdir)/,;s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(pkglibexecdir)/$$f; \ +@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir),;s,pkglibexecdir=.*,pkglibexecdir=$(pkglibexecdir)/,;s,localstatedir=.*,localstatedir=$(localstatedir),;s,\$${PKGLIBEXECDIR},$(pkglibexecdir)/," $(DESTDIR)$(pkglibexecdir)/$$f; \ @BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ done @BUILD_ELFUTILS_TRUE@@BUILD_TRANSLATOR_TRUE@stamp-elfutils: config.status @BUILD_ELFUTILS_TRUE@@BUILD_TRANSLATOR_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -C build-elfutils all bin_PROGRAMS= @@ -1894,6 +1894,8 @@ install-data-local: i_cmd="$(INSTALL_DATA)"; fi; \ $$i_cmd -D $$f $(DESTDIR)$(docdir)/examples/$$f; done) test -e $(DESTDIR)$(sysconfdir)/systemtap || mkdir -p $(DESTDIR)$(sysconfdir)/systemtap +@BUILD_SERVER_TRUE@ test -e $(DESTDIR)$(localstatedir)/run/stap-server || mkdir -p $(DESTDIR)$(localstatedir)/run/stap-server +@BUILD_SERVER_TRUE@ test -e $(DESTDIR)$(localstatedir)/log || mkdir -p $(DESTDIR)$(localstatedir)/log gcov: @-$(MAKE) clean CXXFLAGS="-g -fprofile-arcs -ftest-coverage" all check @@ -1935,6 +1937,8 @@ uninstall-local: done rm -rf $(DESTDIR)$(sysconfdir)/systemtap rm -rf $(DESTDIR)$(docdir)/examples +@BUILD_SERVER_TRUE@ rm -rf $(DESTDIR)$(localstatedir)/run/stap-server +@BUILD_SERVER_TRUE@ rm -f $(DESTDIR)$(localstatedir)/log/stap-server.log check-local: SRCDIR=`cd $(srcdir); pwd`; \ diff --git a/initscript/stap-server.in b/initscript/stap-server.in index 7b951d15..6001180a 100644 --- a/initscript/stap-server.in +++ b/initscript/stap-server.in @@ -8,880 +8,5 @@ # config: /etc/sysconfig/stap-server # config: /etc/stap-server/conf.d -. /etc/rc.d/init.d/functions - -# Systemtap function library -. @libexecdir@/systemtap/stap-env - -prog=stap-server - -# Commands -STAP_START_SERVER=@libexecdir@/systemtap/stap-start-server -STAP_STOP_SERVER=@libexecdir@/systemtap/stap-stop-server -UNAME=/bin/uname - -# Default Global Configuration -CONFIG_FILE=@sysconfdir@/sysconfig/stap-server -CONFIG_PATH=@sysconfdir@/stap-server/conf.d -STAT_PATH=@localstatedir@/run/stap-server -LOG_FILE=@localstatedir@/log/stap-server.log -STAP_USER=stap-server - -# 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 @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 @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 $"" -} - -#----------------------------------------------------------------- -# 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" -} - -#------------------------------------------------------------------ -# 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 -} - -# 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 - - return 0 -} - -# 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 - - # 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" - - # Are we managing a server with the given pid? - test ! -f $STAT_PATH/$pid && echo "No stap-server running as pid $pid" && \ - 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`" - - return 0 -} - -# 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 - - # kernel release specified directly - OPT_SERVER_CMDS="$OPT_SERVER_CMDS RELEASE='$1'" - return 0 -} - -load_config () { - # Include configs - if [ -f "$CONFIG_FILE" ]; then - . "$CONFIG_FILE" - fi - if [ -f "$OPT_CONFIG_FILE" ]; then - . "$OPT_CONFIG_FILE" - fi -} - -# Default to the currently running kernel release -get_release () { - $UNAME -r -} - -# Default to the currently running kernel release -get_arch () { - stap_get_arch -} - -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'" - # The NICKNAME= command must be last. See start (). - echo -n " NICKNAME='$NICKNAME'" - echo -} - -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 -} - -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 - done -} - -prepare_stat_dir () { - if [ ! -d "$STAT_PATH" ]; then - logex mkdir -p "$STAT_PATH" - [ $? -ne 0 ] && return 1 - fi - return 0 -} - -stat_file () { # server-spec - echo $STAT_PATH/$1 -} - -default_server_cmds () { - echo "EXEC" -} - -init_server_opts () { - ARCH=`get_arch` - RELEASE=`get_release` - BUILD= - INCLUDE= - NICKNAME= - NICKNAME_NOT_FOUND= - RUNTIME= - USER=$STAP_USER -} - -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 -} - -start_server () { - clog $"Starting $prog for $RELEASE $ARCH: " -n - - # 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 - - # 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=`runuser -s /bin/bash - $USER -c "$server_cmd"` - 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 - - # Nickname defaults to the pid. - test -z "$NICKNAME" && NICKNAME="$pid" - - # 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 - - do_success $"$prog start `echo_server_options`" -} - -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 -} - -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 - runuser -s /bin/bash - $USER -c "$STAP_STOP_SERVER $pid" - 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 -} - -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 -} - -# 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 -} - -# 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 -} - -#------------------------------------------------------------------ -# Mainline script -#------------------------------------------------------------------ -CMD=$1 -shift 1 -OPTS=`getopt -s bash -u -o 'a:B:c:iI:n:p:r:R:u:' -- $@` -if [ $? -ne 0 ]; then - slog "Error: Argument parse error: $@" - failure $"parse error" - 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 +# Call the installed stap-server script. +STAP_USER=stap-server @bindir/stap-server "$@" @@ -18,6 +18,7 @@ stap_exec_prefix= stap_sysconfdir=`pwd`/net stap_pkglibexecdir= +stap_localstatedir=`pwd`/net/var # General configuration stap_tmpdir_prefix_client=stap.client 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 diff --git a/stap-server-connect.c b/stap-server-connect.c index e063fd91..cf0e5a65 100644 --- a/stap-server-connect.c +++ b/stap-server-connect.c @@ -467,9 +467,9 @@ handle_connection(PRFileDesc *tcpSocket) } #endif - /* Call the stap-server script. */ + /* Call the stap-server-request script. */ stap_server_prefix = getenv("SYSTEMTAP_SERVER_SCRIPTS") ?: PKGLIBDIR; - cmdline = PORT_Alloc(strlen (stap_server_prefix) + sizeof ("/stap-server") + 1 + + cmdline = PORT_Alloc(strlen (stap_server_prefix) + sizeof ("/stap-server-request") + 1 + sizeof (requestFileName) + 1 + sizeof (responseDirName) + 1 + sizeof (responseZipName) + 1 + @@ -482,7 +482,7 @@ handle_connection(PRFileDesc *tcpSocket) goto cleanup; } - sprintf (cmdline, "%s/stap-server %s %s %s %s '%s'", stap_server_prefix, + sprintf (cmdline, "%s/stap-server-request %s %s %s %s '%s'", stap_server_prefix, requestFileName, responseDirName, responseZipName, dbdir, stapOptions); rc = system (cmdline); 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 diff --git a/stap-server.8.in b/stap-server.8.in index 436e4670..3994a17d 100644 --- a/stap-server.8.in +++ b/stap-server.8.in @@ -1,12 +1,15 @@ .\" -*- nroff -*- .TH STAP-SERVER 8 @DATE@ "Red Hat" .SH NAME -stap\-server \- systemtap server service +stap\-server \- systemtap server management .SH SYNOPSIS .br -.B service stap\-server +[ +.B service +] +.B stap\-server { .B start | @@ -35,7 +38,7 @@ front end. Each server advertises its presence and configuration on the local network using mDNS (\fIavahi\fR) allowing for automatic detection by clients. .PP -The stap\-server service aims to provide: +The stap\-server script aims to provide: .IP \(bu 4 management of systemtap compile servers as a service. .IP \(bu 4 @@ -186,7 +189,8 @@ that server will be used as if they were specified on the command line. .TP \fB\-u\fR \fIuser\-name\fR Each systemtap compile server is normally run by the user name -\fistap\-server\fR, +\fistap\-server\fR (for the initscript) or as the user invoking +\fIstap-server\fR, unless otherwise configured (see \fBFILES\fR). This option specifies the user name used to run the server(s). The user name specified must be a member of the group \fIstap\-server\fR. @@ -225,7 +229,8 @@ Specifies the absolute path of the log file .TP .B STAP_USER Specifies the userid which will be used to run the server(s) -(default: \fIstap\-server\fR). +(default: for the initscript \fIstap\-server\fR, otherwise the user running +\fIstap-server\fR). .SH Individual Server Configuration @@ -300,12 +305,12 @@ that server\[aq]s certificate to the client\[aq]s database of trusted servers. .PP -For the \fIstap\-server\fR service, on the local host, this is handled +For the \fIstap\-server\fR initscript, on the local host, this is handled automatically. When the \fIsystemtap\-server\fR package is installed, the server\[aq]s certificate for the default user (\fIstap\-server\fR) is automatically generated and installed. This means that servers started by the -\fIstap\-server\fR service, +\fIstap\-server\fR initscript, with the default user, are automatically trusted by clients on the local host. @@ -323,29 +328,29 @@ manual page for a collection of sample \fIsystemtap\fR scripts. .PP To start the configured servers, or the default server, if none are configured: .PP -.B \& $ service stap\-server start +.B \& $ [ service ] stap\-server start .PP To start a server for each kernel installed in /lib/modules: .PP -.B \& $ service stap\-server start \-i +.B \& $ [ service ] stap\-server start \-i .PP To obtain information about the running server(s): .PP -.B \& $ service stap\-server status +.B \& $ [ service ] stap\-server status .PP To start a server like another one, except targeting a different architecture, by referencing the first server\[aq]s nickname: .PP -.B \& $ service stap\-server start \-n \fINICKNAME\fR \-a \fIARCH\fR +.B \& $ [ service ] stap\-server start \-n \fINICKNAME\fR \-a \fIARCH\fR .PP To stop one of the servers by referencing its process id (obtained by running \fBstap\-server status\fR): .PP -.B \& $ service stap\-server stop \-p \fIPID\fR +.B \& $ [ service ] stap\-server stop \-p \fIPID\fR .PP To stop all running servers: .PP -.B \& $ service stap\-server stop +.B \& $ [ service ] stap\-server stop .SH SAFETY AND SECURITY Systemtap is an administrative tool. It exposes kernel internal data diff --git a/systemtap.spec b/systemtap.spec index 6a9a17bd..74ec47b3 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -431,7 +431,7 @@ exit 0 %files server %defattr(-,root,root) %{_bindir}/stap-authorize-server-cert -%{_libexecdir}/%{name}/stap-server +%{_bindir}/stap-server %{_libexecdir}/%{name}/stap-serverd %{_libexecdir}/%{name}/stap-start-server %{_libexecdir}/%{name}/stap-find-servers @@ -439,6 +439,7 @@ exit 0 %{_libexecdir}/%{name}/stap-stop-server %{_libexecdir}/%{name}/stap-gen-cert %{_libexecdir}/%{name}/stap-server-connect +%{_libexecdir}/%{name}/stap-server-request %{_libexecdir}/%{name}/stap-sign-module %{_mandir}/man8/stap-server.8* %{_mandir}/man8/stap-authorize-server-cert.8* |