#!/bin/sh -f
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
#

status=0
require_offline=""
require_online=""
have_db=""
have_repair=""
opt_extflg=""			# -e
opt_force=""			# -f
opt_log2=""			# -j
opt_projid32bit=""		# -p
opt_get_label=""		# -l
opt_get_uuid=""			# -u
opt_cfgfile=""			# -C
cfgfile=""
opt_set_label=""		# -L
set_label=""
opt_set_uuid=""			# -U
set_uuid=""
opt_rtdev=""			# -r
rtdev=""
repair_tokens=""

USAGE="Usage: xfs_admin [-efjlpuV] [-C cfgfile] [-c 0|1] [-L label] [-O v5_feature] [-r rtdev] [-U uuid] device [logdev]"

while getopts "C:c:efjlL:O:pr:uU:V" c
do
	case $c in
	c)	repair_tokens="$repair_tokens lazycount=$OPTARG"
		require_offline=1
		have_repair=1
		;;
	C)	opt_cfgfile=1
		cfgfile=$OPTARG
		have_db=1
		;;
	e)	opt_extflg=1
		have_db=1
		require_offline=1
		;;
	f)	opt_force=1
		have_db=1
		require_offline=1
		;;
	j)	opt_log2=1
		have_db=1
		require_offline=1
		;;
	l)	opt_get_label=1
		have_db=1
		;;
	L)	opt_set_label=1
		set_label=$OPTARG
		have_db=1
		;;
	O)	repair_tokens="$repair_tokens $OPTARG"
		require_offline=1
		have_repair=1
		;;
	p)	opt_projid32bit=1
		have_db=1
		require_offline=1
		;;
	r)	opt_rtdev=1
		rtdev=$OPTARG
		require_offline=1
		;;
	u)	opt_get_uuid=1
		have_db=1
		;;
	U)	opt_set_uuid=1
		set_uuid=$OPTARG
		have_db=1
		require_offline=1
		;;
	V)	xfs_db -p xfs_admin -V
		status=$?
		exit $status
		;;
	\?)	echo $USAGE 1>&2
		exit 2
		;;
	esac
done
set -- extra "$@"
shift $OPTIND
device=$1
logdev=$2

# We use a bunch of opt_* flags here instead of crafting argument strings
# directly in the getopts loop above. This is because passing such strings
# to eval could cause command injection.
#
# As we cannot use arrays in POSIX, instead we resort to using the positional
# parameters ($@). Before calling any of the xfs_* utilities we reset $@ to an
# empty set with "set --". Then, based on the flags parsed above, we append all
# necessary arguments. This way each argument is passed verbatim, without being
# re-parsed or word-split by the shell.
case $# in
	1|2)
		if mntpt="$(findmnt -t xfs -f -n -o TARGET "$device" 2>/dev/null)"; then
			# filesystem is mounted
			if [ -n "$require_offline" ]; then
				echo "$device: filesystem is mounted."
				exit 2
			fi

			have_io=""
			if [ -n "$opt_get_label" ] || [ -n "$opt_set_label" ] || \
			   [ -n "$opt_get_uuid" ]; then
				have_io=1
			fi

			if [ -n "$opt_cfgfile" ]; then
				xfs_spaceman -p xfs_admin -c "makecfg $cfgfile" "$mntpt"
				res=$?
				test $res -ne 0 && exit $res
				test -n "$have_io" || exit $res
			fi

			if [ -n "$have_io" ]; then
				set --
				[ -n "$opt_get_label" ] && set -- "$@" -r -c label
				[ -n "$opt_set_label" ] && set -- "$@" -c "label -s $set_label"
				[ -n "$opt_get_uuid" ] && set -- "$@" -r -c fsuuid
				exec xfs_io -p xfs_admin "$@" "$mntpt"
			fi
		fi

		# filesystem is not mounted
		if [ -n "$require_online" ]; then
			echo "$device: filesystem is not mounted"
			exit 2
		fi

		if [ -n "$have_db" ]
		then
			set --
			[ -n "$logdev" ] && set -- "$@" -l "$logdev"
			[ -n "$opt_rtdev" ] && set -- "$@" -R "$rtdev"
			[ -n "$opt_cfgfile" ] && set -- "$@" -c "makecfg $cfgfile"
			[ -n "$opt_extflg" ] && set -- "$@" -c "version extflg"
			[ -n "$opt_force" ] && set -- "$@" -f
			[ -n "$opt_log2" ] && set -- "$@" -c "version log2"
			[ -n "$opt_get_label" ] && set -- "$@" -r -c label
			[ -n "$opt_set_label" ] && set -- "$@" -c "label $set_label"
			[ -n "$opt_projid32bit" ] && set -- "$@" -c "version projid32bit"
			[ -n "$opt_get_uuid" ] && set -- "$@" -r -c uuid
			[ -n "$opt_set_uuid" ] && set -- "$@" -c "uuid $set_uuid"
			xfs_db -x -p xfs_admin "$@" "$device"
			status=$?
		fi
		if [ -n "$have_repair" ]
		then
			echo "Running xfs_repair to upgrade filesystem."
			set --
			[ -n "$logdev" ] && set -- "$@" -l "$logdev"
			[ -n "$opt_rtdev" ] && set -- "$@" -r "$rtdev"
			for token in $repair_tokens
			do
				set -- "$@" -c "$token"
			done
			xfs_repair "$@" "$device"
			status=`expr $? + $status`
		fi
		;;
	*)	echo $USAGE 1>&2
		exit 2
		;;
esac
exit $status
