#! /bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (c) 2021 Oracle.  All Rights Reserved.
#
# FS QA Test No. 157
#
# Functional testing for xfs_admin to ensure that it parses arguments correctly
# with regards to data devices that are files, external logs, and realtime
# devices.
#
# Because this test synthesizes log and rt devices (by modifying the test run
# configuration), it does /not/ require the ability to mount the scratch
# filesystem.  This increases test coverage while isolating the weird bits to a
# single test.
#
# This is partially a regression test for "xfs_admin: pick up log arguments
# correctly", insofar as the issue fixed by that patch was discovered with an
# earlier revision of this test.

. ./common/preamble
_begin_fstest auto quick admin

# Override the default cleanup function.
_cleanup()
{
	cd /
	rm -f $tmp.* $fake_logfile $fake_rtfile $fake_datafile
}

# Import common functions.
. ./common/filter

_require_test
_require_scratch_nocheck
_require_command "$XFS_ADMIN_PROG" "xfs_admin"


# Create some fake sparse files for testing external devices and whatnot
fs_size=$((500 * 1024 * 1024))

fake_datafile=$TEST_DIR/$seq.scratch.data
rm -f $fake_datafile
truncate -s $fs_size $fake_datafile

fake_logfile=$TEST_DIR/$seq.scratch.log
rm -f $fake_logfile
truncate -s $fs_size $fake_logfile

fake_rtfile=$TEST_DIR/$seq.scratch.rt
rm -f $fake_rtfile
truncate -s $fs_size $fake_rtfile

scenario() {
	echo "$@" | tee -a $seqres.full

	dev=$SCRATCH_DEV
	logdev=
	rtdev=
}

_fake_mkfs()
{
	OPTIONS="$*"
	if [ -n "$logdev" ]; then
		OPTIONS="$OPTIONS -l logdev=$logdev"
	fi
	if [ -n "$rtdev" ]; then
		OPTIONS="$OPTIONS -r rtdev=$rtdev"
	fi
	$MKFS_XFS_PROG -f $OPTIONS $dev || _fail "mkfs failed"
}

_fake_xfs_db_options()
{
	OPTIONS=""
	if [ ! -z "$logdev" ]; then
		OPTIONS="-l $logdev"
	fi
	if [ ! -z "$rtdev" ]; then
		if [ $XFS_DB_PROG --help 2>&1 | grep -q -- '-R rtdev']; then
			OPTIONS="$OPTIONS -R $rtdev"
		fi
	fi
	echo $OPTIONS $* $dev
}

_fake_xfs_db()
{
	$XFS_DB_PROG "$@" $(_fake_xfs_db_options)
}

_fake_xfs_admin()
{
	local options=("$dev")
	local rt_opts=()
	if [ -n "$logdev" ]; then
		options+=("$logdev")
	fi
	if [ -n "$rtdev" ]; then
		$XFS_ADMIN_PROG --help 2>&1 | grep -q 'rtdev' || \
			_notrun 'xfs_admin does not support rt devices'
		rt_opts+=(-r "$rtdev")
	fi

	# xfs_admin in xfsprogs 5.11 has a bug where an external log device
	# forces xfs_db to be invoked, potentially with zero command arguments.
	# When this happens, xfs_db will wait for input on stdin, which causes
	# fstests to hang.  Since xfs_admin is not an interactive tool, we
	# can redirect stdin from /dev/null to prevent this issue.
	$XFS_ADMIN_PROG "${rt_opts[@]}" "$@" "${options[@]}" < /dev/null
}


_fake_xfs_repair()
{
	OPTIONS=""
	if [ -n "$logdev" ]; then
		OPTIONS="-l $logdev"
	fi
	if [ -n "$rtdev" ]; then
		OPTIONS="$OPTIONS -r $rtdev"
	fi
	$XFS_REPAIR_PROG $OPTIONS $* $dev
}

check_label() {
	_fake_mkfs -L oldlabel >> $seqres.full 2>&1
	_fake_xfs_db -c label
	_fake_xfs_admin -L newlabel "$@" >> $seqres.full
	_fake_xfs_db -c label
	_fake_xfs_repair -n &>> $seqres.full || echo "Check failed?"
}

scenario "S1: Check that label setting with file image"
dev=$fake_datafile
check_label -f

scenario "S2: Check that setting with logdev works"
logdev=$fake_logfile
check_label

scenario "S3: Check that setting with rtdev works"
rtdev=$fake_rtfile
check_label

scenario "S4: Check that setting with rtdev + logdev works"
logdev=$fake_logfile
rtdev=$fake_rtfile
check_label

scenario "S5: Check that setting with nortdev + nologdev works"
check_label

scenario "S6: Check that setting with bdev incorrectly flagged as file works"
check_label -f

# success, all done
status=0
exit
