summaryrefslogtreecommitdiffstats
path: root/initscript/systemtap.in
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-01-30 18:54:06 -0500
committerMasami Hiramatsu <mhiramat@redhat.com>2009-01-30 18:54:06 -0500
commit9a8d8be369cd1d2ac148b367e1c4b74ab9a005ba (patch)
treeeee895a1ac6b4a94f268647b031708fc17e102dc /initscript/systemtap.in
parent255b5e73f14c9fc72e5566edf595ab8df184f14f (diff)
downloadsystemtap-steved-9a8d8be369cd1d2ac148b367e1c4b74ab9a005ba.tar.gz
systemtap-steved-9a8d8be369cd1d2ac148b367e1c4b74ab9a005ba.tar.xz
systemtap-steved-9a8d8be369cd1d2ac148b367e1c4b74ab9a005ba.zip
PR6936: Add systemtap initscript and systemtap-initscript subpackage.
Diffstat (limited to 'initscript/systemtap.in')
-rw-r--r--initscript/systemtap.in664
1 files changed, 664 insertions, 0 deletions
diff --git a/initscript/systemtap.in b/initscript/systemtap.in
new file mode 100644
index 00000000..eaa1d969
--- /dev/null
+++ b/initscript/systemtap.in
@@ -0,0 +1,664 @@
+#!/bin/bash
+#
+# systemtap Startup script for systemtap scrips
+#
+# chkconfig: - 00 99
+# description: Systemtap is a programable kernel/application tracing tool.
+# config: /etc/systemtap/config
+# config: /etc/systemtap/conf.d
+### BEGIN INIT INFO
+# Provides: Systemtap scripts startup
+# Required-Start: $local_fs
+# Required-Stop: $local_fs
+# Short-Description: start and stop systemtap scripts
+# Description: Systemtap is a programable kernel/application tracing tool.
+### END INIT INFO
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+prog=systemtap
+
+# Commands
+STAP=@bindir@/stap
+STAPRUN=@bindir@/staprun
+UNAME=/bin/uname
+LSMOD=/sbin/lsmod
+
+# Path setup
+SCRIPT_PATH=/etc/systemtap/script.d
+CONFIG_PATH=/etc/systemtap/conf.d
+CACHE_PATH=/var/cache/systemtap
+STAT_PATH=/var/run/systemtap
+TEMP_PATH=/tmp
+LOG_FILE=/var/log/systemtap.log
+
+# FAIL unless all scripts succeeded to run
+PASSALL=yes
+
+# Always follows script dependencies
+RECURSIVE=no
+
+# Automatically recompile scripts if caches are old or do not exist.
+AUTOCOMPILE=yes
+
+# Start these scripts by default. If omitted, all scripts are started.
+DEFAULT_START=
+
+# Allow cache only scripts
+ALLOW_CACHEONLY=no
+
+# Optional settings
+CONFIG=/etc/systemtap/config
+SCRIPTS=
+KRELEASE=`uname -r`
+OPT_RECURSIVE=
+OPT_SCRIPTS=
+OPTS=
+OPT_ASSUMEYES=
+
+echo_usage () {
+ echo $"Usage: $prog {start|stop|restart|status|compile|cleanup} [option]"
+ echo $"Options:"
+ echo $" -c configfile : specify config file"
+ echo $" -r kernelrelease: specify kernel release version"
+ echo $" -R : recursively dependency checking"
+ echo $" -y : answer yes for all questions."
+ echo $" script(s) : specify systemtap scripts"
+}
+
+#-----------------------------------------------------------------
+# 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_warning () { # message
+ slog "Warning: $1"
+ warning "$1"
+}
+do_failure () { # message
+ slog "Error: $1"
+ failure "$1"
+}
+do_success () { # message
+ log "Pass: $1"
+ success "$1"
+}
+# Normalize options
+check_bool () { # value
+ case $1 in
+ n|N|no|No|NO|0)
+ return 0;;
+ y|Y|yes|Yes|YES|1)
+ return 1;;
+ *)
+ return 2;;
+ esac
+}
+ask_yesno () { # message
+ local yn ret=2
+ [ "$OPT_ASSUMEYES" ] && return 1
+ while [ $ret -eq 2 ]; do
+ echo -n "$1 [y/N]: "
+ read yn
+ [ -z "$yn" ] && return 0
+ check_bool $yn
+ ret=$?
+ done
+ return $ret
+}
+
+#------------------------------------------------------------------
+# Parameter parsing and setup options
+#------------------------------------------------------------------
+parse_args () { # arguments
+ while [ -n "$1" ]; do
+ case "$1" in
+ -c)
+ CONFIG=$2
+ shift 1
+ ;;
+ -r)
+ KRELEASE=$2
+ shift 1
+ ;;
+ -R)
+ OPT_RECURSIVE=1
+ ;;
+ -y)
+ OPT_ASSUMEYES=1
+ ;;
+ --)
+ ;;
+ *)
+ OPT_SCRIPTS=$OPT_SCRIPTS\ $1
+ ;;
+ esac
+ shift 1
+ done
+}
+
+CMD=$1
+shift 1
+OPTS=`getopt -s bash -u -o 'r:c:R' -- $@`
+if [ $? -ne 0 ]; then
+ slog "Error: Argument parse error: $@"
+ failure $"parse error"
+ echo_usage
+ exit 3
+fi
+parse_args $OPTS
+
+# Include configs
+. "$CONFIG"
+
+for f in "$CONFIG_PATH"/*.conf; do
+ if [ -f "$f" ]; then
+ . "$f"
+ fi
+done
+
+check_bool $PASSALL
+PASSALL=$?
+check_bool $RECURSIVE
+RECURSIVE=$?
+if [ "$OPT_RECURSIVE" ]; then # -r option overrides RECURSIVE.
+ RECURSIVE=1
+fi
+check_bool $AUTOCOMPILE
+AUTOCOMPILE=$?
+CACHE_PATH="$CACHE_PATH/$KRELEASE"
+
+check_bool $ALLOW_CACHEONLY
+ALLOW_CACHEONLY=$?
+
+__get_all_scripts () {
+ local s
+ if [ $ALLOW_CACHEONLY -eq 1 ]; then
+ for s in "$CACHE_PATH"/*.ko; do
+ if [ -f "$s" ]; then
+ basename "$s" | sed s/\.ko$//g
+ fi
+ done
+ fi
+ for s in "$SCRIPT_PATH"/*.stp; do
+ if [ -f "$s" ]; then
+ basename "$s" | sed s/\.stp$//g
+ fi
+ done
+}
+
+get_all_scripts() {
+ __get_all_scripts | sort | uniq
+}
+
+if [ -z "$OPT_SCRIPTS" ]; then
+ SCRIPTS=`get_all_scripts | xargs`
+ RECURSIVE=1
+else
+ SCRIPTS="$OPT_SCRIPTS"
+fi
+
+#------------------------------------------------------------------
+# Main routine
+#------------------------------------------------------------------
+NR_FAILS=0
+might_fail () { # message exitcode
+ if [ $PASSALL -eq 1 ]; then
+ do_failure "$1"
+ echo
+ [ -z "$2" ] && exit 1
+ exit $2
+ else
+ log "Warning: "$1
+ NR_FAILS=$((NR_FAILS+1))
+ return 0
+ fi
+}
+might_success () { # message
+ if [ $NR_FAILS -ne 0 ]; then
+ log "Warning: $NR_FAILS failure occured."
+ do_warning "$1"
+ else
+ do_success "$1"
+ fi
+ return 0
+}
+
+get_all_runnings () {
+ local f
+ for f in "$STAT_PATH"/*; do
+ if [ -f "$f" ]; then
+ basename "$f"
+ fi
+ done
+}
+
+get_daemon_pid () { # script
+ cat "$STAT_PATH/$1"
+}
+
+check_running () { # script
+ local m f
+ f="$STAT_PATH/$1"
+ m=`$LSMOD | grep "^$1 "`
+ if [ "$m" ]; then
+ [ -f "$f" ] && return 0 # running
+ return 4 # another script is running
+ else
+ [ -f "$f" ] && return 1 # dead, but pidfile remains
+ return 3 # dead
+ fi
+}
+
+# check whether a script cache need to be updated.
+check_cache () { # script opts
+ local s tmp tmp2
+ s=$1; shift 1
+ [ ! -f "$CACHE_PATH/$s.ko" -o ! -f "$CACHE_PATH/$s.opts" ] && return 1
+ if [ $ALLOW_CACHEONLY -ne 1 -o -f "$SCRIPT_PATH/$s.stp" ]; then
+ [ "$SCRIPT_PATH/$s.stp" -nt "$CACHE_PATH/$s.ko" ] && return 2
+ fi
+ tmp=`head -n 1 "$CACHE_PATH/$s.opts"`
+ tmp2=`$UNAME -a`
+ [ "$tmp" != "$tmp2" ] && return 3
+ tmp=`tail -n 1 "$CACHE_PATH/$s.opts"`
+ tmp2="$*"
+ [ "$tmp" != "$tmp2" ] && return 4
+ return 0
+}
+
+stap_getopt () { # opts
+ local ret
+ # TODO: support quoted options
+ getopt -s bash -u \
+ -l 'kelf,kmap::,ignore-vmlinux,ignore-dwarf,vp:' \
+ -o 'hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:F' -- $@
+ ret=$?
+ [ $ret -ne 0 ] && slog "Failed to parse parameters. ($@)"
+ return $ret
+}
+
+get_compile_opts () { # opts
+ local opts o skip
+ opts=`stap_getopt $*`
+ [ $? -ne 0 ] && return 1
+ skip=0
+ for o in $opts; do
+ if [ $skip -ne 0 ]; then skip=0; continue; fi
+ case $o in
+ -p|-m|-r|-c|-x|-e|-s|-o)
+ skip=1 ;;
+ -h|-V|-k)
+ ;;
+ *)
+ echo -n $o" " ;;
+ esac
+ done
+}
+
+get_run_opts () { # normalized_opts
+ local opts o show
+ opts=`stap_getopt $*`
+ [ $? -ne 0 ] && return 1
+ show=0
+ for o in $opts; do
+ case $o in
+ -c|-x|-s|-o)
+ [ $o == '-s' ] && o='-b'
+ echo -n $o" "
+ show=1
+ ;;
+ *)
+ if [ $show -ne 0 ]; then
+ echo -n $o" "
+ show=0
+ fi
+ ;;
+ esac
+ done
+}
+
+prepare_cache_dir () {
+ if [ ! -d "$CACHE_PATH" ]; then
+ logex mkdir -p "$CACHE_PATH"
+ [ $? -ne 0 ] && return 1
+ fi
+ return 0
+}
+
+prepare_stat_dir () {
+ if [ ! -d "$STAT_PATH" ]; then
+ logex mkdir -p "$STAT_PATH"
+ [ $? -ne 0 ] && return 1
+ fi
+ return 0
+}
+
+compile_script () { # script checkcache
+ local opts f tmpdir ret
+ eval f="$SCRIPT_PATH/$1.stp"
+ if [ ! -f "$f" ]; then
+ if [ $ALLOW_CACHEONLY -eq 1 ]; then
+ clog "Warning: no script file($f). Use compiled cache."
+ return 0
+ else
+ clog "Error: no script file($f)."
+ return 1
+ fi
+ fi
+
+ eval opts=\$$1_OPT
+ opts=`get_compile_opts $opts`
+ [ $? -ne 0 ] && return 2
+
+ if [ "$2" = "check" ]; then
+ check_cache $1 $opts
+ [ $? -eq 0 ] && return 0 # already compiled
+ if [ $AUTOCOMPILE -eq 0 ]; then
+ slog "No valid cache for $1"
+ return 1
+ fi
+ fi
+
+ clog " Compiling $1 ... " -n
+ tmpdir=`mktemp -d -p "$TEMP_PATH" cache.XXXXXXXX`
+ if [ $? -ne 0 ]; then
+ clog "failed to create temporary directory."
+ return 1
+ fi
+ pushd "$tmpdir" &> /dev/null
+ logex $STAP -m "$1" -p4 -r $KRELEASE $opts "$f"
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ $UNAME -a > "$1.opts"
+ echo $opts >> "$1.opts"
+ logex mv "$1.ko" "$1.opts" "$CACHE_PATH/"
+ ret=$?
+ else
+ slog "Failed to compile script($1)."
+ fi
+ popd &> /dev/null
+ rm -rf $tmpdir
+ [ $ret -eq 0 ] && clog "done" || clog "error"
+ return $ret
+}
+
+# dependency resolver
+__SORTED=
+__follow_dependency () { # script requesters
+ local opts r reqs s ret
+ s=$1
+ shift 1
+ r=`echo \ $*\ | grep \ $s\ `
+ if [ -n "$r" ]; then
+ might_fail $"Dependency loop detected on $s"
+ return 1
+ fi
+ r=`echo \ $__SORTED\ | grep \ $s\ `
+ [ -n "$r" ] && return 0 # already listed up
+ eval reqs=\$${s}_REQ
+ if [ -n "$reqs" ]; then
+ for r in $reqs; do
+ __follow_dependency $r $s $*
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ return $ret # if one of requires failed, we can't run this script.
+ fi
+ done
+ fi
+ echo -n "$s "
+ return 0
+}
+
+sort_dependency () { # scripts
+ local s r=0
+ __SORTED=
+ for s in $*; do
+ __SORTED="$__SORTED "`__follow_dependency $s`
+ [ $? -ne 0 ] && return 1
+ done
+ echo $__SORTED
+ return 0
+}
+
+start_script () { # script
+ local tmpdir s=$1
+ check_running $s
+ ret=$?
+ [ $ret -eq 0 ] && return 0 # already running
+ if [ $ret -eq 4 ]; then
+ clog "$s is dead, but another script is running."
+ return 4
+ fi
+
+ compile_script $s check
+ ret=$?
+ [ $ret -ne 0 ] && return $ret
+
+ eval opts=\$${s}_OPT
+ opts=`get_run_opts $opts`
+ [ $? -ne 0 ] && return 2
+
+ clog " Starting $1 ... " -n
+ tmpdir=`mktemp -d -p "$TEMP_PATH" cache.XXXXXXXX` # bz7097
+ if [ $? -ne 0 ]; then
+ clog "failed to create temporary directory."
+ return 1
+ fi
+ pushd "$tmpdir" &> /dev/null
+ logex $STAPRUN -L $opts "$CACHE_PATH/$s.ko"
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ # TODO: store daemon pid after supporting on-file flight recorder
+ echo 0 > "$STAT_PATH/$s"
+ fi
+ popd &> /dev/null
+ rm -rf "$tmpdir"
+ [ $ret -eq 0 ] && clog "done" || clog "error"
+ return $ret
+}
+
+start () {
+ local scripts s ret
+ clog $"Starting $prog: " -n
+
+ if [ -n "$DEFAULT_START" -a -z "$OPT_SCRIPTS" ]; then
+ SCRIPTS="$DEFAULT_START"
+ fi
+
+ if [ -z "$SCRIPTS" ]; then
+ do_warning $"no scripts exist."
+ return 5 # program is not installed
+ fi
+
+ prepare_stat_dir
+ if [ $? -ne 0 ]; then
+ do_failure $"Failed to make stat directory ($STAT_PATH)"
+ return 1
+ fi
+ prepare_cache_dir
+ if [ $? -ne 0 ]; then
+ do_failure $"Failed to make cache directory ($CACHE_PATH)"
+ return 1
+ fi
+
+ if [ $RECURSIVE -eq 1 ]; then
+ SCRIPTS=`sort_dependency $SCRIPTS`
+ if [ $? -ne 0 ]; then
+ do_failure $"Failed to sort dependency"
+ return 6 # program is not configured
+ fi
+ fi
+ for s in $SCRIPTS; do
+ start_script "$s"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ might_fail $"Failed to run \"$s\". ($ret)"
+ fi
+ done
+ might_success $"$prog startup"
+ return 0
+}
+
+stop_script () { # script
+ local p
+ check_running "$1"
+ ret=$?
+ [ $ret -eq 1 ] && rm -f "$STAT_PATH/$1"
+ [ $ret -ne 0 ] && return 0
+
+ p=`get_daemon_pid $1`
+ if [ $p -ne 0 ]; then
+ logex killall -TERM $p
+ else
+ logex $STAPRUN -d "$1"
+ fi
+ [ $? -ne 0 ] && return 1
+ rm -f "$STAT_PATH/$1"
+ return $?
+}
+
+stop () {
+ local s sl=
+ clog $"Stopping $prog: " -n
+ [ -z "$OPT_SCRIPTS" ] && SCRIPTS=`get_all_runnings`
+ if [ $RECURSIVE -eq 1 ]; then
+ SCRIPTS=`sort_dependency $SCRIPTS`
+ if [ $? -ne 0 ]; then
+ do_failure $"Failed to sort dependency"
+ return 6 # program is not configured
+ fi
+ fi
+ for s in $SCRIPTS; do
+ sl="$s $sl"
+ done
+ for s in $sl; do
+ stop_script $s
+ [ $? -ne 0 ] && might_fail $"Failed to run \"$s\". "
+ done
+ might_success $"$prog stopping "
+ return 0
+}
+
+status () {
+ local s pid ret r
+ [ -z "$SCRIPTS" ] && SCRIPTS=`get_all_runnings`
+ ret=3
+ for s in $SCRIPTS; do
+ check_running $s
+ r=$?
+ [ $ret -ne 0 ] && ret=$r
+ case $r in
+ 0)
+ pid=`get_daemon_pid $s`
+ [ $pid -ne 0 ] && pid="($pid)" || pid=
+ echo $"$s$pid is running..." ;;
+ 1|3) echo $"$s is stopped" ;;
+ 4) echo $"$s is dead, but another script is running.";;
+ esac
+ done
+ return $ret
+}
+
+compile () {
+ local s ss
+ clog $"Compiling $prog: " -n
+ prepare_cache_dir
+ if [ $? -ne 0 ]; then
+ do_failure $"Failed to make cache directory ($CACHE_PATH)"
+ return 1
+ fi
+ for s in $SCRIPTS; do
+ ss="$ss "`ls "$CACHE_PATH/$s.ko" "$CACHE_PATH/$s.opts" 2> /dev/null`
+ done
+ ss=`echo -n $ss`
+ if [ "$ss" ]; then
+ clog "Updating caches: $ss"
+ ask_yesno "Do you really want to update above caches"
+ [ $? -eq 0 ] && return 0
+ fi
+ for s in $SCRIPTS; do
+ compile_script $s nocheck
+ [ $? -ne 0 ] && might_fail $"$s compilation failed "
+ done
+ might_success $"$prog compiled "
+ return 0
+}
+
+# Cleanup caches
+cleanup () {
+ local s ss ret
+ clog $"Cleaning up $prog: " -n
+ if [ ! -d "$CACHE_PATH" ]; then
+ do_success "no cache"
+ return 0
+ fi
+
+ for s in $SCRIPTS; do
+ ss="$ss "`ls "$CACHE_PATH/$s.ko" "$CACHE_PATH/$s.opts" 2> /dev/null`
+ done
+ ss=`echo -n $ss`
+ if [ "$ss" ]; then
+ echo "Removing caches: $ss"
+ ask_yesno "Do you really want to remove above caches"
+ [ $? -eq 0 ] && return 0
+ for s in $SCRIPTS; do
+ logex rm -f "$CACHE_PATH/$s.ko" "$CACHE_PATH/$s.opts"
+ [ $? -ne 0 ] && might_fail $"failed to clean cache $s.ko"
+ done
+ might_success "done"
+ return 0
+ fi
+}
+
+RETVAL=0
+
+case $CMD in
+ start)
+ start
+ RETVAL=$?
+ ;;
+ stop)
+ stop
+ RETVAL=$?
+ ;;
+ restart|force-reload)
+ stop
+ start
+ RETVAL=$?
+ ;;
+ status)
+ status
+ RETVAL=$?
+ ;;
+ compile)
+ compile
+ RETVAL=$?
+ ;;
+ cleanup)
+ cleanup
+ RETVAL=$?
+ ;;
+ *)
+ echo_usage
+ RETVAL=3
+ ;;
+esac
+
+echo
+exit $RETVAL