#!/bin/sh
#==============================================================================
# (C) Copyright IBM Corp. 2003-2005    All Rights Reserved.
#
# lstape ($Revision: 1.8.4.1 $)
#
# Script to generate /proc/tapedevices output for kernels beyond 2.4.
# (Designed to work with 2.4 as well.)
#
# Author(s): S. Bader <shbader@de.ibm.com>
#
# This file is part of s390-tools
#
# s390-tools 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.
#
# s390-tools 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 s390-tools; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#==============================================================================
CMD=$(basename $0)

function RequireArgument() {
	if [ $2 -eq 1 ]; then
		echo "The $1 option requires an argument" >&2
	else
		echo "The $1 option requires $2 arguments" >&2
	fi
}

function PrintUsage() {
	cat <<-EOD | cut -c2-
	:Usage: $1 [<options>]
	:
	:	<options>
	:		-h|--help
	:			Print this help text.
	:		-t|--type <list of device types>
	:			Limit output to the given devices. The list
	:			consists of device types seperated by ','.
	:			(e.g. -t 3480,3490)
	:		--online|--offline
	:			Show only devices that are either online or
	:			offline (only one option is allowed).
	:		-s|--shortid
	:			Show only devices on channel subsytem 0 with
	:			subchannel set 0 and remove the leading '0.0.'
	:			from the displayed bus id.
	:		--version
	:			Display the tools and command version of
	:			$1.
	EOD
}

function PrintVersion()
{
	local TVER=$(echo '$Revision: 1.8.4.1 $'|awk '{print $2}')

	cat <<-EOD
	%S390_TOOLS_VERSION% ($CMD version $TVER)
	(C) Copyright IBM Corp. 2003-2004
	EOD
}
DEVLIST="3480,3490,3590"
FILTERONLINE=false
FILTEROFFLINE=false
SHORTID=false
FLSEP=""
while [ $# -ne 0 ]; do
	case $1 in
		-h|--help)
			PrintUsage
			exit 1
			;;
		-t|--type)
			if [ $# -lt 2 ]; then
				RequireArgument $1 1
				exit 1
			fi
			shift
			DEVLIST="$1"
			;;
		--online)
			if $FILTEROFFLINE; then
				echo -n "Option --online and --offline " >&2
				echo "are exclusive" >&2
				exit 1
			fi
			FILTERONLINE=true
			;;
		--offline)
			if $FILTERONLINE; then
				echo -n "Option --online and --offline " >&2
				echo "are exclusive" >&2
				exit 1
			fi
			FILTEROFFLINE=true
			;;
		-s|--shortid)
			SHORTID=true
			;;
		--version)
			PrintVersion
			exit 0
			;;
		-*|--*)
			echo "Invalid option $1" >&2
			exit 1
			;;
		*)
			FILTERLIST="$FILTERLIST$FLSEP$1"
			FLSEP=","
			;;
	esac
	shift
done

function SysfsCreateList() {
	echo -n "TapeNo  BusID      CuType/Model DevType/Model   "
	echo    "BlkSize State   Op      MedState"
	(
		find $1/bus/ccw/drivers/tape_34xx -type l \
			-printf '%f\n' 2>/dev/null
		find $1/bus/ccw/drivers/tape_3590 -type l \
			-printf '%f\n' 2>/dev/null
	) | awk '
		BEGIN{
			medium_state_str[0] = "UNKNOWN "
			medium_state_str[1] = "LOADED  "
			medium_state_str[2] = "UNLOADED"

			split("'$DEVLIST'", A, ",")
			for(i = 1; i in A; i++) {
				devlist[A[i]] = 1
			}
		}
		function Read(file) {
			value = ""
			getline value <file
			close(file)
			return value
		}
		{
			bus_id = tolower($1)
			devdir = "'$1'/bus/ccw/devices/" bus_id

			devtype      = Read(devdir "/devtype")
			split(devtype, A, "/")
			if (!(A[1] in devlist))
				next

			cutype       = Read(devdir "/cutype")
			online = Read(devdir "/online")
			majmin = Read(devdir "/non-rewinding/dev")
			if (majmin != "") {
				split(majmin, A, ":")
				first_minor = A[2]
			} else {
				first_minor = Read(devdir "/first_minor")
			}
			if(first_minor == "")
				next
			medium_state = Read(devdir "/medium_state")
			state        = Read(devdir "/state")
			operation    = Read(devdir "/operation")
			blocksize    = Read(devdir "/blocksize")

			printf("%-7.7s %-10.10s %-12.12s %-13.13s   %-7.7s ",
				(online==0) ? "N/A" : first_minor / 2,
				bus_id,
				tolower(cutype),
				tolower(devtype),
				(online==0) ? "N/A" : \
					((blocksize == 0) ? "auto" : blocksize))
			printf("%-7.7s %-7.7s %-8.8s\n",
				(online==0) ? "OFFLINE" : state,
				(online==0) ? "---" : operation,
				(online==0) ? "N/A" : \
					medium_state_str[medium_state])
		}
	' | sort 
}

case $(uname -r|cut -d. -f1-2) in
	1.*|2.[012])
		echo "Not supported!" >&2
		exit 1
		;;
	2.3|2.4)
		SYSFS=false
		;;
	*)
		SYSFS=true
		if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
			echo "WARNING: no sysfs support. Using proc!" >&2
			SYSFS=false
		fi
		SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
		if [ "$SYSFSDIR" = "" ]; then
			echo "WARNING: sysfs not mounted. Using proc!" >&2
			SYSFS=false
		fi
		if ! $SYSFS; then
			echo -n "WARNING: proc interface will not find offline"
			echo " devices on kernel $(uname -r|cut -d. -f1-2)."
			echo
		fi
		;;
esac

if $SYSFS; then
	SysfsCreateList $SYSFSDIR
else
	if [ ! -r /proc/tapedevices ]; then
		echo "ERROR: neither proc nor sysfs interface found!" >&2
		exit 1
	fi
	cat /proc/tapedevices
fi | awk -v LIST="$FILTERLIST" '
	function PrintEntry(e) {
		if("'$SHORTID'" == "true") {
			p1 = substr(e, 1, 8)
			p2 = substr(e, 9, 10)
			p3 = substr(e, 19)

			if(substr(p2, 1, 4) == "0.0.")
				print p1 substr(p2, 5) "    " p3
		} else {
			print e
		}
	}
	BEGIN{
		if(LIST != "")
			split(LIST, A, ",")
	}
	"'$FILTERONLINE'" == "true" && /OFFLINE/{
		next
	}
	"'$FILTEROFFLINE'" == "true" && !/OFFLINE/{
		next
	}
	LIST != ""{
		for(i in A) {
			if(index($2, A[i]) > 0) {
				PrintEntry($0)
				next
			}
		}
		next
	}
	{
		PrintEntry($0)
	}
'

exit 0

