#!/usr/bin/env bash
# This scripts present a friendly interface to the fiu remote control
# capabilities. Currently, it supports only the named pipe method (the only
# one implemented).
# default remote control over named pipes prefix; we use the same one as
# fiu-run so it's easier to use
FIFO_PREFIX="${TMPDIR:-/tmp}/fiu-ctrl"
# commands to send, will be filled by options processing; must be in the
# format supported by the fiu remote control (see fiu-rc.c for more details)
declare -a CMDS
HELP_MSG="
Usage: fiu-ctrl [options] PID [PID ...]
The following options are supported:
-c command Run the given libfiu remote control command before executing
the program (see below for reference).
-f ctrlpath Enable remote control over named pipes with the given path as
base name, the process id will be appended (defaults to
\"$FIFO_PREFIX\", set to \"\" to disable).
Remote control commands are of the form 'command param1=value1,param2=value2'.
Valid commands are:
- 'enable name=NAME'
Enables the NAME failure point unconditionally.
- 'enable_random name=NAME,probability=P'
Enables the NAME failure point with a probability of P.
- 'disable name=NAME'
Disables the NAME failure point.
All of the enable\* can also optionally take 'failnum' and 'failinfo'
parameters, analogous to the ones taken by the C functions.
The following options existed in the past but are deprecated and WILL BE
REMOVED in future releases: -e, -p, -u, -i, and -d.
Examples:
fiu-ctrl -c 'enable_random name=posix/io/*,probability=0.25' \\
-c 'enable_random name=libc/mm/*,probability=0.05' 12345
Tell the process with pid 12345 to enable the failure point 'posix/io/read'
with a 25% of probability to fail, and the failure point 'libc/mm/malloc' with
a 5% of probability to fail.
fiu-ctrl -c 'disable name=posix/io/read' 12345
Tell the same process to disable the previously enabled failure point.
You can control multiple processes at once by specifiying more than one
process ID.
"
#
# Parse the options
#
if [ $# -lt 1 ]; then
echo "$HELP_MSG"
exit 1
fi
function opts_reset() {
# variables to store what we know so far; after a new name is found
# the old one is added to $CMD
DEP_NAME=""
DEP_PROB=-1
DEP_FAILNUM=1
DEP_FAILINFO=0
}
function add_deprecated_enable() {
if [ "$DEP_NAME" == "" ]; then
return
fi;
PARAMS="name=$DEP_NAME,failnum=$DEP_FAILNUM,failinfo=$DEP_FAILINFO"
if [ "$DEP_PROB" -ge 0 ]; then
C="enable_random $PARAMS,probability=0.$DEP_PROB"
else
C="enable $PARAMS"
fi
CMDS[${#CMDS[*]}]="$C"
}
function deprecated_warning() {
echo "Warning: this option is deprecated and will be removed." >&2
}
opts_reset;
while getopts "+c:e:p:u:i:d:f:h" opt; do
case $opt in
c)
CMDS[${#CMDS[*]}]="$OPTARG"
;;
e)
# add the current one, if any
deprecated_warning;
add_deprecated_enable;
opts_reset;
DEP_NAME="$OPTARG"
;;
p)
deprecated_warning;
DEP_PROB="$OPTARG"
;;
u)
deprecated_warning;
DEP_FAILNUM="$OPTARG"
;;
i)
deprecated_warning;
DEP_FAILINFO="$OPTARG"
;;
f)
FIFO_PREFIX="$OPTARG"
;;
d)
deprecated_warning;
CMDS[${#CMDS[*]}]="disable name=$OPTARG"
opts_reset;
;;
h|*)
echo "$HELP_MSG"
exit 1
;;
esac;
done
# add leftovers
if [ "$DEP_NAME" != "" ]; then
add_deprecated_enable;
fi
# eat the parameters we already processed
shift $(( $OPTIND - 1 ))
PIDS=""
PREFIXES=""
for i in "$@"; do
if test -p "$i.out"; then
PREFIXES="$PREFIXES $i"
elif kill -0 $i > /dev/null 2> /dev/null && \
test -p "$FIFO_PREFIX-$i.out"; then
PIDS="$PIDS $i"
else
echo "Error: unknown pid or named pipe $i, skipping"
echo "Note that options must come before the PID"
fi
done
#
# Send the commands
#
function send_cmd_fifo() {
# $1 = complete fifo prefix
# $2+ = command to send
# echoes the reply
P=$1
shift 1
echo "$@" > $P.in
REPLY=$(cat "$P.out")
if [ "$REPLY" == "-1" ]; then
echo "$P: Command '$@' returned error ($REPLY)"
fi
#echo "$P: $@ -> $REPLY"
}
for c in "${CMDS[@]}"; do
for i in $PIDS; do
send_cmd_fifo $FIFO_PREFIX-$i "$c"
done
for i in $PREFIXES; do
send_cmd_fifo $i "$c"
done
done