Home | History | Annotate | Download | only in lib
      1 #!/bin/sh
      2 #
      3 # Copyright (c) Linux Test Project, 2014-2017
      4 #
      5 # This program is free software; you can redistribute it and/or modify
      6 # it under the terms of the GNU General Public License as published by
      7 # the Free Software Foundation; either version 2 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License along
     16 # with this program; if not, write to the Free Software Foundation, Inc.,
     17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18 #
     19 # Written by Cyril Hrubis <chrubis (at] suse.cz>
     20 #
     21 # This is a LTP test library for shell.
     22 #
     23 
     24 export LTP_RET_VAL=0
     25 export TST_COUNT=1
     26 export TST_LIB_LOADED=1
     27 export TST_TMPDIR_RHOST=0
     28 
     29 . tst_ansi_color.sh
     30 
     31 # Exit values map
     32 tst_flag2mask()
     33 {
     34 	case "$1" in
     35 	TPASS) return 0;;
     36 	TFAIL) return 1;;
     37 	TBROK) return 2;;
     38 	TWARN) return 4;;
     39 	TINFO) return 16;;
     40 	TCONF) return 32;;
     41 	*) tst_brkm TBROK "Invalid resm type '$1'";;
     42 	esac
     43 }
     44 
     45 tst_resm()
     46 {
     47 	local ttype="$1"
     48 
     49 	tst_flag2mask "$ttype"
     50 	local mask=$?
     51 	LTP_RET_VAL=$((LTP_RET_VAL|mask))
     52 
     53 	local ret=$1
     54 	shift
     55 
     56 	printf "$TCID $TST_COUNT "
     57 	tst_print_colored $ret "$ret:"
     58 	echo " $@"
     59 
     60 	case "$ret" in
     61 	TPASS|TFAIL)
     62 	TST_COUNT=$((TST_COUNT+1));;
     63 	esac
     64 }
     65 
     66 tst_brkm()
     67 {
     68 	case "$1" in
     69 	TFAIL) ;;
     70 	TBROK) ;;
     71 	TCONF) ;;
     72 	*) tst_brkm TBROK "Invalid tst_brkm type '$1'";;
     73 	esac
     74 
     75 	local ret=$1
     76 	shift
     77 	tst_resm "$ret" "$@"
     78 	tst_exit
     79 }
     80 
     81 tst_record_childstatus()
     82 {
     83 	if [ $# -ne 1 ]; then
     84 		tst_brkm TBROK "Requires child pid as parameter"
     85 	fi
     86 
     87 	local child_pid=$1
     88 	local ret=0
     89 
     90 	wait $child_pid
     91 	ret=$?
     92 	if [ $ret -eq 127 ]; then
     93 		tst_brkm TBROK "Child process pid='$child_pid' does not exist"
     94 	fi
     95 	LTP_RET_VAL=$((LTP_RET_VAL|ret))
     96 }
     97 
     98 tst_require_root()
     99 {
    100 	if [ "$(id -ru)" != 0 ]; then
    101 		tst_brkm TCONF "Must be super/root for this test!"
    102 	fi
    103 }
    104 
    105 tst_exit()
    106 {
    107 	if [ -n "${TST_CLEANUP:-}" -a -z "${TST_NO_CLEANUP:-}" ]; then
    108 		$TST_CLEANUP
    109 	fi
    110 
    111 	if [ -n "${LTP_IPC_PATH:-}" -a -f "${LTP_IPC_PATH:-}" ]; then
    112 		rm -f "$LTP_IPC_PATH"
    113 	fi
    114 
    115 	# Mask out TINFO
    116 	exit $((LTP_RET_VAL & ~16))
    117 }
    118 
    119 tst_tmpdir()
    120 {
    121 	if [ -z "$TMPDIR" ]; then
    122 		export TMPDIR="/tmp"
    123 	fi
    124 
    125 	TST_TMPDIR=$(mktemp -d "$TMPDIR/$TCID.XXXXXXXXXX")
    126 
    127 	chmod 777 "$TST_TMPDIR"
    128 
    129 	TST_STARTWD=$(pwd)
    130 
    131 	cd "$TST_TMPDIR"
    132 }
    133 
    134 tst_rmdir()
    135 {
    136 	if [ -n "$TST_TMPDIR" ]; then
    137 		cd "$LTPROOT"
    138 		rm -r "$TST_TMPDIR"
    139 		[ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost
    140 	fi
    141 }
    142 
    143 #
    144 # Checks if commands passed as arguments exists
    145 #
    146 tst_check_cmds()
    147 {
    148 	local cmd
    149 	for cmd in $*; do
    150 		if ! command -v $cmd > /dev/null 2>&1; then
    151 			tst_brkm TCONF "'$cmd' not found"
    152 		fi
    153 	done
    154 }
    155 
    156 # tst_retry "command" [times]
    157 # try run command for specified times, default is 3.
    158 # Function returns 0 if succeed in RETRIES times or the last retcode the cmd
    159 # returned
    160 tst_retry()
    161 {
    162 	local cmd="$1"
    163 	local RETRIES=${2:-"3"}
    164 	local i=$RETRIES
    165 
    166 	while [ $i -gt 0 ]; do
    167 		eval "$cmd"
    168 		ret=$?
    169 		if [ $ret -eq 0 ]; then
    170 			break
    171 		fi
    172 		i=$((i-1))
    173 		sleep 1
    174 	done
    175 
    176 	if [ $ret -ne 0 ]; then
    177 		tst_resm TINFO "Failed to execute '$cmd' after $RETRIES retries"
    178 	fi
    179 
    180 	return $ret
    181 }
    182 
    183 # tst_timeout "command arg1 arg2 ..." timeout
    184 # Runs command for specified timeout (in seconds).
    185 # Function returns retcode of command or 1 if arguments are invalid.
    186 tst_timeout()
    187 {
    188 	local command=$1
    189 	local timeout=$(echo $2 | grep -o "^[0-9]\+$")
    190 
    191 	# command must be non-empty string with command to run
    192 	if [ -z "$command" ]; then
    193 		echo "first argument must be non-empty string"
    194 		return 1
    195 	fi
    196 
    197 	# accept only numbers as timeout
    198 	if [ -z "$timeout" ]; then
    199 		echo "only numbers as second argument"
    200 		return 1
    201 	fi
    202 
    203 	setsid sh -c "eval $command" 2>&1 &
    204 	local pid=$!
    205 	while [ $timeout -gt 0 ]; do
    206 		kill -s 0 $pid 2>/dev/null
    207 		if [ $? -ne 0 ]; then
    208 			break
    209 		fi
    210 		timeout=$((timeout - 1))
    211 		sleep 1
    212 	done
    213 
    214 	local ret=0
    215 	if [ $timeout -le 0 ]; then
    216 		ret=128
    217 		kill -TERM -- -$pid
    218 	fi
    219 
    220 	wait $pid
    221 	ret=$((ret | $?))
    222 
    223 	return $ret
    224 }
    225 
    226 ROD_SILENT()
    227 {
    228 	$@ > /dev/null 2>&1
    229 	if [ $? -ne 0 ]; then
    230 		tst_brkm TBROK "$@ failed"
    231 	fi
    232 }
    233 
    234 ROD_BASE()
    235 {
    236 	local cmd
    237 	local arg
    238 	local file
    239 	local flag
    240 
    241 	for arg; do
    242 		file="${arg#\>}"
    243 		if [ "$file" != "$arg" ]; then
    244 			flag=1
    245 			if [ -n "$file" ]; then
    246 				break
    247 			fi
    248 			continue
    249 		fi
    250 
    251 		if [ -n "$flag" ]; then
    252 			file="$arg"
    253 			break
    254 		fi
    255 
    256 		cmd="$cmd $arg"
    257 	done
    258 
    259 	if [ -n "$flag" ]; then
    260 		$cmd > $file
    261 	else
    262 		$@
    263 	fi
    264 }
    265 
    266 ROD()
    267 {
    268 	ROD_BASE "$@"
    269 	if [ $? -ne 0 ]; then
    270 		tst_brkm TBROK "$@ failed"
    271 	fi
    272 }
    273 
    274 EXPECT_PASS()
    275 {
    276 	ROD_BASE "$@"
    277 	if [ $? -eq 0 ]; then
    278 		tst_resm TPASS "$@ passed as expected"
    279 	else
    280 		tst_resm TFAIL "$@ failed unexpectedly"
    281 	fi
    282 }
    283 
    284 EXPECT_FAIL()
    285 {
    286 	# redirect stderr since we expect the command to fail
    287 	ROD_BASE "$@" 2> /dev/null
    288 	if [ $? -ne 0 ]; then
    289 		tst_resm TPASS "$@ failed as expected"
    290 	else
    291 		tst_resm TFAIL "$@ passed unexpectedly"
    292 	fi
    293 }
    294 
    295 tst_mkfs()
    296 {
    297 	local fs_type=$1
    298 	local device=$2
    299 	shift 2
    300 	local fs_opts="$@"
    301 
    302 	if [ -z "$fs_type" ]; then
    303 		tst_brkm TBROK "No fs_type specified"
    304 	fi
    305 
    306 	if [ -z "$device" ]; then
    307 		tst_brkm TBROK "No device specified"
    308 	fi
    309 
    310 	tst_resm TINFO "Formatting $device with $fs_type extra opts='$fs_opts'"
    311 
    312 	ROD_SILENT mkfs.$fs_type $fs_opts $device
    313 }
    314 
    315 tst_umount()
    316 {
    317 	local device="$1"
    318 	local i=0
    319 
    320 	if ! grep -q "$device" /proc/mounts; then
    321 		tst_resm TINFO "The $device is not mounted, skipping umount"
    322 		return
    323 	fi
    324 
    325 	while [ "$i" -lt 50 ]; do
    326 		if umount "$device" > /dev/null; then
    327 			return
    328 		fi
    329 
    330 		i=$((i+1))
    331 
    332 		tst_resm TINFO "umount($device) failed, try $i ..."
    333 		tst_resm TINFO "Likely gvfsd-trash is probing newly mounted "\
    334 			       "fs, kill it to speed up tests."
    335 
    336 		tst_sleep 100ms
    337 	done
    338 
    339 	tst_resm TWARN "Failed to umount($device) after 50 retries"
    340 }
    341 
    342 # Check a module file existence
    343 # Should be called after tst_tmpdir()
    344 tst_module_exists()
    345 {
    346 	local mod_name="$1"
    347 
    348 	if [ -f "$mod_name" ]; then
    349 		TST_MODPATH="$mod_name"
    350 		return
    351 	fi
    352 
    353 	local mod_path="$LTPROOT/testcases/bin/$mod_name"
    354 	if [ -f "$mod_path" ]; then
    355 		TST_MODPATH="$mod_path"
    356 		return
    357 	fi
    358 
    359 	if [ -n "$TST_TMPDIR" ]; then
    360 		mod_path="$TST_STARTWD/$mod_name"
    361 		if [ -f "$mod_path" ]; then
    362 			TST_MODPATH="$mod_path"
    363 			return
    364 		fi
    365 	fi
    366 
    367 	tst_brkm TCONF "Failed to find module '$mod_name'"
    368 }
    369 
    370 # Appends LTP path when doing su
    371 tst_su()
    372 {
    373 	local usr="$1"
    374 	shift
    375 
    376 	su "$usr" -c "PATH=\$PATH:$LTPROOT/testcases/bin/ $@"
    377 }
    378 
    379 TST_CHECKPOINT_WAIT()
    380 {
    381 	ROD tst_checkpoint wait 10000 "$1"
    382 }
    383 
    384 TST_CHECKPOINT_WAKE()
    385 {
    386 	ROD tst_checkpoint wake 10000 "$1" 1
    387 }
    388 
    389 TST_CHECKPOINT_WAKE2()
    390 {
    391 	ROD tst_checkpoint wake 10000 "$1" "$2"
    392 }
    393 
    394 TST_CHECKPOINT_WAKE_AND_WAIT()
    395 {
    396 	TST_CHECKPOINT_WAKE "$1"
    397 	TST_CHECKPOINT_WAIT "$1"
    398 }
    399 
    400 # Check that test name is set
    401 if [ -z "$TCID" ]; then
    402 	tst_brkm TBROK "TCID is not defined"
    403 fi
    404 
    405 if [ -z "$TST_TOTAL" ]; then
    406 	tst_brkm TBROK "TST_TOTAL is not defined"
    407 fi
    408 
    409 export TCID="$TCID"
    410 export TST_TOTAL="$TST_TOTAL"
    411 
    412 # Setup LTPROOT, default to current directory if not set
    413 if [ -z "$LTPROOT" ]; then
    414 	export LTPROOT="$PWD"
    415 	export LTP_DATAROOT="$LTPROOT/datafiles"
    416 else
    417 	export LTP_DATAROOT="$LTPROOT/testcases/data/$TCID"
    418 fi
    419 
    420 if [ "$TST_NEEDS_CHECKPOINTS" = "1" ]; then
    421 	LTP_IPC_PATH="/dev/shm/ltp_${TCID}_$$"
    422 
    423 	LTP_IPC_SIZE=$(getconf PAGESIZE)
    424 	if [ $? -ne 0 ]; then
    425 		tst_brkm TBROK "getconf PAGESIZE failed"
    426 	fi
    427 
    428 	ROD_SILENT dd if=/dev/zero of="$LTP_IPC_PATH" bs="$LTP_IPC_SIZE" count=1
    429 	ROD_SILENT chmod 600 "$LTP_IPC_PATH"
    430 	export LTP_IPC_PATH
    431 fi
    432