You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
432 lines
7.5 KiB
432 lines
7.5 KiB
#!/bin/sh
|
|
#
|
|
# Copyright (c) Linux Test Project, 2014-2017
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
# Written by Cyril Hrubis <chrubis@suse.cz>
|
|
#
|
|
# This is a LTP test library for shell.
|
|
#
|
|
|
|
export LTP_RET_VAL=0
|
|
export TST_COUNT=1
|
|
export TST_PASS_COUNT=0
|
|
export TST_LIB_LOADED=1
|
|
export TST_TMPDIR_RHOST=0
|
|
|
|
. tst_ansi_color.sh
|
|
|
|
# Exit values map
|
|
tst_flag2mask()
|
|
{
|
|
case "$1" in
|
|
TPASS) return 0;;
|
|
TFAIL) return 1;;
|
|
TBROK) return 2;;
|
|
TWARN) return 4;;
|
|
TINFO) return 16;;
|
|
TCONF) return 32;;
|
|
*) tst_brkm TBROK "Invalid resm type '$1'";;
|
|
esac
|
|
}
|
|
|
|
tst_resm()
|
|
{
|
|
local ttype="$1"
|
|
|
|
tst_flag2mask "$ttype"
|
|
local mask=$?
|
|
LTP_RET_VAL=$((LTP_RET_VAL|mask))
|
|
|
|
local ret=$1
|
|
shift
|
|
|
|
printf "$TCID $TST_COUNT "
|
|
tst_print_colored $ret "$ret:"
|
|
echo " $@"
|
|
|
|
case "$ret" in
|
|
TPASS|TFAIL|TCONF) TST_COUNT=$((TST_COUNT+1));;
|
|
esac
|
|
|
|
if [ "$ret" = TPASS ]; then
|
|
TST_PASS_COUNT=$((TST_PASS_COUNT+1))
|
|
fi
|
|
}
|
|
|
|
tst_brkm()
|
|
{
|
|
case "$1" in
|
|
TFAIL) ;;
|
|
TBROK) ;;
|
|
TCONF) ;;
|
|
*) tst_brkm TBROK "Invalid tst_brkm type '$1'";;
|
|
esac
|
|
|
|
local ret=$1
|
|
shift
|
|
tst_resm "$ret" "$@"
|
|
tst_exit
|
|
}
|
|
|
|
tst_record_childstatus()
|
|
{
|
|
if [ $# -ne 1 ]; then
|
|
tst_brkm TBROK "Requires child pid as parameter"
|
|
fi
|
|
|
|
local child_pid=$1
|
|
local ret=0
|
|
|
|
wait $child_pid
|
|
ret=$?
|
|
if [ $ret -eq 127 ]; then
|
|
tst_brkm TBROK "Child process pid='$child_pid' does not exist"
|
|
fi
|
|
LTP_RET_VAL=$((LTP_RET_VAL|ret))
|
|
}
|
|
|
|
tst_require_root()
|
|
{
|
|
if [ "$(id -ru)" != 0 ]; then
|
|
tst_brkm TCONF "Must be super/root for this test!"
|
|
fi
|
|
}
|
|
|
|
tst_exit()
|
|
{
|
|
if [ -n "${TST_CLEANUP:-}" -a -z "${TST_NO_CLEANUP:-}" ]; then
|
|
$TST_CLEANUP
|
|
fi
|
|
|
|
if [ -n "${LTP_IPC_PATH:-}" -a -f "${LTP_IPC_PATH:-}" ]; then
|
|
rm -f "$LTP_IPC_PATH"
|
|
fi
|
|
|
|
# Mask out TCONF if no TFAIL/TBROK/TWARN but has TPASS
|
|
if [ $((LTP_RET_VAL & 7)) -eq 0 -a $TST_PASS_COUNT -gt 0 ]; then
|
|
LTP_RET_VAL=$((LTP_RET_VAL & ~32))
|
|
fi
|
|
# Mask out TINFO
|
|
exit $((LTP_RET_VAL & ~16))
|
|
}
|
|
|
|
tst_tmpdir()
|
|
{
|
|
if [ -z "$TMPDIR" ]; then
|
|
export TMPDIR="/tmp"
|
|
fi
|
|
|
|
TST_TMPDIR=$(mktemp -d "$TMPDIR/$TCID.XXXXXXXXXX")
|
|
|
|
chmod 777 "$TST_TMPDIR"
|
|
|
|
TST_STARTWD=$(pwd)
|
|
|
|
cd "$TST_TMPDIR"
|
|
}
|
|
|
|
tst_rmdir()
|
|
{
|
|
if [ -n "$TST_TMPDIR" ]; then
|
|
cd "$LTPROOT"
|
|
rm -r "$TST_TMPDIR"
|
|
[ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Checks if commands passed as arguments exists
|
|
#
|
|
tst_require_cmds()
|
|
{
|
|
local cmd
|
|
for cmd in $*; do
|
|
if ! command -v $cmd > /dev/null 2>&1; then
|
|
tst_brkm TCONF "'$cmd' not found"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# tst_retry "command" [times]
|
|
# try run command for specified times, default is 3.
|
|
# Function returns 0 if succeed in RETRIES times or the last retcode the cmd
|
|
# returned
|
|
tst_retry()
|
|
{
|
|
local cmd="$1"
|
|
local RETRIES=${2:-"3"}
|
|
local i=$RETRIES
|
|
|
|
while [ $i -gt 0 ]; do
|
|
eval "$cmd"
|
|
ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
break
|
|
fi
|
|
i=$((i-1))
|
|
sleep 1
|
|
done
|
|
|
|
if [ $ret -ne 0 ]; then
|
|
tst_resm TINFO "Failed to execute '$cmd' after $RETRIES retries"
|
|
fi
|
|
|
|
return $ret
|
|
}
|
|
|
|
# tst_timeout "command arg1 arg2 ..." timeout
|
|
# Runs command for specified timeout (in seconds).
|
|
# Function returns retcode of command or 1 if arguments are invalid.
|
|
tst_timeout()
|
|
{
|
|
local command=$1
|
|
local timeout=$(echo $2 | grep -o "^[0-9]\+$")
|
|
|
|
# command must be non-empty string with command to run
|
|
if [ -z "$command" ]; then
|
|
echo "first argument must be non-empty string"
|
|
return 1
|
|
fi
|
|
|
|
# accept only numbers as timeout
|
|
if [ -z "$timeout" ]; then
|
|
echo "only numbers as second argument"
|
|
return 1
|
|
fi
|
|
|
|
setsid sh -c "eval $command" 2>&1 &
|
|
local pid=$!
|
|
while [ $timeout -gt 0 ]; do
|
|
kill -s 0 $pid 2>/dev/null
|
|
if [ $? -ne 0 ]; then
|
|
break
|
|
fi
|
|
timeout=$((timeout - 1))
|
|
sleep 1
|
|
done
|
|
|
|
local ret=0
|
|
if [ $timeout -le 0 ]; then
|
|
ret=128
|
|
kill -TERM -- -$pid
|
|
fi
|
|
|
|
wait $pid
|
|
ret=$((ret | $?))
|
|
|
|
return $ret
|
|
}
|
|
|
|
ROD_SILENT()
|
|
{
|
|
local tst_out="$($@ 2>&1)"
|
|
if [ $? -ne 0 ]; then
|
|
echo "$tst_out"
|
|
tst_brkm TBROK "$@ failed"
|
|
fi
|
|
}
|
|
|
|
ROD_BASE()
|
|
{
|
|
local cmd
|
|
local arg
|
|
local file
|
|
local flag
|
|
|
|
for arg; do
|
|
file="${arg#\>}"
|
|
if [ "$file" != "$arg" ]; then
|
|
flag=1
|
|
if [ -n "$file" ]; then
|
|
break
|
|
fi
|
|
continue
|
|
fi
|
|
|
|
if [ -n "$flag" ]; then
|
|
file="$arg"
|
|
break
|
|
fi
|
|
|
|
cmd="$cmd $arg"
|
|
done
|
|
|
|
if [ -n "$flag" ]; then
|
|
$cmd > $file
|
|
else
|
|
$@
|
|
fi
|
|
}
|
|
|
|
ROD()
|
|
{
|
|
ROD_BASE "$@"
|
|
if [ $? -ne 0 ]; then
|
|
tst_brkm TBROK "$@ failed"
|
|
fi
|
|
}
|
|
|
|
EXPECT_PASS()
|
|
{
|
|
ROD_BASE "$@"
|
|
if [ $? -eq 0 ]; then
|
|
tst_resm TPASS "$@ passed as expected"
|
|
else
|
|
tst_resm TFAIL "$@ failed unexpectedly"
|
|
fi
|
|
}
|
|
|
|
EXPECT_FAIL()
|
|
{
|
|
# redirect stderr since we expect the command to fail
|
|
ROD_BASE "$@" 2> /dev/null
|
|
if [ $? -ne 0 ]; then
|
|
tst_resm TPASS "$@ failed as expected"
|
|
else
|
|
tst_resm TFAIL "$@ passed unexpectedly"
|
|
fi
|
|
}
|
|
|
|
tst_mkfs()
|
|
{
|
|
local fs_type=$1
|
|
local device=$2
|
|
shift 2
|
|
local fs_opts="$@"
|
|
|
|
if [ -z "$fs_type" ]; then
|
|
tst_brkm TBROK "No fs_type specified"
|
|
fi
|
|
|
|
if [ -z "$device" ]; then
|
|
tst_brkm TBROK "No device specified"
|
|
fi
|
|
|
|
tst_resm TINFO "Formatting $device with $fs_type extra opts='$fs_opts'"
|
|
|
|
ROD_SILENT mkfs.$fs_type $fs_opts $device
|
|
}
|
|
|
|
tst_umount()
|
|
{
|
|
local device="$1"
|
|
local i=0
|
|
|
|
if ! grep -q "$device" /proc/mounts; then
|
|
tst_resm TINFO "The $device is not mounted, skipping umount"
|
|
return
|
|
fi
|
|
|
|
while [ "$i" -lt 50 ]; do
|
|
if umount "$device" > /dev/null; then
|
|
return
|
|
fi
|
|
|
|
i=$((i+1))
|
|
|
|
tst_resm TINFO "umount($device) failed, try $i ..."
|
|
tst_resm TINFO "Likely gvfsd-trash is probing newly mounted "\
|
|
"fs, kill it to speed up tests."
|
|
|
|
tst_sleep 100ms
|
|
done
|
|
|
|
tst_resm TWARN "Failed to umount($device) after 50 retries"
|
|
}
|
|
|
|
# Check a module file existence
|
|
# Should be called after tst_tmpdir()
|
|
tst_module_exists()
|
|
{
|
|
local mod_name="$1"
|
|
|
|
if [ -f "$mod_name" ]; then
|
|
TST_MODPATH="$mod_name"
|
|
return
|
|
fi
|
|
|
|
local mod_path="$LTPROOT/testcases/bin/$mod_name"
|
|
if [ -f "$mod_path" ]; then
|
|
TST_MODPATH="$mod_path"
|
|
return
|
|
fi
|
|
|
|
if [ -n "$TST_TMPDIR" ]; then
|
|
mod_path="$TST_STARTWD/$mod_name"
|
|
if [ -f "$mod_path" ]; then
|
|
TST_MODPATH="$mod_path"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
tst_brkm TCONF "Failed to find module '$mod_name'"
|
|
}
|
|
|
|
TST_CHECKPOINT_WAIT()
|
|
{
|
|
ROD tst_checkpoint wait 10000 "$1"
|
|
}
|
|
|
|
TST_CHECKPOINT_WAKE()
|
|
{
|
|
ROD tst_checkpoint wake 10000 "$1" 1
|
|
}
|
|
|
|
TST_CHECKPOINT_WAKE2()
|
|
{
|
|
ROD tst_checkpoint wake 10000 "$1" "$2"
|
|
}
|
|
|
|
TST_CHECKPOINT_WAKE_AND_WAIT()
|
|
{
|
|
TST_CHECKPOINT_WAKE "$1"
|
|
TST_CHECKPOINT_WAIT "$1"
|
|
}
|
|
|
|
# Check that test name is set
|
|
if [ -z "$TCID" ]; then
|
|
tst_brkm TBROK "TCID is not defined"
|
|
fi
|
|
|
|
if [ -z "$TST_TOTAL" ]; then
|
|
tst_brkm TBROK "TST_TOTAL is not defined"
|
|
fi
|
|
|
|
export TCID="$TCID"
|
|
export TST_TOTAL="$TST_TOTAL"
|
|
|
|
# Setup LTPROOT, default to current directory if not set
|
|
if [ -z "$LTPROOT" ]; then
|
|
export LTPROOT="$PWD"
|
|
export LTP_DATAROOT="$LTPROOT/datafiles"
|
|
else
|
|
export LTP_DATAROOT="$LTPROOT/testcases/data/$TCID"
|
|
fi
|
|
|
|
if [ "$TST_NEEDS_CHECKPOINTS" = "1" ]; then
|
|
LTP_IPC_PATH="/dev/shm/ltp_${TCID}_$$"
|
|
|
|
LTP_IPC_SIZE=$(tst_getconf PAGESIZE)
|
|
if [ $? -ne 0 ]; then
|
|
tst_brkm TBROK "tst_getconf PAGESIZE failed"
|
|
fi
|
|
|
|
ROD_SILENT dd if=/dev/zero of="$LTP_IPC_PATH" bs="$LTP_IPC_SIZE" count=1
|
|
ROD_SILENT chmod 600 "$LTP_IPC_PATH"
|
|
export LTP_IPC_PATH
|
|
fi
|