#!/bin/bash
#
# Designed to be called from mhvtl rc script
#
# * Copyright (C) 2005 - 2025 Mark Harvey markh794@gmail.com
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 2 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# TODO:
#	- ensure we are root?
#

DEVICE_CONF="device.conf"
PROG_NAME="$0"
CONFIG_FILE='/etc/mhvtl/mhvtl.conf'
FORCE=''
CREATE_DIR=''
MKTAPE_PATH=''

# print usage info
usage()
{
	echo "Usage: $PROG_NAME: [OPTIONS] -- generate the tape device database"
	echo "where OPTIONS are from:"
	echo "  [-h|--help]            -- print this message and exit"
	echo "  [-H|--home-dir MHVTL_HOME_PATH]"
	echo "                         -- home path [default $MHVTL_HOME_PATH]"
	echo "  [-C|--config-dir DIR]  -- configuration dir [default /etc/mhvtl]"
	echo "  [-f|--force]           -- overwrite files if present"
	echo "  [-c|--create-dir]      -- mkdir MHVTL_HOME_PATH if needed"
	echo "  [-m|--mktape-path MKTAPE] -- pass in dir where mktape lives [default uses PATH]"
}

#
# set_media_type -- set global variable MEDIA_TYPE
#
set_media_type()
{
	if [[ $# -ne 1 ]] ; then
		echo "internal error: wrong number of arguments" 1>&1
		exit 1
	fi
	type=$1

	e0_regex='[A-Z0-9]{6,8}([J])([WXY])$'
	lto_regex='[A-Z0-9]{6,8}([L])([TUVW])$'

	# default to data type
	MEDIA_TYPE="data"

	if [[ $type =~ ^"W" ]]; then
		MEDIA_TYPE="WORM"
	elif [[ $type =~ ^"CLN" ]]; then
		MEDIA_TYPE="clean"
	# Match JW / JX as 'worm' media
	elif [[ $type =~ $e0_regex ]]; then
		MEDIA_TYPE="WORM"
	elif [[ $type =~ $lto_regex ]]; then
		MEDIA_TYPE="WORM"
	fi
}

#
# set_density -- set global variable DENSITY
#
set_density()
{
	if [[ $# -ne 1 ]] ; then
		echo "internal error: wrong number of arguments" 1>&1
		exit 1
	fi
	density=$1

	# I'm sure there is a better method then this...
	# There is.. Thanks to Gavin Barnard.
	regex='[A-Z0-9]{6,8}([SLXTJD])([12345678ABKUVWXYZ])$'
	#regex='[A-Z0-9]{4,6}([SLXTJ])([123456ABWX])[0-9]*$' # for bacula
	DENSITY=UNKNOWN

	if [[ $density =~ $regex ]]; then
		#matches=${#BASH_REMATCH[*]}
		if [ ${BASH_REMATCH[1]} = 'L' ]; then
			if [ ${BASH_REMATCH[2]} = 'T' ]; then
				DENSITY="LTO3"
			elif [ ${BASH_REMATCH[2]} = 'U' ]; then
				DENSITY="LTO4"
			elif [ ${BASH_REMATCH[2]} = 'V' ]; then
				DENSITY="LTO5"
			elif [ ${BASH_REMATCH[2]} = 'W' ]; then
				DENSITY="LTO6"
			else
				DENSITY="LTO${BASH_REMATCH[2]}"
			fi
		elif [ ${BASH_REMATCH[1]} = 'D' ]; then
			if [ ${BASH_REMATCH[2]} = '7' ]; then
				DENSITY="DLT4"
			fi
		elif [ ${BASH_REMATCH[1]} = 'S' ]; then
			if [ ${BASH_REMATCH[2]} = '3' ]; then
				DENSITY="SDLT600"
			elif [ ${BASH_REMATCH[2]} = '2' ]; then
				DENSITY="SDLT320"
			elif [ ${BASH_REMATCH[2]} = '1' ]; then
				DENSITY="SDLT220"
			else
				DENSITY="SDLT"
			fi
		elif [ ${BASH_REMATCH[1]} = 'J' ]; then
			if [ ${BASH_REMATCH[2]} = 'A' ]; then
				DENSITY="J1A"
			elif [ ${BASH_REMATCH[2]} = 'B' ]; then
				DENSITY="E05"
			elif [ ${BASH_REMATCH[2]} = 'W' ]; then
				DENSITY="E05"
			elif [ ${BASH_REMATCH[2]} = 'X' ]; then
				DENSITY="E05"
			elif [ ${BASH_REMATCH[2]} = 'Y' ]; then
				DENSITY="E07"
			elif [ ${BASH_REMATCH[2]} = 'K' ]; then
				DENSITY="E07"
			fi
		elif [ ${BASH_REMATCH[1]} = 'X' ]; then
			DENSITY="AIT${BASH_REMATCH[2]}"
		elif [ ${BASH_REMATCH[1]} = 'T' ]; then
			if [ ${BASH_REMATCH[2]} = 'Z' ]; then
				DENSITY="9840A"
			elif [ ${BASH_REMATCH[2]} = 'Y' ]; then
				DENSITY="9840B"
			elif [ ${BASH_REMATCH[2]} = 'X' ]; then
				DENSITY="9840C"
			elif [ ${BASH_REMATCH[2]} = 'W' ]; then
				DENSITY="9840D"
			elif [ ${BASH_REMATCH[2]} = 'V' ]; then
				DENSITY="9940A"
			elif [ ${BASH_REMATCH[2]} = 'U' ]; then
				DENSITY="9940B"
			else
				DENSITY="T10K${BASH_REMATCH[2]}"
			fi
		fi
	fi
}

#
# find_mktape -- set MKTAPE_PATH to path to 'mktape' or exit if not found
#
find_mktape_path()
{
	if [[ $# -gt 0 ]] ; then
		echo "internal error: $0: no argument expected" 1>&2
		exit 1
	fi
	if [[ -s "$MKTAPE_PATH" ]] ; then
		# make sure supplied path works
		if [[ ! -x $MKTAPE_PATH/mktape ]] ; then
			echo "error: no 'mktape' at specified path: $MKTAPE_PATh" 1>&2
			exit 1
		fi
	else
		# we must find mktape in our PATH
		OIFS="$IFS"
		IFS=':'
		for d in $PATH; do
			if [[ -x $d/mktape ]] ; then
				MKTAPE_PATH="$d"
				IFS="$OIFS"
				return
			fi
		done
		echo "error: no 'mktape' found in PATH" 1>&2
		exit 1
	fi
}

##################################################################
## Main starts here...
##################################################################

TEMP=$(getopt -o 'hH:C:fcm:' --long 'help,home-dir:,config-dir:,force,create-dir,mktape-path:' -n "$PROG_NAME" -- "$@")
if [[ $? -ne 0 ]] ; then
	usage
	exit 1
fi
eval set - "$TEMP"
unset TEMP

while true; do
	case "$1" in
	'-h'|'--help')
		usage
		exit 0
		;;
	'-H'|'--home-dir')
		PARAM_MHVTL_HOME_PATH="$2"
		shift 2
		continue
		;;
	'-C'|'--config-dir')
		MHVTL_CONFIG_PATH="$2"
		shift 2
		continue
		;;
	'-f'|'--force')
		FORCE='1'
		shift
		continue
		;;
	'-c'|'--create-dir')
		CREATE_DIR='1'
		shift
		continue
		;;
	'-m'|'--mktape-path')
		MKTAPE_PATH="$2"
		shift 2
		continue
		;;
	'--')
		shift
		break
		;;
	*)
		echo "internal error: unknown arg: $1" 1>&2
		exit 1
	esac
done

# should be no more arguments
if [[ $# -gt 0 ]] ; then
	echo "error: too many arguments"
	usage
	exit 1
fi

if [[ ! -z "$MHVTL_CONFIG_PATH" ]] ; then
	CONFIG_FILE="$MHVTL_CONFIG_PATH/mhvtl.conf"
fi
if [[ ! -r $CONFIG_FILE ]] ; then
	echo "error: config file not found: $CONFIG_FILE" 1>&2
	exit 1
fi

# get default capacity
. $CONFIG_FILE

# Set default capacity to 500M if not defined.
CAPACITY=${CAPACITY:=500}

# override home dir if passed in by user
if [[ ! -z "$PARAM_MHVTL_HOME_PATH" ]] ; then
	MHVTL_HOME_PATH=$PARAM_MHVTL_HOME_PATH
fi

if [[ ! -d $MHVTL_HOME_PATH ]] ; then
	if [[ -z "$CREATE_DIR" ]] ; then
		echo "error: no such directory: $MHVTL_HOME_PATH" 1>&2
		usage
		exit 1
	fi
	echo "warning: creating directory: $MHVTL_HOME_PATH" 1>&2
	mkdir -p $MHVTL_HOME_PATH
	chmod 755 $MHVTL_HOME_PATH
fi

# Create any media specified in library config.
umask 022

if [[ ! -r $MHVTL_CONFIG_PATH/$DEVICE_CONF ]] ; then
	echo "error: not found: $MHVTL_CONFIG_PATH/$DEVICE_CONF" 1>&2
	exit 1
fi

# make sure we can find mktape
find_mktape_path

# for LIBCONTENTS in $MHVTL_CONFIG_PATH/library_contents.*
echo '===>' "Reading from $MHVTL_CONFIG_PATH/$DEVICE_CONF file to find Tape Libraries and Drives ..."
for LIBID in $(awk '/Library:/ {print $2}' $MHVTL_CONFIG_PATH/$DEVICE_CONF) ; do
	LIBCONTENTS="$MHVTL_CONFIG_PATH/library_contents.$LIBID"

	if [[ ! -r $LIBCONTENTS ]] ; then
		echo "error: not found: $LIBCONTENTS" 1>&2
		echo "have you ran 'generate_library_contents'?" 1>&2
		exit 1
	fi
	echo '===>' "Scanning for 'Slot' entries in $LIBCONTENTS ..."
	for a in $(awk '/^Slot/ {print $3}' <$LIBCONTENTS|sort -u) ; do
		if [[ -d $MHVTL_HOME_PATH/$a ]] ; then
			if [[ -z "$FORCE" ]] ; then
				echo "Directory already exists: $MHVTL_HOME_PATH/$a: skipping"
				continue
			fi
			echo "warning: removing entry: $MHVTL_HOME_PATH/$a"
			rm -rf $MHVTL_HOME_PATH/$a
		fi
		echo '===>' "Creating entry: $MHVTL_HOME_PATH/$a ..."
		set_density $a
		set_media_type $a
		# pass in "-D[0-9]" for debugging, "-v" for verbosity
		$MKTAPE_PATH/mktape -v -D5 -l $LIBID -s $CAPACITY -t $MEDIA_TYPE -m $a -d $DENSITY \
			-C $MHVTL_CONFIG_PATH -H $MHVTL_HOME_PATH
		res=$?
		[[ $res -eq 0 ]] || exit 1
	done
done
