#!/bin/sh
###############################################################################
# Tape hotplug agent for Linux 2.4 kernels
#
# Copyright (c) 2002 IBM Development Germany, Boeblingen
#
# the GNU Public License applies
# 
# Author: Stefan Bader <Stefan.Bader@de.ibm.com>, 2002
#
# History:
#   2002-10-14 Stefan Bader <Stefan.Bader@de.ibm.com>
#              Fixed remove char case (missing statement)
#   2002-10-01 Stefan Bader <Stefan.Bader@de.ibm.com>
#              Created inital version
#
# Generated by:
#   /usr/src/linux/drivers/s390/char/tape.c
#
# Evionment:
#   ACTION    ::= add | remove
#   DEVNO     ::= <4 digit hex number>
#   MAJOR     ::= <dec major number>
#   MINOR     ::= <dec minor number>
#   INTERFACE ::= char | block
###############################################################################
: ${ACTION?Bad invocation: \$ACTION is not set}
: ${DEVNO?Bad invocation: \$DEVNO is not set}
: ${MAJOR?Bad invocation: \$MAJOR is not set}
: ${MINOR?Bad invocation: \$MINOR is not set}
: ${INTERFACE?Bad invocation: \$INTERFACE is not set}

# Convert to lowercase (just in case)
DEVNO=$(echo $DEVNO | tr A-F a-f)

cd /etc/hotplug
. hotplug.functions

mesg "$ACTION $DEVNO $MAJOR $MINOR $INTERFACE"

if test -r tape.permissions; then
	. tape.permissions
else
	mesg "Tape permission handling not found"
	exit 1
fi

#==============================================================================
# To preserve the script from doing anything real, call it with
# CONDOM=echo
: ${CONDOM=}
# To try things on an alternate location set ROOTDIR to a different base
#: ${ROOTDIR=}
: ${ROOTDIR=}
# Abort on error or unset variables:
set -o errexit
set -o nounset
#==============================================================================

#------------------------------------------------------------------------------
# Environment: none
# Parameters : $1 : abort message
#              $2 : optional return code
#------------------------------------------------------------------------------
# Abort handling
abort() {
	if test "$#" -lt 2; then
		RC=1
	else
		RC=$2
	fi

	mesg "$1 RC($RC)"
	exit $RC
}

#------------------------------------------------------------------------------
# Environment: INTERFACE
#              MINOR
# Parameters:  none
#
# Prints:      Tape number [0..127]
# Returns:     0
#------------------------------------------------------------------------------
tape_number() {
	if test "$INTERFACE" = "block"; then
		echo $MINOR
	else
		echo "$(($MINOR / 2))"
	fi
	return 0
}

#------------------------------------------------------------------------------
# Environment: ROOTDIR
#              DEVNO
#              CONDOM
# Parameters:  $1 : variable part of the link name
#              $2 : variable part of the target node name
#
# Creates a symbolic link to access the tape device by devno
#
# Prints:      nothing
# Returns:     0 on success, otherwise 1
#------------------------------------------------------------------------------
create_symlink() {
	LINK=$ROOTDIR/dev/tape/$DEVNO/$1
	TARGET=../../../$2$(tape_number)

	# Do not create link if devfs compatibility mode is not started
	if test ! -d $ROOTDIR/dev/tape; then
		return 0
	fi

	if test ! -d $(dirname $LINK); then
		$CONDOM mkdir -p $(dirname $LINK)                  || return 1
	fi
	mesg "Creating symlink $LINK -> $TARGET"
	$CONDOM rm -f $LINK                                        || return 1
	$CONDOM ln -s $TARGET $LINK                                || return 1

	return 0
}

#------------------------------------------------------------------------------
# Environment: MAJOR
#              MINOR
# Parameters:  $1 : node name
#              $2 : device type (b|c)
#
# Tests whether the node already exists with the correct type, major and minor
#
# Prints:      nothing
# Returns:     0 if the node is ok, otherwise 1
#------------------------------------------------------------------------------
verify_node() {
	NAME="$1"
	TYPE="$2"
	RC=1

	if test -$TYPE "$NAME"; then
		MAJMIN=$(ls -l "$NAME"|awk '{print $5 $6}')

		if test "$(echo $MAJMIN|cut -d, -f1)" = "$MAJOR"; then
			if test "$(echo $MAJMIN|cut -d, -f2)" = "$MINOR"; then
				RC=0
			fi
		fi
	fi

	return $RC
}

#------------------------------------------------------------------------------
# Environment: ROOTDIR
#              INTERFACE
#              CONDOM
#              MAJOR
#              MINOR
#              OWNER
#              PERMISSIONS
# Parameters:  $1 : device type (b|c)
#              $2 : variable part of the device node name ([brn]tibm)
#
# Creates a device node for the tpae device (if it doesn't exist) and sets
# the permissions.
#
# Prints:      nothing
# Returns:     0 on success, otherwise 1
#------------------------------------------------------------------------------
create_node() {
	TYPE="$1"
	NAME="$ROOTDIR/dev/$2$(tape_number)"

	# FIXME: This would currently recreate the device node if it isn't
	#        right even if devfs compatibility isn't enabled. Should
	#        ownership and permissions be preserved in that case???
	if ! verify_node $NAME $TYPE; then
		mesg "Creating devicenode $NAME"
		$CONDOM rm -f "$NAME"                              || return 1
		$CONDOM mknod "$NAME" $TYPE $MAJOR $MINOR          || return 1
	fi

	# We only want to change ownership and permissions if devfs compa-
	# tibility is enabled.
	tape_permissions $DEVNO
	if test "$OWNER" != "" && test -d $ROOTDIR/dev/tape; then
		$CONDOM chown $OWNER "$NAME"                       || return 1

		if test "$PERMISSIONS" != ""; then
			$CONDOM chmod "$PERMISSIONS" "$NAME"       || return 1
		fi
	fi

	return 0
}

#------------------------------------------------------------------------------
# Main
#------------------------------------------------------------------------------
case "$ACTION" in
	add)
		case "$INTERFACE" in
			block)
				create_node    b btibm             || return 1
				create_symlink block/disc btibm    || return 1
				;;
			char)
				create_node    c ntibm             || return 1
				create_symlink char/norewind ntibm || return 1
				MINOR=$(($MINOR + 1))
				create_node    c rtibm             || return 1
				create_symlink char/rewind rtibm   || return 1
				;;
			*)
				abort "Unknown interface type <$INTERFACE>"
				;;
		esac
		;;
	remove)
		case "$INTERFACE" in
			char)
				$CONDOM rm -rf $ROOTDIR/dev/tape/$DEVNO/char
				if test -d $ROOTDIR/dev/tape; then
					$CONDOM rm -f \
					$ROOTDIR/dev/[nr]tibm$(tape_number)
				fi
				;;
			block)
				$CONDOM rm -rf $ROOTDIR/dev/tape/$DEVNO/block
				if test -d $ROOTDIR/dev/tape; then
					$CONDOM \
					rm -f $ROOTDIR/dev/btibm$(tape_number)
				fi
				;;
			*)
				abort "Unknown interface type <$INTERFACE>"
				;;
		esac

		if test "$(ls $ROOTDIR/dev/tape/$DEVNO)" = ""; then
			$CONDOM rmdir $ROOTDIR/dev/tape/$DEVNO
		fi
		;;
	*)
		abort "$(basename $0): $ACTION event not supported"
		;;
esac

exit 0

