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