File: //usr/sbin/systemtap-service
#!/bin/bash
#
# systemtap Startup script for SystemTap scripts
#
# chkconfig: - 00 99
# 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
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: The systemtap service runs a configured list of scripts at system startup.
### END INIT INFO
# Source function library.
if [ -f /etc/rc.d/init.d/functions ]; then
# This initscript is not compatible with the systemctl redirect on
# newer platforms because it omits the command-line parameters for
# the standard actions (e.g. start, stop, restart, etc...).
SYSTEMCTL_SKIP_REDIRECT=1
# Red Hat init functions
. /etc/rc.d/init.d/functions
else
# Default init functions
success () {
echo -n "OK"
}
failure () {
echo -n "FAILED"
}
fi
prog=systemtap
# Commands
STAP=/usr/bin/stap
STAPRUN=/usr/bin/staprun
UNAME=/bin/uname
LSMOD=/sbin/lsmod
DRACUT=/sbin/dracut
NEWKERNELPKG=/sbin/new-kernel-pkg
# Not actually used directly, but needed by
# stap dracut module for inclusion in initramfs
STAPIO=/usr/libexec/systemtap/stapio
# 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
# NB: this path is also used in 99stap/module-setup.sh
DRACUT_SRC=/usr/lib/dracut/modules.d/99stap/params.conf
# 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
# Log boot-time staprun stderr to /var/run/systemtap/$script.log
LOG_BOOT_ERR=no
# Optional settings
CONFIG=/etc/systemtap/config
SCRIPTS=
KRELEASE=`uname -r`
OPT_RECURSIVE=
OPT_SCRIPTS=
OPTS=
OPT_ASSUMEYES=
INITRAMFS=
BACKUP_INITRAMFS=
EXPLICIT_INITRAMFS=
echo_usage () {
echo $"Usage: $prog {start|stop|status|restart|compile|onboot|cleanup|condrestart|try-restart|reload|force-reload} [OPTIONS] [SCRIPTS]"
echo $"Options:"
echo $" -b : backup initramfs before overwriting"
echo $" -c configfile : specify config file"
echo $" -o path.img : specify initramfs output 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"
echo $""
echo $"See systemtap-service(8) for full documentation"
}
#-----------------------------------------------------------------
# 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
;;
-o)
INITRAMFS=$2
shift 1
;;
-b)
BACKUP_INITRAMFS=1
;;
--)
;;
*)
OPT_SCRIPTS=$OPT_SCRIPTS\ $1
;;
esac
shift 1
done
}
CMD=$1
shift 1
OPTS=`getopt -s bash -u -o 'r:c:Ryo:b' -- $@`
if [ $? -ne 0 ]; then
slog "Error: Argument parse error: $@"
failure $"parse error"
echo_usage
exit 3
fi
parse_args $OPTS
# Set default output file if not given as an option
if [ ! "$INITRAMFS" ]; then
INITRAMFS=/boot/initramfs-$KRELEASE.img
else
# User explicitly specified an img file to output to
EXPLICIT_INITRAMFS=1
fi
# 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=$?
check_bool $LOG_BOOT_ERR
LOG_BOOT_ERR=$?
is_valid_script_name () {
# Same rules as stap -m with the addition of starting
# with a non-digit so that valid shell variables can be
# formed from it (for the config file).
if ! [[ $1 =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
log "$1 is not a valid script name (must match [a-zA-Z_][a-zA-Z0-9_]*)"
return 1
fi
}
__get_all_scripts () {
local s
if [ $ALLOW_CACHEONLY -eq 1 ]; then
for s in "$CACHE_PATH"/*.ko; do
if [ -f "$s" ]; then
script=`basename "$s" .ko`
is_valid_script_name $script
[ $? -eq 0 ] && echo $script
fi
done
fi
for s in "$SCRIPT_PATH"/*.stp; do
if [ -f "$s" ]; then
script=`basename "$s" .stp`
is_valid_script_name $script
[ $? -eq 0 ] && echo $script
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
# Create user-defined $STAT_PATH if it does not exist
if [ ! -d "$STAT_PATH" ]; then
logex mkdir -p "$STAT_PATH"
if [ $? -ne 0 ]; then
do_failure $"Failed to make stat directory ($STAT_PATH)"
exit 1
fi
fi
# Create pidfiles for running boot-time scripts
for srv in $( grep -rl 'running' /proc/systemtap/*/srvstat 2>/dev/null | awk -F\/ '{print $4}' )
do
if [ ! -f "$STAT_PATH/$srv" ]; then
echo "0" > "$STAT_PATH/$srv"
fi
done
#------------------------------------------------------------------
# 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 occurred."
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 whether a script is running. Returns:
# 0: running
# 4: running, but no pidfile
# 3: not running
# 1: not running, but pidfile remains
check_running () { # script
local m f
f="$STAT_PATH/$1"
m=`$LSMOD | grep "^$1 "`
if [ -n "$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 'vp:,save-uprobes' \
-o 'hVvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:' -- $@
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|-S)
skip=1 ;;
-h|-V|-k|-F)
;;
*)
echo -n $o" " ;;
esac
done
}
# Returns 0 if something went wrong
# Returns 1 if in -L mode
# Returns 2 if in -D (daemon) mode
get_run_opts () { # normalized_opts
local opts o show mode
opts=`stap_getopt $*`
[ $? -ne 0 ] && return 0
mode='-L'
show=0
for o in $opts; do
case $o in
--save-uprobes)
# Use cached uprobes module, if available
if [ -f "$CACHE_PATH/uprobes/uprobes.ko" ]; then
echo -n "-u$CACHE_PATH/uprobes/uprobes.ko "
fi
;;
-c|-x|-s|-o|-S)
[ $o == '-s' ] && o='-b'
[ $o == '-o' ] && mode='-D'
echo -n $o" "
show=1
;;
*)
if [ $show -ne 0 ]; then
echo -n $o" "
show=0
fi
;;
esac
done
echo -n $mode
[ "$mode" == "-L" ] && return 1
[ "$mode" == "-D" ] && return 2
return 0
}
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 -E "probe procfs(\"srvstat\").read {\$value = \"running\n\"}" \
-m "$1" -p4 -r $KRELEASE --save-uprobes $opts "$f"
ret=$?
if [ $ret -eq 0 ]; then
if [ -f "uprobes/uprobes.ko" ]; then
logex touch "$CACHE_PATH/$1.uprobes"
logex mkdir -p "$CACHE_PATH/uprobes"
logex mv "uprobes/uprobes.ko" "$CACHE_PATH/uprobes/"
ret=$?
elif [ -f "$CACHE_PATH/$1.uprobes" ]; then
rm "$CACHE_PATH/$1.uprobes"
fi
fi
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 ret count=0 mode
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`
mode=$?
[ $mode -eq 0 ] && return 2
if [ -f "$CACHE_PATH/$s.uprobes" ]; then
opts="$opts -u$CACHE_PATH/uprobes/uprobes.ko"
fi
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
eval log \"Exec: $STAPRUN $opts $CACHE_PATH/$s.ko\"
$STAPRUN $opts "$CACHE_PATH/$s.ko" 2>> "$LOG_FILE" > ./pid
ret=$?
# When the staprun '-D' option (run in background as a daemon) is
# used, staprun detaches from the terminal and *then* prints the new
# pid. So, it is possible to check the ./pid file before it has
# been written. To avoid this, wait a bit (if necessary).
if [ $mode -eq 2 ]; then
while [ $count -lt 10 ]; do
# when the file exists and has a size > 0, quit
[ -s ./pid ] && break
sleep 1
count=`expr $count + 1`
done
fi
[ x`cat ./pid` = x ] && echo 0 > ./pid
if [ $ret -eq 0 ]; then
logex cp -f ./pid "$STAT_PATH/$s"
fi
popd &> /dev/null
rm -rf "$tmpdir"
[ $ret -eq 0 ] && clog "done" || clog "error"
return $ret
}
start () {
local start_scripts s ret
clog $"Starting $prog: " -n
start_scripts=$SCRIPTS
if [ -n "$DEFAULT_START" -a -z "$OPT_SCRIPTS" ]; then
# Only pick the names in DEFAULT_START with valid names
start_scripts=
for s in $DEFAULT_START; do
is_valid_script_name $s
[ $? -eq 0 ] && start_scripts="$start_scripts $s"
done
fi
if [ -z "$start_scripts" ]; then
do_warning $"No scripts exist."
return 0 # only a warning
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
start_scripts=`sort_dependency $start_scripts`
if [ $? -ne 0 ]; then
do_failure $"Failed to sort dependency"
return 6 # program is not configured
fi
fi
for s in $start_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 f count=0
f="$STAT_PATH/$1"
while [ $count -lt 10 ]; do
check_running "$1"
ret=$?
# If the module is isn't running, we're done.
[ $ret -eq 3 ] && return 0
# If the module isn't loaded but the pidfile remains, remove the
# old pidfile and return.
if [ $ret -eq 1 ]; then
rm -f $f
return 0
fi
# Try to either kill the stap process that is handling the
# module (which will cause the module to be unloaded) or use
# staprun to delete the module. (Note that staprun will only
# delete systemtap modules.)
p=`get_daemon_pid $1`
if [ $p -ne 0 ]; then
logex kill -TERM $p
else
logex $STAPRUN -d "$1"
fi
[ $? -ne 0 ] && return 1
# At this point the module should be unloaded, but the pidfile
# will still be present. If so, remove the pidfile and return.
# Otherwise, wait a bit for the module to unload and try again.
check_running "$1"
ret=$?
[ $ret -eq 3 ] && return 0
if [ $ret -eq 1 ]; then
rm -f $f
return 0
fi
sleep 1
count=`expr $count + 1`
done
do_failure $"Failed to stop script \"$1\" after $count attempts"
return 1
}
stop () {
local stop_scripts s sl=
clog $"Stopping $prog: " -n
stop_scripts=$SCRIPTS
[ -z "$OPT_SCRIPTS" ] && stop_scripts=`get_all_runnings`
if [ $RECURSIVE -eq 1 ]; then
stop_scripts=`sort_dependency $stop_scripts`
if [ $? -ne 0 ]; then
do_failure $"Failed to sort dependency"
return 6 # program is not configured
fi
fi
for s in $stop_scripts; do
sl="$s $sl"
done
for s in $sl; do
stop_script $s
[ $? -ne 0 ] && might_fail $"Failed to stop \"$s\". "
done
might_success $"$prog stopping "
return 0
}
rh_status () {
local status_scripts s pid ret r
status_scripts=$SCRIPTS
[ -z "$status_scripts" ] && status_scripts=`get_all_runnings`
ret=3
if [ -z "$status_scripts" ] ; then
echo "No systemtap scripts are present"
return $ret
fi
for s in $status_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
}
rh_status_q () {
rh_status >/dev/null 2>&1
return $?
}
compile () {
local s ss
clog $"Compiling systemtap scripts: " -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" "$CACHE_PATH/$s.uprobes" 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
}
# Writes info to $DRACUT_SRC, which the stap dracut module will source.
# Includes all needed info such as location of stap/staprun, which
# scripts to insert, and their options.
update_dracut() { # scripts
local s opts
if [ -f "$DRACUT_SRC" ]; then
rm -f "$DRACUT_SRC"
fi
echo "STAPRUN=\"$STAPRUN\"" >> "$DRACUT_SRC"
echo "STAPIO=\"$STAPIO\"" >> "$DRACUT_SRC"
echo "CACHE_PATH=\"$CACHE_PATH\"" >> "$DRACUT_SRC"
echo "STAT_PATH=\"$STAT_PATH\"" >> "$DRACUT_SRC"
echo "KRELEASE=\"$KRELEASE\"" >> "$DRACUT_SRC"
echo "LOG_BOOT_ERR=\"$LOG_BOOT_ERR\"" >> "$DRACUT_SRC"
echo -n "ONBOOT_SCRIPTS=\"" >> "$DRACUT_SRC"
for s in $*; do
echo -n "$s " >> "$DRACUT_SRC"
done
echo "\"" >> "$DRACUT_SRC"
for s in $*; do
eval opts=\$${s}_OPT
opts=`get_run_opts $opts`
[ $? -eq 0 ] && return 1
echo -n "$s" >> "$DRACUT_SRC"
echo "_OPT=\"$opts\"" >> "$DRACUT_SRC"
done
}
backup_initramfs() {
# does target file exist?
if [ -f "$INITRAMFS" ]; then
clog
# don't overwrite an existing backup
if [ ! -f "$INITRAMFS.bak" ]; then
mv "$INITRAMFS" "$INITRAMFS.bak"
clog " Renamed $INITRAMFS"
clog " to $INITRAMFS.bak ... " -n
RESTORE_INITRAMFS_ON_FAIL=1
else
clog " Backup already exists: $INITRAMFS.bak ... " -n
fi
fi
}
onboot () {
local s ret ss
if [ ! -f "$NEWKERNELPKG" ]; then
clog "Could not find $NEWKERNELPKG" -n
do_failure "$NEWKERNELPKG not found"
clog
clog "This feature requires $NEWKERNELPKG."
clog "If it is located elsewhere, modify the \$NEWKERNELPKG parameter" -n
return 1
fi
if [ ! -f "$DRACUT" ]; then
clog "Could not find $DRACUT" -n
do_failure "$DRACUT not found"
clog
clog "The system must be dracut-based to use this feature"
clog "If it is located elsewhere, modify the \$DRACUT parameter" -n
return 1
fi
if [ ! -d "$(dirname $DRACUT_SRC)" ]; then
clog "Could not find dracut module" -n
do_failure "SystemTap dracut module $(dirname $DRACUT_SRC) not found"
return 1
fi
prepare_cache_dir
if [ $? -ne 0 ]; then
do_failure "Failed to make cache directory ($CACHE_PATH)"
return 1
fi
# NB: we use OPT_SCRIPTS, not SCRIPTS because we want
# no scripts passed to mean building a virgin initramfs
for s in $OPT_SCRIPTS; do
compile_script $s check
ret=$?
[ $ret -ne 0 ] && might_fail "Could not compile $s ($ret)"
eval opts=\$${s}_OPT
opts=`get_run_opts $opts`
mode=$?
clog " Checking options $s ... " -n
[ $mode -eq 0 ] && might_fail "Bad runtime options for script $s"
[ $mode -eq 2 ] && might_fail "Unsupported option -o in script $s"
if [ $ret -eq 0 ] && [ $mode -eq 1 ]; then
ss="$ss$s "
clog "done"
fi
done
# User specified script(s) but they were all skipped
if [ -n "$OPT_SCRIPTS" ] && [ -z "$ss" ]; then
do_failure "No scripts left to operate on"
return 1
fi
if [ ! "$ss" ]; then
clog " Creating initramfs without scripts ... " -n
else
clog " Creating initramfs with $ss... " -n
fi
update_dracut $ss
if [ $? -ne 0 ]; then
do_failure "Call to update_dracut failed. Bad opts?"
return 1
fi
if [ "$BACKUP_INITRAMFS" ]; then
backup_initramfs
fi
dir=`dirname $INITRAMFS` && TMPINITRAMFS=`mktemp --tmpdir=$dir`
if [ $? -ne 0 ]; then
do_failure "Failed to make temporary file in $dir"
return 1
fi
if [ ! "$ss" ]; then
# Create the initramfs image without stap module enabled.
out=$($DRACUT --force $TMPINITRAMFS $KRELEASE 2>&1)
else
# Create the initramfs image with stap module enabled.
out=$($DRACUT --add stap --force $TMPINITRAMFS $KRELEASE 2>&1)
fi
# dracut will report success even if some modules (e.g. stap) failed
# to install some files, so we need to be a bit more involved in
# checking for errors
if [ $? -ne 0 ] || \
[[ "$out" == *ERROR* ]] || \
( [ -n "$ss" ] && ! lsinitrd "$TMPINITRAMFS" | grep -q ${STAPRUN:1} ); then
do_failure "The initramfs creation is unsuccessful"
if [ -f /var/log/dracut.log ]; then
do_failure "See /var/log/dracut.log for more info"
else
do_failure "See dracut log for more info"
fi
clog
if [ -f "$TMPINITRAMFS" ]; then
rm "$TMPINITRAMFS"
fi
# Put back the initramfs if we moved it (if we didn't move it, then
# whatever initramfs they used to boot in is still there)
if [ "$RESTORE_INITRAMFS_ON_FAIL" ]; then
mv "$INITRAMFS.bak" "$INITRAMFS"
clog " Renamed $INITRAMFS.bak"
clog " to $INITRAMFS"
fi
return 1
fi
mv "$TMPINITRAMFS" "$INITRAMFS"
# The initramfs is in place. If the user explicitly specified an
# output file using -o, then we should skip updating the bootloader
# (the output file may not even be in /boot/).
if [ "$EXPLICIT_INITRAMFS" ]; then
might_success "initramfs created"
clog
clog "NB: bootloader was not updated" -n
return 0
fi
clog "done"
# We're installing the initramfs in the default location, so user
# expects the next boot to use it. Let's also update the bootloader.
clog " Updating bootloader ... " -n
logex $NEWKERNELPKG --initrdfile="$INITRAMFS" \
--update $KRELEASE
if [ $? -ne 0 ]; then
do_failure "$NEWKERNELPKG exited with nonzero status"
return 1
fi
might_success "initramfs created and bootloader updated"
return 0
}
# Cleanup caches
cleanup () {
local s ss ret
clog $"Cleaning up systemtap scripts: " -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" "$CACHE_PATH/$s.uprobes" 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" "$CACHE_PATH/$s.uprobes"
[ $? -ne 0 ] && might_fail $"failed to clean cache $s.ko"
done
fi
# If none of the remaining scripts require uprobes.ko, then delete it as well
if [ -d "$CACHE_PATH/uprobes" ]; then
if ! ls "$CACHE_PATH/*.uprobes" &>/dev/null; then
logex rm -rf "$CACHE_PATH/uprobes"
fi
fi
might_success "done"
return 0
}
# Restart scripts
function restart () {
stop
echo # we need a newline
start
return $?
}
RETVAL=0
case $CMD in
start)
start
RETVAL=$?
;;
stop)
stop
RETVAL=$?
;;
restart|force-reload|reload)
restart
RETVAL=$?
;;
status)
rh_status
exit $?
;;
compile)
compile
RETVAL=$?
;;
onboot)
onboot
RETVAL=$?
;;
cleanup)
cleanup
RETVAL=$?
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
RETVAL=$?
;;
*)
echo_usage
RETVAL=3
;;
esac
echo
exit $RETVAL
# vim: sw=2 ts=8