#!/bin/bash

FSTESTCFG=""
SNAPSHOT=",snapshot=on"
DO_AEX="yes"
API="1.5"
ORIG_CMDLINE="$*"
nowrap=
if base64 -w 0 < /dev/null >& /dev/null ; then
    nowrap="-w 0"
fi
ORIG_CMDLINE_B64=$(echo -n "$ORIG_CMDLINE" | sed -e "s/^ //" | base64 $nowrap)
TESTRUNID=

ourtmp=$(mktemp --tmpdir --directory xfstests-cli.XXXXXXXX)
done_cleanup=false

set_default_arch

trap '_cleanup; exit 0' 0
trap '_cleanup; exit 1' 1 2 3 15

_cleanup()
{
    if $done_cleanup
    then
	:
    else
	rm -rf "$ourtmp"
	done_cleanup=true
    fi
}

supported_flavors ()
{
    flavor_in "$@" || print_help
}

print_help ()
{
    PROG=$(basename "$0")
    echo "Usage: $PROG [<OPTIONS>] smoke|full"
    echo "Usage: $PROG [<OPTIONS>] <test> ..."
    echo "Usage: $PROG [<OPTIONS>] -g <group> ..."
    echo "Usage: $PROG [<OPTIONS>] shell|maint"
    echo "Usage: $PROG [<OPTIONS>] syz <repro>"
    echo ""
    echo "Common options are:"
    echo "	-a		- Disable auto-exclude; run all tests"
    echo "	-c config	- Specify a file system configuration"
    echo "	-C count	- Run the specified tests multiple times"
    echo "	-I image	- Use this test appliance image"
    echo "	-m mountopts	- Append mount options to fs config"
    if flavor_in kvm gce ; then
	echo "	-n nr_cpus	- Specify the number of cpu's"
    fi
    if flavor_in kvm ; then
	echo "	-numa num	- Ask KVM to create <num> NUMA nodes"
	echo "	-N		- Enable networking (requires root)"
    fi
    if flavor_in kvm gce ; then
	echo "	-o opts		- Extra kernel command line options"
    fi
    echo "	-O opts		- Extra options for test runner"
    if flavor_in kvm gce ; then
	echo "	-r ram		- Specify memory to be used in megabytes"
    fi
    echo "	-x group	- Exclude group of tests from running"
    echo "	-X test		- Exclude test from running"
    echo "	--kernel file	- Boot the specified kernel"
    if flavor_in gce ; then
	echo "	--arch arch	- Specify the architecture to run on"
    fi
    if flavor_in kvm ; then
	echo "	--initrd initrd	- Boot with the specified initrd"
    elif flavor_in gce ; then
	echo "	--pmem-device	- Set up persistent memory devices for DAX"
    fi
    if flavor_in kvm android ; then
	echo "	--no-log	- Don't save the log file for this run"
    fi
    if flavor_in kvm gce ; then
	echo "	--no-action	- Print the command to start the VM"
    fi
    if flavor_in gce ; then
	echo "	--email email	- Specify the email address to send a report to"
	echo "	--no-email	- Do not send an email"
    fi
    if flavor_in gce ; then
	echo "	--no-region-shard"
	echo "			- Don't shard test VMs into other GCE zones"
	echo "	--bucket-subdir	- Use the next argument as a bucket subdir"
    fi
    if flavor_in gce ; then
	echo "	--monitor-timeout time	- LTM option to reboot test VM if no"
	echo "		status update after specified time. Accepted time"
	echo "		suffixes include \"h\", \"m\", \"s\"."
    fi
    echo ""
    echo "Common file system configurations are:"
    echo "	4k 1k ext3 nojournal ext3conv metacsum dioread_nolock "
    echo "	data_journal bigalloc_4k bigalloc_1k inline"
    echo ""
    echo "xfstest names have the form: ext4/NNN generic/NNN shared/NNN"
    echo ""
    if flavor_in gce ; then
	echo "Common gce-xfstests commands:"
	echo "	ls		- List running xfstests instances"
	echo "	abort		- Abort a xfstests instance"
	echo "	ls-results	- List saved test results"
	echo "	get-results	- Get and display a specified test result"
	echo "	setup		- Set up gce-xfstests (only needs to be run once)"
	echo "	ssh		- Login to a running test instance"
	echo "	console		- Get the console messages from a test instance"
	echo "	serial		- Attach to the serial port of a test instance"
	echo "	launch-ltm	- Launch an LTM instance. Running the LTM"
	echo "			  requires that you build a gce-xfstests image"
	echo "			  yourself, and set GCE_IMAGE_PROJECT to your own project."
	echo "			  See documentation for details."
	echo "	ltm		- Send the command to the LTM."
	echo "			  Note: NR_CPU and MEM must be their default values."
    fi
    exit 1
}

validate_test_name()
{
    if test -z "$DO_BLKTESTS" ; then
	case "$1" in
	    btrfs*|ceph*|cifs*|ext4*|f2fs*|generic*|nfs*) ;;
	    ocfs2*|overlay*|perf*|shared*|udf*|xfs*|selftest*) ;;
	    *)
		echo -e "Invalid xfstests test name: $1\n"
		print_help
		exit 1
		;;
	esac
    else
	case "$1" in
	    block*|loop*|meta*|nbd*|nvme*|nvmeof-mp*|scsi*|srp*) ;;
	    *)
		echo -e "Invalid blktests test name: $1\n"
		print_help
		exit 1
		;;
	esac
    fi
}

validate_config_name()
{
    local arg="$1"
    local fs
    local cfg
    local base_fstype

    if [[ "$arg" == *":"* ]]; then
	base_fstype="${arg%%:*}"
	arg="${arg#*:}"
    fi

    CONFDIR="$(dirname "$DIR")/test-appliance/files/root/fs"
    if test -d "$CONFDIR"
    then
	case "$arg" in
	    */*)
		fs="${arg%%/*}"
		cfg="${arg#*/}"
		;;
	    *)
		if test -d "$CONFDIR/$arg"
		then
		    fs="$arg"
		    cfg=default
		else
		    fs="$PRIMARY_FSTYPE"
		    cfg="$arg"
		fi
		;;
	esac
	if test ! -d "$CONFDIR/$fs" ; then
	    echo -e "Invalid file system type: $fs\n"
	    print_help
	    exit 1
	fi
	# use fs types in CONFDIR as valid options for the base fstype
	if test ! -d "$CONFDIR/$base_fstype" ; then
	    echo -e "Invalid file system type for base fstype: $base_fstype\n"
	    print_help
	    exit 1
	fi
	. "$CONFDIR/$fs/config"
	cfg=$(test_name_alias $cfg)
	if test -f "$CONFDIR/$fs/cfg/$cfg" -o \
		-f "$CONFDIR/$fs/cfg/$cfg.list"
	then
	    return
	else
	    echo -e "Invalid config name: $arg\n"
	    print_help
	    exit 1
	fi
    fi
}

validate_commit_name()
{
    if test -z "$GIT_REPO"; then
        echo "GIT_REPO is neither found in the config file nor provided with --repo"
        exit 1
    fi
    if [[ "$GIT_REPO" != *".git" ]]; then
	GIT_REPO="$GIT_REPO.git"
    fi
    if ! git ls-remote "$GIT_REPO" &> /dev/null; then
	echo -e "Repo not found: $GIT_REPO\n"
	exit 1
    elif ! git ls-remote "$GIT_REPO" | grep "$1" &> /dev/null; then
	echo "Warning: $1 is not a valid branch or tag of $GIT_REPO"
    fi
}

validate_branch_name()
{
    if test -z "$GIT_REPO"
    then
        echo "GIT_REPO is neither found in the config file nor provided with --repo"
        exit 1
    fi
    if [[ "$GIT_REPO" != *".git" ]]; then
        GIT_REPO="$GIT_REPO.git"
    fi
    if ! git ls-remote "$GIT_REPO" > /dev/null; then
	echo -e "Repo not found: $GIT_REPO\n"
	exit 1
    elif ! git ls-remote --heads  --exit-code "$GIT_REPO" $1 > /dev/null; then
	echo -e "$1 is not a valid branch of $GIT_REPO"
	exit 1
    fi
}

SKIP_KERNEL_ARCH_PROBE=

shortopts="ac:C:g:hI:m:n:No:O:r:vx:X:"
longopts=(
aio:
arch:
arm64
archive
bisect-bad:
bisect-good:
blktests
bucket-subdir:
cache:
commit:
config:
cpu-type:
disable-serial
email:
enable-serial
fail-loop-count:
gce-disk-spec:
gce-network:
gce-zone:
gs-bucket:
help
hooks:
i386
image-family:
image-project:
initrd:
instance-name:
junit-email:
kernel:
kernel-arch:
kbuild-opts:
kconfig-opts:
local-ssd
local-ssd-nvme
log
machtype:
modules:
monitor-timeout:
nfssrv:
note:
oslogin
no-oslogin
oslogin-2fa
no-oslogin-2fa
no-action
no-archive
no-collapse
no-email
no-insert
no-junit-email
no-log
no-preemptible
no-spot-fallback
no-spot
no-punch
no-region-shard
no-virtio-rng
no-vm-timeout
no-zero
numa:
pmem-device
pts-size:
preemptible
spot
spot-fallback
primary_fstype:
repo:
skip-kernel-arch-probe
soak-duration:
stress-mem:
stress-opts:
testrunid:
unwatch:
update-files
update-xfstests
update-xfstests-tar
virtfs-model:
virtfs-scratch:
virtfs-test:
virtfs:
watch:
)
longopts=$(echo "${longopts[*]}" | tr ' ' ,)

if ! options=$(getopt -o "$shortopts" -l "$longopts" -- "$@"); then
    print_help
fi

eval set -- "$options"
while (( $# >= 1 )); do
    case "$1" in
	-a)
	    DO_AEX=""
	    ;;
	-c) shift
	    if test -n "$FSTESTCFG" ; then
		echo "The '-c' option (or 'smoke') can only be specified once. "
		echo "If you want to run tests in multiple configurations," \
			"use -c CFG1,CFG2,..."
		exit 1
	    fi
	    for i in ${1//,/ }
	    do
		validate_config_name "$i"
	    done
	    FSTESTCFG="$1"
	    ;;
	-C) shift
	    LOOP_COUNT="$1"
	    LOOP_COUNT_EXPLICIT=yes
	    ;;
	-m) shift
	    MNTOPTS="$1"
	    ;;
	-r) shift
	    supported_flavors kvm gce
	    case "$1" in
		*[mM])
		    MEM=$(echo "$1" | sed -e 's/[mM]$//')
		    ;;
		*[gG])
		    temparg=$(echo "$1" | sed -e 's/[gG]$//')
		    MEM=$(expr "$temparg" \* 1024)
		    unset temparg
		    ;;
		*)
		    MEM="$1"
		    ;;
	    esac
	    EXPLICIT_RAM=yes
	    ;;
	-g) shift
	    FSTESTSET="$FSTESTSET,-g,$1"
	    ;;
	-x) shift
	    FSTESTSET="$FSTESTSET,-x,$1"
	    ;;
	-h|--help|help)
	    print_help
	    ;;
	-I) shift
	    ROOT_FS="$1"
	    if flavor_in gce ; then
		IMAGE_FLAG="--image"
	    fi
	    EXPLICIT_ROOT_FS=yes
	    ;;
	-n) shift
	    supported_flavors kvm gce
	    NR_CPU="$1"
	    EXPLICIT_CPU=yes
	    ;;
	-o) shift
	    supported_flavors kvm gce
	    EXTRA_ARG=$(echo "$1" | sed -e 's/ /:/g')
	    ;;
	-v)
	    supported_flavors kvm gce
	    if test "$V" = "1" ; then
		QUIET=""
		V=2
	    else
		QUIET="systemd.show_status=auto systemd.log_level=crit"
		V=1
	    fi
	    ;;
	-N)
	    supported_flavors kvm
	    DO_NET=yes
	    ;;
	-O) shift
	    FSTESTOPT="$FSTESTOPT,extra_opt,$1"
	    ;;
	-X) shift
	    if test -n "$FSTESTEXC" ; then
		FSTESTEXC="$FSTESTEXC,$1"
	    else
		FSTESTEXC="$1"
	    fi
	    ;;
	--arch) shift
	    supported_flavors kvm gce
	    ARCH="$1"
	    EXPLICIT_ARCH=yes
	    ;;
	--arm64)
	    supported_flavors kvm gce
	    ARCH="arm64"
	    EXPLICIT_ARCH=yes
	    ;;
	--i386)
	    supported_flavors kvm gce
	    ARCH="i386"
	    EXPLICIT_ARCH=yes
	    ;;
	--blktests)
	    supported_flavors kvm gce
	    FSTESTOPT="$FSTESTOPT,blktests"
	    DO_BLKTESTS=yes
	    ;;
	--hooks) shift
	    supported_flavors gce
	    GCE_HOOKS="$1"
	    ;;
	--image-family) shift
	    supported_flavors gce
	    ROOT_FS="$1"
	    IMAGE_FLAG="--image-family"
	    EXPLICIT_ROOT_FS=yes
	    ;;
	--fail-loop-count) shift
	    FAIL_LOOP_COUNT="$1"
	    FAIL_LOOP_COUNT_EXPLICIT=yes
	    ;;
	--update-xfstests-tar)
	    supported_flavors kvm gce
	    UPDATE_XFSTESTS_TAR=yes
	    UPDATE_XFSTESTS=yes
	    ;;
	--update-xfstests)
	    supported_flavors kvm gce
	    if ! test -f "$DIR/../fstests-bld/xfstests.tar.gz"
	    then
		echo "The xfstests.tar.gz file has not been built!"
		exit 1
	    fi
	    UPDATE_XFSTESTS=yes
	    ;;
	--update-files)
	    supported_flavors kvm gce
	    UPDATE_FILES=yes
	    ;;
	--nfssrv) shift
	    NFSSRV="$1"
	    ;;
	--numa) shift
	    supported_flavors kvm
	    NUMA_NUM="$1"
	    case "$NUMA_NUM" in
		''|*[!0-9]*)
		    echo "Invalid number of NUMA nodes: $NUMA_NUM"
		    exit 1
	    esac
	    ;;
	--cpu-type) shift
	    supported_flavors kvm
	    CPU_TYPE="$1"
	    ;;
	--oslogin)
	    supported_flavors gce
	    GCE_OSLOGIN=TRUE
	    ;;
	--no-oslogin)
	    supported_flavors gce
	    GCE_OSLOGIN=FALSE
	    ;;
	--oslogin-2fa)
	    supported_flavors gce
	    GCE_OSLOGIN_2FA=TRUE
	    ;;
	--no-oslogin-2fa)
	    supported_flavors gce
	    GCE_OSLOGIN_2FA=FALSE
	    ;;
	--no-action)
	    supported_flavors kvm gce
	    NO_ACTION="echo -e Would execute:\n\t"
	    SKIP_LOG=yes
	    ;;
	--no-punch)
	    NO_PUNCH=yes
	    ;;
	--no-collapse)
	    NO_COLLAPSE=yes
	    ;;
	--no-insert)
	    NO_INSERT=yes
	    ;;
	--no-zero)
	    NO_ZERO=yes
	    ;;
	--no-log)
	    supported_flavors kvm android
	    SKIP_LOG=yes
	    ;;
	--log)
	    supported_flavors kvm android
	    SKIP_LOG=no
	    ;;
	--kernel) shift
	    KERNEL="$1"
	    OVERRIDE_KERNEL="$KERNEL"
	    ;;
	--kernel-arch) shift
	    KERNEL_ARCH="$1"
	    SKIP_KERNEL_ARCH_PROBE="yes"
	    ;;
	--modules) shift
	    supported_flavors kvm gce
	    case "$1" in
		gs://*)
		    MODULES="$1"
		    ;;
		//*)
		    MODULES=$(echo "$1" | sed -e "s;//;gs://$GS_BUCKET/;")
		    ;;
		none)
		    MODULES=""
		    ;;
		*)
		    if test -f "$1" ; then
			MODULES="$1"
		    else
			echo "Can't find modules at $1"
			exit 1
		    fi
		    ;;
	    esac
	    OVERRIDE_MODULES="$MODULES";
	    ;;
	--note) shift
	    ;;
	--initrd) shift
	    supported_flavors kvm
	    INITRD="$1"
	    if test ! -f "$INITRD" ; then
		print_help
	    fi
	    ;;
	--local-ssd)
	    supported_flavors gce
	    DO_LOCAL_SSD=SCSI
	    ;;
	--local-ssd-nvme)
	    supported_flavors gce
	    DO_LOCAL_SSD=NVME
	    ;;
	--pmem-device)
	    supported_flavors gce
	    PMEM_DEVICE=yes
	    ;;
	--machtype) shift
	    supported_flavors gce kvm
	    if flavor_in gce ; then
		GCE_MACHTYPE="$1"
	    else
		KVM_MACHTYPE="$1"
	    fi
	    ;;
	--image-project) shift
	    supported_flavors gce
	    GCE_IMAGE_PROJECT="$1"
	    ;;
	--instance-name) shift
	    supported_flavors gce
	    INSTANCE_NAME="$1"
	    ;;
	--no-virtio-rng)
	    supported_flavors kvm
	    NO_VIRTIO_RNG=yes
	    ;;
	--no-vm-timeout)
	    supported_flavors gce
	    GCE_NO_VM_TIMEOUT=yes
	    ;;
	--preemptible|--spot)
	    supported_flavors gce
	    GCE_SPOT=yes
	    ;;
	--spot-fallback)
	    supported_flavors gce
	    GCE_SPOT_FALLBACK=yes
	    ;;
	--primary_fstype) shift
	    PRIMARY_FSTYPE="$1"
	    ;;
	--pts-size) shift
	    supported_flavors gce
	    PTS_SIZE="$1"
	    ;;
	--no-preemptible|--no-spot)
	    supported_flavors gce
	    GCE_SPOT=
	    ;;
	--no-spot-fallback)
	    supported_flavors gce
	    GCE_SPOT_FALLBACK=
	    ;;
	--gce-disk-spec) shift
	    supported_flavors gce
	    GCE_DISK_SPEC="$1"
	    ;;
	--gce-network) shift
	    supported_flavors gce
	    GCE_NETWORK="$1"
	    if ! gcloud compute networks describe "$GCE_NETWORK" > /dev/null ; then
		echo -e "Invalid GCE network: $GCE_NETWORK"
		echo -e "To see a list of valid zones, run"
		echo -e "\tgcloud compute networks list\n"
		exit 1
	    fi
	    ;;
	--gce-zone) shift
	    supported_flavors gce
	    GCE_ZONE="$1"
	    if ! gcloud compute zones describe "$GCE_ZONE" > /dev/null ; then
		echo -e "Invalid GCE zone: $GCE_ZONE"
		echo -e "To see a list of valid zones, run"
		echo -e "\tgcloud compute zones list\n"
		exit 1
	    fi
	    ;;
	--gs-bucket) shift
	    supported_flavors gce
	    GS_BUCKET="$1"
	    if ! gsutil ls -b "gs://$GS_BUCKET" > /dev/null ; then
		echo -e "Invalid Cloud Storage Bucket: $GS_BUCKET\n"
		exit 1
	    fi
	    ;;
	--bucket-subdir) shift
	    supported_flavors gce
	    BUCKET_SUBDIR="$1"
	    ;;
	--repo) shift
	    supported_flavors gce
	    if test -n "${GIT_REPOS[$1]}" ; then
		GIT_REPO="${GIT_REPOS[$1]}"
	    else
		GIT_REPO="$1"
	    fi
	    ;;
	--commit) shift
	    supported_flavors gce
	    OVERRIDE_KERNEL="none"
	    COMMIT="$1"
	    ;;
	--watch) shift
	    supported_flavors gce
	    OVERRIDE_KERNEL="none"
	    BRANCH="$1"
	    ;;
	--unwatch) shift
	    supported_flavors gce
	    OVERRIDE_KERNEL="none"
	    WATCHER_ID="$1"
	    ;;
	--bisect-bad) shift
	    supported_flavors gce
	    BISECT_BAD="$1"
	    OVERRIDE_KERNEL="none"
	    ;;
	--bisect-good) shift
	    supported_flavors gce
	    if test -z "$BISECT_GOOD"; then
		BISECT_GOOD="$1"
	    else
		BISECT_GOOD="$BISECT_GOOD|$1"
	    fi
	    OVERRIDE_KERNEL="none"
	    ;;
	--config) shift
	    supported_flavors gce
	    KCONFIG="$1"
	    case "$KCONFIG" in
		gs://*) ;;
		*)
		    if test -e "$KCONFIG"
		    then
			gsutil cp "$KCONFIG" "gs://$GS_BUCKET/build_config"
			KCONFIG="gs://$GS_BUCKET/build_config"
		    else
			echo -e "Could not find: $1\n"
			print_help
			exit 1
		    fi
		    ;;
	    esac
	    ;;
	--kconfig-opts) shift
	    supported_flavors gce
	    KCONFIG_OPTS="$1"
	    ;;
	--kbuild-opts) shift
	    supported_flavors gce
	    KBUILD_OPTS="$1"
	    ;;
	--testrunid) shift
	    supported_flavors gce kvm
	    TESTRUNID="$1"
	    ;;
	--email) shift
	    supported_flavors gce
	    GCE_REPORT_EMAIL="$1"
	    ;;
	--no-email)
	    supported_flavors gce
	    GCE_REPORT_EMAIL=""
	    ;;
	--junit-email) shift
	    supported_flavors gce
	    GCE_JUNIT_EMAIL="$1"
	    ;;
	--no-junit-email)
	    supported_flavors gce
	    GCE_JUNIT_EMAIL=""
	    ;;
	--no-region-shard)
	    supported_flavors gce
	    if test -z "$RUN_ON_LTM"; then
		echo -e "The --no-region-shard option does not do anything if\n"
		echo -e "not run on the ltm!\n"
		echo -e "Use \"gce-xfstests ltm\" to send a command to the ltm\n"
		exit 1
	    fi
	    NO_REGION_SHARD="yes"
	    ;;
	--aio) shift
	    supported_flavors kvm
	    if test "$1" = "default" ; then
		AIO=
	    else
		AIO=",aio=$1"
	    fi
	    ;;
	--cache) shift
	    supported_flavors kvm
	    CACHE="$1"
	    if test "$CACHE" = "default" ; then
		CACHE=
	    fi
	    ;;
	--virtfs) shift
	    supported_flavors kvm
	    VIRTFS_PATH="$1"
	    ;;
	--virtfs-test) shift
	    supported_flavors kvm
	    VIRTFS_TEST_PATH="$1"
	    ;;
	--virtfs-scratch) shift
	    supported_flavors kvm
	    VIRTFS_SCRATCH_PATH="$1"
	    ;;
	--virtfs-model) shift
	    supported_flavors kvm
	    VIRTFS_MODEL="$1"
	    ;;
	--archive)
	    supported_flavors kvm
	    DO_ARCHIVE=1
	    ;;
	--no-archive)
	    supported_flavors kvm
	    unset DO_ARCHIVE
	    ;;
	--stress-opts) shift
	    supported_flavors kvm gce
	    stress_opts=$(echo "$1" | sed -e 's/ /,/g')
	    if test -n "$FSTESTSTR" ; then
		FSTESTSTR="$FSTESTSTR $stress_opts"
	    else
		FSTESTSTR="$stress_opts"
	    fi
	    unset stress_opts
	    ;;
	--stress-mem) shift
	    supported_flavors kvm gce
	    stress_opts="-m,1,--vm-bytes,$1"
	    if test -n "$FSTESTSTR" ; then
		FSTESTSTR="$FSTESTSTR $stress_opts"
	    else
		FSTESTSTR="$stress_opts"
	    fi
	    unset stress_opts
	    ;;
	--enable-serial)
	    GCE_SERIAL_PORT_ACCESS=TRUE
	    ;;
	--enable-serial)
	    GCE_SERIAL_PORT_ACCESS=TRUE
	    ;;
	--disable-serial)
	    GCE_SERIAL_PORT_ACCESS=FALSE
	    ;;
	--skip-kernel-arch-probe)
	    SKIP_KERNEL_ARCH_PROBE=YES
	    ;;
	--soak-duration) shift
	    SOAK_DURATION="$1"
	    ;;
	--monitor-timeout) shift
	    MONITOR_TIMEOUT="$1"
	    ;;
	--)
	    shift
	    break
	    ;;
	*)
	    echo 1>&2 "Invalid option: \"$1\""
	    print_help
	    ;;
    esac
    shift
done

while (( $# >= 1 )); do
    case "$1" in
	smoke)
	    DO_SMOKE=yes
	    ;;
	quick)
	    FSTESTSET="$FSTESTSET,-g,quick"
	    ;;
	full)
	    FSTESTSET="$FSTESTSET,-g,auto"
	    ;;
	syz)
	    supported_flavors kvm
	    shift
	    if test "$1"x = "x" ; then
		echo "Missing syzkaller repro"
		print_help
		exit 1
	    fi
	    mkdir -p "$ourtmp/xfstests/tests"
	    cp -r "$DIR/test-appliance/syz" "$ourtmp/xfstests/tests"
	    repro="$1"
	    case "$repro" in
		https://syzkaller*repro.syz*)
		    curl -o "$ourtmp/repro.syz" "$repro"
		    ed "$ourtmp/repro.syz" >& /dev/null <<EOF
1i
# Downloaded from $repro
.
w
q
EOF
		    repro="$ourtmp/repro.syz"
		    save_copy="/tmp/$USER-downloaded-repro.syz"
		    cp $repro "$save_copy"
		    echo "Saved downloaded copy at $save_copy"
		    ;;
		https://syzkaller*repro.c*)
		    curl -o "$ourtmp/repro.c" "$repro"
		    ed "$ourtmp/repro.c" >& /dev/null <<EOF
1i
// Downloaded from $repro
.
w
q
EOF
		    repro="$ourtmp/repro.c"
		    save_copy="/tmp/$USER-downloaded-repro.c"
		    cp $repro "$save_copy"
		    echo "Saved downloaded copy at $save_copy"
		    ;;
		https://*)
		    echo "Unknown URL: $repro"
		    exit 1
		    ;;
	    esac
	    case "$repro" in
		*.c)
		    if test -f "$repro" ; then
			exe="$ourtmp/xfstests/tests/syz/001.exe"
			if ! gcc -o $exe -static $repro -lpthread ; then
			    echo "Failed to build $repro"
			    exit 1;
			fi
		    else
			echo "Reproduction file $repro not found"
			exit 1
		    fi
		    ;;
		*.syz)
		    if ! test -f "$repro" ; then
			echo "Reproduction file $repro not found"
			exit 1
		    fi
		    cp "$repro" "$ourtmp/xfstests/tests/syz/001.syz"
		    ;;
		*)
		    if ! test -f "$repro" ; then
			echo "Reproduction file $repro not found"
			exit 1
		    fi
		    if ! test -x "$repro" ; then
			echo "Reproduction file $repro not executable"
			exit 1
		    fi
		    cp "$repro" "$ourtmp/xfstests/tests/syz/001.exe"
		    ;;
	    esac
	    tar -C "$ourtmp" -cvz -f "$ourtmp/extra-tests.tar.gz" xfstests \
		>& /dev/null
	    UPDATE_EXTRA_TESTS=yes
	    FSTESTSET="$FSTESTSET,syz/001"
	    ;;
	launch)
	    supported_flavors gce
	    ARG="cmd=maint"
	    NO_SSH=yes
	    ;;
	shell)
	    ARG="cmd=maint"
	    ;;
	maint)
	    if ! flavor_in gce ; then
		ARG="cmd=maint"
		EPH="-root_ephemeral=no"
		SNAPSHOT=""
	    else
		ARG="cmd=maint"
		if test -z "$GCE_MACHTYPE"
		then
		    GCE_MACHTYPE="f1-micro"
		fi
		OVERRIDE_KERNEL="none"
	    fi
	    ;;
	pts|phoronix)
	    supported_flavors gce
	    ARG="cmd=pts"
	    DO_PTS="yes"
	    ;;
	ver)
	    ARG="cmd=ver"
	    ;;
	*)
	    validate_test_name "$1"
	    FSTESTSET="$FSTESTSET,$1"
	    ;;
    esac
    shift
done

if test -n "$DO_SMOKE" ; then
    SOAK_DURATION=3m
    FSTESTSET="$FSTESTSET,-g,smoketest"
    if test -z "$FSTESTCFG" ; then
	FSTESTCFG="$PRIMARY_FSTYPE/default"
    fi
fi

if test -z "$FSTESTCFG" ; then
    FSTESTCFG=all
fi

if test -n "$RUN_ON_LTM" -a -n "$DO_BLKTESTS"
then
    echo "Block tests can not be using LTM"
    exit 1
fi

if test -n "$RUN_ON_KCS" -a -n "$DO_BLKTESTS"
then
    echo "Block tests can not be using KCS"
    exit 1
fi

if test -n "$COMMIT"
then
    validate_commit_name $COMMIT
fi

if test -n "$BRANCH"
then
    validate_branch_name $BRANCH
fi

if test -n "$BISECT_GOOD" -o -n "$BISECT_BAD"
then
	if test -z "$BISECT_BAD" -o -z "$BISECT_BAD"
	then
		echo "Both BISECT_GOOD and BISECT_BAD should be set"
		exit 1
	fi
	validate_commit_name $BISECT_BAD
fi

if test -n "$RUN_ON_KCS" -a -z "$COMMIT"
then
    echo "No commit id specified for KCS to build"
    exit 1
fi

if test -n "$COMMIT" -a -z "$RUN_ON_LTM" -a -z "$RUN_ON_KCS"
then
    echo "Commit id only works with LTM or KCS"
    exit 1
fi

if test -z "$FAIL_LOOP_COUNT_EXPLICIT" -a -n "$LOOP_COUNT"
then
    FAIL_LOOP_COUNT=
fi

if test -z "$LOOP_COUNT_EXPLICIT" -a -n "$FAIL_LOOP_COUNT"
then
    LOOP_COUNT=
fi

if test -n "$FAIL_LOOP_COUNT" -a -n "$LOOP_COUNT"
then
    echo "The options -C and --fail-loop-count are mutually exclusive"
    exit 1
fi

if test -n "$FAIL_LOOP_COUNT" ; then
    FSTESTOPT="$FSTESTOPT,fail_loop_count,$FAIL_LOOP_COUNT"
fi

if test -n "$LOOP_COUNT" ; then
    FSTESTOPT="$FSTESTOPT,count,$LOOP_COUNT"
    # Older test appliances don't clear fail_loop_count default
    # This can be removed in the future...
    FSTESTOPT="$FSTESTOPT,fail_loop_count,0"
fi

if test -n "$KCONFIG" -a -z "$RUN_ON_LTM" -a -z "$RUN_ON_KCS"
then
    echo "--config only is supported with LTM or KCS"
    exit 1
fi

if test -n "$KCONFIG_OPTS" -a -z "$RUN_ON_LTM" -a -z "$RUN_ON_KCS"
then
    echo "--kconfig-opts only is supported with LTM or KCS"
    exit 1
fi

if test -n "$KBUILD_OPTS" -a -z "$RUN_ON_LTM" -a -z "$RUN_ON_KCS"
then
    echo "--kbuild-opts only is supported with LTM or KCS"
    exit 1
fi

if test -n "$BRANCH" -a -z "$RUN_ON_LTM"
then
    echo "Repo watcher only works with LTM"
    exit 1
fi

if test -n "$COMMIT" -a -n "$BRANCH"
then
    echo "--commit conflicts with --watch"
fi

if test -z "$FSTESTSET" -a -z "$ARG" -a -z "$DO_BLKTESTS" \
    -a -z "$RUN_ON_KCS" -a -z "$WATCHER_ID" -a -z "$LTM_INFO"
then
    echo -e "No tests specified!\n"
    print_help
    exit 1
fi

if test "$ARG" = "cmd=maint" -a -z "$SKIP_LOG" ; then
  SKIP_LOG=yes
fi

if test "$ARG" = "cmd=ver" -a -z "$SKIP_LOG" ; then
  SKIP_LOG=yes
fi

if test "$DO_AEX" = yes ; then
    FSTESTOPT="$FSTESTOPT,aex"
fi

if test "$NO_PUNCH" = yes ; then
    FSTESTOPT="$FSTESTOPT,no_punch"
fi

if test "$NO_COLLAPSE" = yes ; then
    FSTESTOPT="$FSTESTOPT,no_collapse"
fi

if test "$NO_INSERT" = yes ; then
    FSTESTOPT="$FSTESTOPT,no_insert"
fi

if test "$NO_ZERO" = yes ; then
    FSTESTOPT="$FSTESTOPT,no_zero"
fi

if test -n "$SOAK_DURATION" ; then
    FSTESTOPT="$FSTESTOPT,soak,$SOAK_DURATION"
fi

FSTESTOPT=${FSTESTOPT/#,/}

case "$FSTESTCFG" in
    dax|dax,*|*,dax,*|*,dax|*/dax|*/dax,*)
	PMEM_DEVICE=yes
	;;
    filestore*|*filestore|*filestore*)
	if test -z "$NFSSRV" ; then
	    NFSSRV=filestore
	fi
	;;
esac

if test "$SKIP_LOG" = no ; then
   unset SKIP_LOG
fi

if test -n "$ARG" ; then
    :
elif test -n "$DO_BLKTESTS" ; then
    ARG="fstestopt=$FSTESTOPT"
    if test -n "$FSTESTSET" ; then
     FSTESTSET=${FSTESTSET/#,/}
     ARG="$ARG fstestset=$FSTESTSET"
    fi
elif test -n "$FSTESTSET"; then
     FSTESTSET=${FSTESTSET/#,/}
     ARG="fstestcfg=$FSTESTCFG fstestset=$FSTESTSET fstestopt=$FSTESTOPT"
fi
if test -n "$FSTESTEXC" ; then
    ARG="$ARG fstestexc=$FSTESTEXC"
fi

if test -n "$MNTOPTS" ; then
    ARG="$ARG mount_opts=$MNTOPTS"
fi

if test -n "$NFSSRV" ; then
    ARG="$ARG nfssrv=$NFSSRV"
fi

if test -n "$TZ" ; then
    ARG="$ARG fstesttz=$TZ"
fi

if test -n "$DO_ARCHIVE" ; then
    ARG="$ARG fstestarc=$DO_ARCHIVE"
fi

set_canonicalized_arch "$ARCH"

find_kernel_to_use

if test -z "$SKIP_KERNEL_ARCH_PROBE" -a "$OVERRIDE_KERNEL" != "none" ; then
   get_kernel_file_info "$KERNEL"
fi
if test -n "$KERNEL_ARCH" ; then
    if test "$KERNEL_ARCH" = "x86" -a \
	    \( "$ARCH" = "i386" -o "$ARCH" = "amd64" \) ; then
	KERNEL_ARCH="$ARCH"
    fi
    if test -n "$EXPLICIT_ARCH" ; then
	if test "$ARCH" != "$KERNEL_ARCH" ; then
	    echo "Kernel $KERNEL is apparently built for $KERNEL_ARCH"
	    echo "Expected architecture: $ARCH"
	    exit 1
	fi
    else
	ARCH="$KERNEL_ARCH"
    fi
fi

if test -n "$UPDATE_XFSTESTS_TAR" ; then
    (cd "$DIR/../fstests-bld" ; ./gen-tarball --fast --arch "$ARCH")
fi

if test -n "$PMEM_DEVICE" ; then
    if test -n "$EXTRA_ARG" ; then
	EXTRA_ARG="$EXTRA_ARG:"
    fi
    EXTRA_ARG="${EXTRA_ARG}"'memmap=4G!9G:memmap=9G!14G'
    if test -z "$EXPLICIT_RAM" -a -z "$GCE_MACHTYPE"; then
	MEM=26624
	NR_CPU=4
	EXPLICIT_RAM=yes
	EXPLICIT_CPU=yes
    elif test "$MEM" -lt 14436 ; then
	MEM=14436
    fi
fi

if test -n "$DO_PTS" -a -z "$EXPLICIT_RAM" -a -z "$EXPLICIT_CPU" -a \
	-z "$GCE_MACHTYPE" ; then
    GCE_MACHTYPE="n1-standard-16"
fi

if test -n "$NUMA_NUM" ; then
    if test "$NUMA_NUM" -lt 2 ; then
	echo "Invalid number of NUMA nodes ($NUMA_NUM) too small"
	exit 1
    fi
    if test "$NUMA_NUM" -gt "$NR_CPU" ; then
	echo "Can't have more NUMA nodes than CPUs"
	exit 1
    fi
    NUMA="-numa node"
    for i in $(seq 2 "$NUMA_NUM") ; do
	NUMA="$NUMA -numa node"
    done
fi

if test -n "$CPU_TYPE" ; then
    if test "$CPU_TYPE" = none ; then
	CPU_TYPE=
    else
	CPU_TYPE="-cpu $CPU_TYPE"
    fi
fi

if test -z "$NO_VIRTIO_RNG" ; then
    VIRTIO_RNG="-object rng-random,filename=/dev/urandom,id=rng0 \
	-device virtio-rng-pci,rng=rng0"
fi

ARG="$ARG fstesttyp=$PRIMARY_FSTYPE fstestapi=$API"

if test -n "$FSTESTSTR" ; then
    ARG="$ARG fsteststr=$FSTESTSTR"
fi

if test -n "$PTS_SIZE" ; then
    ARG="$ARG pts_size=$PTS_SIZE"
fi

ARG="$ARG orig_cmdline=$ORIG_CMDLINE_B64"
