From 9a8d8be369cd1d2ac148b367e1c4b74ab9a005ba Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 30 Jan 2009 18:54:06 -0500 Subject: [PATCH] PR6936: Add systemtap initscript and systemtap-initscript subpackage. --- ChangeLog | 7 + NEWS | 5 + configure | 3 +- configure.ac | 2 +- initscript/ChangeLog | 6 + initscript/README.initscript | 355 +++++++++++++++++++ initscript/config | 20 ++ initscript/systemtap.in | 664 +++++++++++++++++++++++++++++++++++ systemtap.spec | 40 +++ 9 files changed, 1100 insertions(+), 2 deletions(-) create mode 100644 initscript/ChangeLog create mode 100644 initscript/README.initscript create mode 100644 initscript/config create mode 100644 initscript/systemtap.in diff --git a/ChangeLog b/ChangeLog index 62708e24b..618588a89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-01-30 Masami Hiramatsu + + PR6936 + * configure.ac (AC_CONFIG_FILES): Add initscript/systemtap.in. + * configure: Regenerated. + * systemtap.spec: Add systemtap-initscript subpackage. + 2009-01-30 Dave Brolley * Makefile.am (install-scripts): New target. Set exec_prefix and diff --git a/NEWS b/NEWS index 47d4199b7..25ebcccf9 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ * What's new +- Systemtap initscript is available. This initscript allows you to run + systemtap scripts as system services (in flight recorder mode) and + control those scripts individually. + See README.initscript for details. + - The stap "-r DIR" option may be used to identify a hand-made kernel build directory. The tool determines the appropriate release string automatically from the directory. diff --git a/configure b/configure index 4f63ffda2..7bf7bb146 100755 --- a/configure +++ b/configure @@ -7937,7 +7937,7 @@ _ACEOF ac_config_headers="$ac_config_headers config.h:config.in" -ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5" +ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5 initscript/systemtap" @@ -8644,6 +8644,7 @@ do "man/stapprobes.socket.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.socket.5" ;; "man/stapprobes.tcp.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.tcp.5" ;; "man/stapprobes.udp.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.udp.5" ;; + "initscript/systemtap") CONFIG_FILES="$CONFIG_FILES initscript/systemtap" ;; "run-stap") CONFIG_FILES="$CONFIG_FILES run-stap" ;; *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 diff --git a/configure.ac b/configure.ac index a0d18c29e..542b3b487 100644 --- a/configure.ac +++ b/configure.ac @@ -335,7 +335,7 @@ dnl Don't use this directly (when not given it is set to NONE). AC_DEFINE_UNQUOTED(STAP_PREFIX, "$prefix", [configure prefix location]) AC_CONFIG_HEADERS([config.h:config.in]) -AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5) +AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5 initscript/systemtap) AC_CONFIG_SUBDIRS(testsuite) AC_CONFIG_FILES([run-stap], [chmod +x run-stap]) AC_OUTPUT diff --git a/initscript/ChangeLog b/initscript/ChangeLog new file mode 100644 index 000000000..3672a901a --- /dev/null +++ b/initscript/ChangeLog @@ -0,0 +1,6 @@ +2009-01-30 Masami Hiramatsu + + PR6936 + * systemtap.in: First commit of systemtap initscript. + * README.initscript: Ditto. + * config: Ditto. diff --git a/initscript/README.initscript b/initscript/README.initscript new file mode 100644 index 000000000..f566cf710 --- /dev/null +++ b/initscript/README.initscript @@ -0,0 +1,355 @@ +Systemtap initscript +Version 0.2 +Author: Masami Hiramatsu + +INDEX +===== +1. Introduction +2. Usage +3. Files +4. Configuration Format +5. How to use + +1. Introduction +=============== +Systemtap initscript aims to provide +- running systemtap script as a service with dependency. +- easy way to control(start/stop) those scripts individually. +The dependency means that which user-defined systemtap script is required by +other script (Here the scripts don't include tapsets). This dependency +will be useful for users who use -DRELAY_HOST and -DRELAY_GUEST. + +2. Usage +======== +2.1 Synopsis + +/sbin/service systemtap {start|stop|restart|status|compile|cleanup} \ + [-r kernelrelease] [-c config] [-R] [-y] [script(s)] + +2.2 Commands + You have to specify one of the below commands. + +2.2.1 start + Run script(s). If the script(s) is already started, the command will be + ignored. If it fails to start, return FAIL. If AUTOCOMPILE option is 'yes' + (see 4.1.9), this will try to compile or update the specified script when + one of the below condition is true. + - compiled cache file does not exist. + - mtime (modified time stamp) of original script file is newer than compiled + script cache. + - script options which is used when compiling(see 4.2.1) has been changed. + - result of `uname -a` has been changed. + If no scripts specified from command line, it starts all scripts in the script + directory or the scripts specified by DEFAULT_START in config (see 4.1.10). + +2.2.2 stop + Stop script(s). If the script(s) is already stopped, this will be ignored. + If it fails to stop, return FAIL. + If no scripts specified from command line, it stops all running scripts. + +2.2.3 restart + Stop and start script(s) again. + +2.2.4 status + Show running script(s) status and dependency. + +2.2.5 compile + Compile script(s) on the specified kernel. This command takes '-r' option + which specifies the release of the kernel(see 2.3.4) on which you would + like to compile script(s). This command asks user whether it can overwrite +existing caches. + +2.2.6 cleanup + Cleanup compiled script(s) from cache directory(see 3.4). This command also + takes '-r' option. If '-r' option is omitted, cleanup all caches for running + kernel. This command asks user whether it can remove caches. + +2.3 Options + Systemtap initscript can have some options. However, since user can't pass + these options on boot, these options are only for testing or managing scripts + after booting. + +2.3.1 -c config_path + You can specify configuration path of this initscript. + +2.3.2 script(s) + You can specify individual scripts to the commands. If you omit to specify + any script, systemtap initscript will execute the command with all scripts + in the script directory(except 'start' and 'stop' command, see 2.2.1 and + 2.2.2). + +2.3.3 -R + If this option is specified, systemtap initscript will try to solve + dependency of specified script(s). This option is always set if you don't + specify any script(s) from command line. + +2.3.4 -r kernelrelease + You can specify release version of the kernel(e.g. 2.6.26.1). This option + is valid only with compile and cleanup commands. + +2.3.5 -y + Answer yes for all questions. + +2.4 Misc +2.4.1 Service Priority + Each initscript has execution priority. Since user would like to trace + other services by using systemtap, systemtap initscript should have the + highest priority. + +3. Files +======== +3.1 initscript + /etc/init.d/systemtap + + This file is an executable bash script. + +3.2 Configurations + Configuration files are written in bash script. + +3.2.1 Global config file + /etc/systemtap/config + + This config file is for global parameters(see 4.1). + +3.2.2 Script config files + /etc/systemtap/conf.d/*.conf + + The config files under this directory are for each scripts or script groups + (see 4.2). + +3.3 Script directory + /etc/systemtap/script.d/ + + Systemtap initscript finds systemtap scripts from this directory. + +3.3.1 Scripts in the directory + /etc/systemtap/script.d/.stp + + Systemtap scripts stored in the script directory must have ".stp" suffix. + +3.4 Cache directory + /var/cache/systemtap// + + Systemtap initscript stores compiled scripts in this directory. + +3.4.1 Compiled scripts (or script caches) + /var/cache/systemtap//.ko + /var/cache/systemtap//.opts + + *.ko file is the compiled script, and *.opts is the file which stores + stap options and uname -a. + +3.5 Message Log + /var/log/systemtap.log + + All messages including compilation errors and detailed messages are sent + to this file. + Some error and warning messages are also sent to console and syslogd (syslog + output is optional, because this service will start before syslog). + +3.7 Status files + /var/run/systemtap/ + + +4. Configuration Format +======================= +Configuration file allows us +- specifying options for each script +- supporting flight recorder mode (on file or memory) + +4.1 Global Parameters + +4.1.1 SCRIPT_PATH + Specify the absolute path of the script directory. + (default: /etc/systemtap/script.d) + +4.1.2 CONFIG_PATH + Specify the absolute path of the script config directory. + (default: /etc/systemtap/conf.d) + +4.1.3 CACHE_PATH + Specify the absolute path of the parent directory of the cache directory. + (default: /var/cache/systemtap) + +4.1.4 TEMP_PATH + Specify the absolute path of the temporary directory on which systemtap + initscript make temporary directories to compile scripts. + (default: /tmp) + +4.1.5 STAT_PATH + Specify the absolute path of the running status directory. + (default: /var/run/systemtap) + +4.1.6 LOG_FILE + Specify the absolute path of the log file + (default: /var/log/systemtap.log) + +4.1.7 PASSALL + If this is set 'yes', systemtap initscript will fail when it fails + to run one of the scripts. If not, systemtap initscript will not + fail(just warn). + (default: yes) + +4.1.8 RECURSIVE + If this is set 'yes', systemtap initscript will always follow script + dependencies. This means, you don't need to specify '-R' option. This flag is + effective only if you specify script(s) from command line. + (default: no) + +4.1.9 AUTOCOMPILE + If this is set 'yes', systemtap initscript automatically tries to compile + specified script if there is no valid cache. Otherwides, it just fails to + run script(s). + (default: yes) + +4.1.10 DEFAULT_START + Specify scripts which will be started by default. If omitted (or empty), + all scripts in the script directory will be started. + (default: "") + +4.1.11 ALLOW_CACHEONLY + If this is set 'yes', systemtap initscript list up cache-only scripts too. + *NOTE*: systemtap initscript will load unexpected obsolate caches with this + option. You should check cache directory before enabling this option. + (default: no) + +4.2 Script Parameters + +4.2.1 _OPT + Specify options passed to stap command for each script. "script-name" is the + name of the script file without the suffix extension(.stp). + Some options are just ignored. And even if you don't specify -F option, + systemtap initscript always add it for flight recorder mode. + - Below options are ignored when compiling script. + -p,-m,-r,-c,-x,-e,-s,-o,-h,-V,-k + - Below options are ignored when starting script. + -h,-V,-M,-v,-t,-p,-I,-e,-R,-r,-m,-k,-g,-P,-D,-b,-u,-q,-w,-l,-d,-L,-F, and + other long options. + +4.2.2 _REQ + Specify script dependency(which script this script requires). + For example, "foo.stp" script requires(or run after) "bar.stp" script, set + + foo_REQ="bar" + + If the script requires many scripts, set all scripts separated by spaces. + + foo_REQ="bar baz" + +4.3 Configuration Example + +4.3.1 Global Config Example +--- +SCRIPT_PATH=/var/systemtap/script.d/ +PASSALL=yes +RECURSIVE=no +--- + +4.3.2 Script Config Example +--- +script1_OPT="-o /var/log/script1.out -DRELAYHOST=group1" +script2_OPT="-DRELAYGUEST=group1" +script2_REQ=script1 +--- + +5. How to use +============= + +5.1 Package Installation + After installing systemtap package, install systemtap-initscript package. + # yum install systemtap-initscript + This package will include initscript and default configuration file and + other files. + +5.2 Script installation +5.2.1 Installing script files + Copy a systemtap script ("script1.stp") into script directory. + # cp script1.stp /etc/systemtap/script.d/ + +5.2.2 Configuration script options + Add configuration file to specify options. + # vi /etc/systemtap/conf.d/group1 + script1_OPT="-o /var/log/group1.log -DRELAYHOST=group1" + +5.2.3 Installing script file with dependency + For example, a script("script2.stp") which shares buffer with another + script("script1.stp"), there is a dependency. In this case, you just do + as following. + + # cp script2.stp /etc/systemtap/script.d/ + # vi /etc/systemtap/conf.d/group1 + script2_OPT="-DRELAYGUEST=group1" + script2_REQ=script1 + + In this case, if stap fails to run script1.stp, systemtap initscript will + not run script2.stp. + +5.3 Testing + After installing all scripts, please make sure to run service successfully. + # service systemtap start + # service systemtap stop + If there is no error, we are ready to use it. + +5.4 Service Enabling + After all test passed, enable systemtap initscript. + # chkconfig systemtap on + +5.5 Adding script +5.5.1 Installing and configuring new scripts + Copy new systemtap script("script3.stp") into script directory. + # cp script3.stp /etc/systemtap/script.d/ + and configure it. + # vi /etc/systemtap/conf.d/group1 + script3_OPT="-DRELAYGUEST=group1" + script3_REQ="script1" + +5.5.2 Start new script + If you've already started systemtap initscript, just start new script. + # service systemtap start script3 + +5.6 Deleting script +5.6.1 Deleting old script + Remove old script ("script2.stp") and remove configure lines + # rm /etc/systemtap/script.d/script2.stp + # vi /etc/systemtap/conf.d/group1 + (delete script2_OPT and script2_REQ) + +5.6.2 Stopping old script and cleanup + Stop old script. + # service systemtap stop script2 + And cleanup the script caches. + # service systemtap cleanup script2 + +5.7 Updating kernel + Usually, you don't need to do anything. Systemtap initscript checks the + kernel version when starting the service, and compile scripts. + (If you would like to use compiled scripts due to lack of compiler or + debuginfo on the system, see 5.8) + However, if you want to avoid compiling when booting system, you can prepare + script caches for new kernel. + # service systemtap compile -r + +5.8 Using with compiled scripts + Sometimes, production systems don't have any compilation environment. Even + though, you can use systemtap initscript with compiled scripts as script + caches, which are compiled on other machine (but same software environment). + +5.8.1 Preparing compiled scripts + As described in 5.2, installing scripts and configure it on the compiling + machine (which has compilation environment). + After that, compile those scripts. + # service systemtap compile -r + And package the compiled scripts and configuration file. + # tar czf stap-scripts-.tar.gz \ + /var/cache/systemtap/ /etc/systemtap/conf.d/ + And copy this package to the target machine. + +5.8.2 Installing pre-compiled scripts + On the target machine, unpackage the compiled scripts into cache + directory. + # tar xzf stap-scripts-.tar.gz -C /var/cache/systemtap/ + # mv /var/cache/systemtap/ /etc/systemtap/conf.d/ + At last, set AUTOCOMPILE=no and ALLOW_CACHEONLY=yes in config file. + # vi /etc/systemtap/config + AUTOCOMPILE=no + ALLOW_CACHEONLY=yes diff --git a/initscript/config b/initscript/config new file mode 100644 index 000000000..c49a34a5b --- /dev/null +++ b/initscript/config @@ -0,0 +1,20 @@ +# 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= + diff --git a/initscript/systemtap.in b/initscript/systemtap.in new file mode 100644 index 000000000..eaa1d9690 --- /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 diff --git a/systemtap.spec b/systemtap.spec index 2586b85a2..be00fa98e 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -116,6 +116,16 @@ Requires: systemtap %description sdt-devel Support tools to allow applications to use static probes. +%package initscript +Summary: Systemtap Initscript +Group: Development/System +License: GPLv2+ +URL: http://sourceware.org/systemtap/ +Requires: systemtap-runtime, initscripts + +%description initscript +Initscript for Systemtap scripts. + %prep %setup -q %{?setup_elfutils} @@ -203,6 +213,15 @@ mv $RPM_BUILD_ROOT%{_datadir}/doc/systemtap/*.pdf docs.installed/ mv $RPM_BUILD_ROOT%{_datadir}/doc/systemtap/tapsets docs.installed/ %endif +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/init.d/ +install -m 755 initscript/systemtap $RPM_BUILD_ROOT%{_sysconfdir}/init.d/ +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/systemtap +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/systemtap/conf.d +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/systemtap/script.d +install -m 644 initscript/config $RPM_BUILD_ROOT%{_sysconfdir}/systemtap +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/cache/systemtap +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/systemtap + %clean rm -rf ${RPM_BUILD_ROOT} @@ -211,6 +230,15 @@ getent group stapdev >/dev/null || groupadd -r stapdev getent group stapusr >/dev/null || groupadd -r stapusr exit 0 +%post initscript +chkconfig --add systemtap +exit 0 + +%preun initscript +chkconfig --del systemtap +exit 0 + + %files %defattr(-,root,root) @@ -276,6 +304,18 @@ exit 0 %{_bindir}/dtrace %{_includedir}/sys/sdt.h +%files initscript +%defattr(-,root,root) +%{_sysconfdir}/init.d/systemtap +%dir %{_sysconfdir}/systemtap +%dir %{_sysconfdir}/systemtap/conf.d +%dir %{_sysconfdir}/systemtap/script.d +%config(noreplace) %{_sysconfdir}/systemtap/config +%dir %{_localstatedir}/cache/systemtap +%dir %{_localstatedir}/run/systemtap +%doc initscript/README.initscript + + %changelog * Thu Nov 13 2008 Frank Ch. Eigler - 0.8-1 - Upstream release. -- 2.43.5