#!/bin/bash
########################################################################
#  File...........: lsqeth
#  Author(s)......: Steffen Thoss	<thoss@de.ibm.com>
#  (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2004
# 
#  History of changes:
# 
#  This shell script displays all QETH devices out of the sys filesystem
#  on one page
#
#  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, 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.
########################################################################
 
#Globael variables
version="1.0"
script_name=${0##*/}                     # name of this script
format=0
ccw_group_format=0			 # display output for ccwgroup input
device=0				 # device name specified by user
device_dir="/sys/bus/ccwgroup/drivers/qeth" 	 # sysfs entry 
interface_dir="/sys/class/net/" 	 # sysfs entry 
qeth_devices=0				 # includes all qeth based devices
device_list=0				 # list of available devices 
QETHCONF="/sbin/qethconf"
# Array for format (/proc/qeth like) output
format_array=( cdev0 cdev1 cdev2 
	       chpid  
	       if_name 
	       card_type  
	       portno  
	       checksumming 
	       priority_queueing 
	       route4 route6 
	       n/a 
	       buffer_count )	 
# Array for normal output (only for sysfs systems)
output_array=( if_name 
	       card_type 
	       cdev0 cdev1 cdev2 
	       chpid 
	       online portname 
	       portno 
	       route4 route6 
	       checksumming 
	       state 
	       priority_queueing 
	       detach_state 
	       fake_ll fake_broadcast 
	       buffer_count 
	       add_hhlen
	       layer2 
	       large_send )
# Array for sysfs values
sysfs_entries=( "sw checksumming" "hw checksumming" "no checksumming"
		"always queue 0" "always queue 1" 
		"always queue 2" "always queue 3" 
		"by precedence" "by type of service"
		"primary router" "secondary router" 
		"primary connector+" "primary connector" 
		"secondary connector+" "secondary connector"
		"multicast router+" "multicast router" )
# Array for ipa entries
ipa_array=0
# Array for vipa entries
vipa_array=0
# Array for parp entries
parp_array=0

#
# what is the kernel version we are on ?
#
kernel_version=`uname -r`		 

if [ "${kernel_version:2:1}" \> 4 ]; then
	kernel_version=2.6
else
	kernel_version=2.4
fi



#---------------------------------------
# --           functions              --
#---------------------------------------

function PrintVersion
{
        echo "$script_name version $version (S390 Tools %S390_TOOLS_VERSION%)" 
	echo "(C) Copyright IBM Corp. 2003-2004"
}


#
# exit script on error and print usage hint
#
function __exit_on_error
{
   echo "Try '$script_name --help' for more information."
   exit 1
}

function __no_such_device
{
   echo "$script_name: $1 no such device"
   exit 1
}

function __no_such_parameter
{
   echo "$script_name: wrong parameter $1"
   __usage
   exit 1
}
#
# function for printing the usage message
#
function __usage
{
    printf '\n%s %s %s\n\n' "Usage:" $script_name "[-p] [-c] [--help] [<INTERFACE>]"
    printf '  %s\n'   "Description:"
    printf '  \t\t%s\n\n' "The shell script list all QETH based networking devices."
    printf '  %s\n' "Parameter:    The following parameters are only available on kernel 2.6"
    printf '  %s\n\n' "              based systems."
    printf '\t\t%s\n' "-p | --proc: list all devices in /proc/qeth format"
    printf '\t\t%s\n\n' "-c | --ccw: list all devices in /etc/ccwgroup.conf format"
    printf '  %s\n\n' "<INTERFACE>:  List only attributes of specified interface."
    printf '\n%s\n' "Report bugs to <linux390@de.ibm.com>"
    printf '\n'
    exit 1
}

#
# check given parameters
#
function __check_input_parameter 
{
if [ "$#" -gt 2 ]; then
    	echo "$script_name: invalid number of parameters specified"
    	__exit_on_error
fi


if [ "$#" -ne 0 ]; then
	case "$1" in
		--help | -h | '?') __usage;;
		-p | --proc 	) format=1
			  if [ "$#" -eq 2 ];then 
				  if [ -d $interface_dir$2 ];then
					device=$2
			  	  else
					__no_such_device $2
				  fi
			  fi;;
		-c | --ccw	) format=2
			  if [ "$#" -eq 2 ];then 
				  if [ -d $interface_dir$2 ];then
					device=$2
			  	  else
					__no_such_device $2
				  fi
			  fi;;
		-v | --version ) PrintVersion
				 exit 1;;
		-*	) __no_such_parameter;;
	 	*	) format=0
			  if [ "$#" -eq 2 ]; then
			 	__no_such_parameter "$1"
			  elif [ "$#" -eq 1 ]; then
			  	if [ -d $interface_dir$1 ];then
					device=$1
			  	else
					__no_such_device $1
			  	fi
			  fi;;
	esac
fi
}



#
# search value in format_array
#

function __array_pos
{
	if [ -z "$1" ];then
                return 100
        fi

	case  "$2" in
		0 | 2 ) temp_array=( ${output_array[@]} );;
		1 ) temp_array=( ${format_array[@]} );;
	esac
	local k=0
	while [ $k -lt ${#temp_array[@]} ];
		do 
			if [ $1 = ${temp_array[$k]} ]; then
				return $k
			fi
			k=$((k+1))
		done
   	return 100
}

#
# format output cat /proc/qeth like
#

function __print_proc_format
{
	local count=0
	local countb=0
	local countc=3

	#
	# include all /proc/qeth entries
	#
	procfs_entries=( "sw" "hw" "no" "always_q_0" "always_q_1"
			 "always_q_2" "always_q_3" "by_prec." "by_ToS"
		         "pri" "sec" "p+c" "p.c" "s+c" "s.c" "mc+" "mc" )

	 for i in 7 8 9 10 
		 do
			 count="${#sysfs_entries[*]}"
			 countb=0
			 while [ "$count" -gt 0 ]
				 do
				     if [ "${sysfs_entries[$countb]}" = "${format_array_print[$i]}" ]; then
					 	format_array_print[$i]=${procfs_entries[$countb]}
				    fi
				    count=$((count-1))
				    countb=$((countb+1))
			  	 done
		 done
	 
	# print device data
	printf '%-27s' "${format_array_print[0]}/${format_array_print[1]}/${format_array_print[2]}"
	for j in 6 11 15 5 7 11 5 5 6 5
		do
			if [ "$countc" -eq 3 ]; then
				printf "%-${j}s" "x${format_array_print[$countc]}"
			else
				if [ "${format_array_print[$countc]}" = '' ]; then
					format_array_print[$countc]='n/a'
				fi
				printf "%-${j}s" "${format_array_print[$countc]}"
			fi
			countc=$((countc+1))
		done
	 printf '\n'
	
}

#
# print new format output 
#
function __print_normal_format
{
	local count=0
	local countc=1
	local countb=0
	local countd=0
	local temp=0
	local m
	local is_in_layer2_list=0
	local rc=0

	countd=${#output_array[@]}
	countd=$((countd-1))

	printf 'Device name\t\t\t: %-20s\n' "${format_array_print[0]}"
	echo '---------------------------------------------'
	
	while [ "$countc" -le "$countd" ]
		do
			if [ -e "$interface_dir$1/device/layer2" ]; then
			 if [ `cat "$interface_dir$1/device/layer2"` = 1 ]; then 
				__layer2_print ${output_array[$countc]} $1
				rc=$?
			 fi
			fi 
			if [ "${format_array_print[$countc]}" != '' ] && [ "$rc" = 0 ]; then
				   printf '\t%-20s\t: %s\n' "${output_array[$countc]}" "${format_array_print[$countc]}"
			fi
			countc=$((countc+1))
		done
	
	for k in  'ipa' 'vipa' 'parp'
		do 
			case "$k" in
				ipa ) temp=( ${ipa_array[@]} )
				      m="ipa";;
				vipa ) temp=( ${vipa_array[@]} )
				      m="vipa";;
				parp ) temp=( ${parp_array[@]} )
				      m="parp";;
			esac
			if [ "$temp" != 0 ];then
				count=0
				countb=0
				while [ "$count" -lt ${#temp[*]} ]
					do
						if [ "$countb" -gt 0 ]; then
							printf '\t\t\t\t: %s\n' "${temp[$count]}"
						else
							printf '\t%-20s\t: %s\n' $m "${temp[$count]}"
						fi
						count=$(($count+1))
						countb=$(($countb+1))
					done
			fi
		done
}

#
# print ccwgroup.conf format
#
function __print_ccwgroup_format
{
	local count=0
	local countb
	local temp=0
	local m

	ccwgroup_entries=( "sw_checksumming" "hw_checksumming" "no_checksumming"
			   "no_prio_queueing:0" "no_prio_queueing:1"
			   "no_prio_queueing:2" "no_prio_queueing:3"
			   "prio_queueing_prec" "prio_queueing_tos"
			   "primary_router" "secondary_router"
			   "primary_connector" "primary_connector"
			   "secondary_connector" "secondary_connector"
			   "multicast_router" "multicast_router" )
	
 	if [ -z "${format_array_print[0]}" ]; then
		return
	fi
	echo "# Definitions for ${format_array_print[1]} interface ${format_array_print[0]}"
	echo "group qeth ${format_array_print[2]} ${format_array_print[3]} ${format_array_print[4]}"
	for i in 7 8 9 10 11 13 15 16 17 18 19 20 
		do
			__check_ccwgroup_value "${format_array_print[$i]}" "${output_array[$i]}"
			if [ "$?" != 0 ]; then
			 count="${#sysfs_entries[*]}"
			 countb=0
			 while [ "$count" -gt 0 ]
				 do
				    if [ "${sysfs_entries[$countb]}" = "${format_array_print[$i]}" ]; then
					 	format_array_print[$i]=${ccwgroup_entries[$countb]}
				    fi
				    count=$((count-1))
				    countb=$((countb+1))
			  	 done
			echo "${output_array[$i]} ${format_array_print[$i]}"
			fi
		done

	if [  -e "$QETHCONF" ]; then
		for k in  'ipa' 'vipa' 'parp'
        	        do
                	        case "$k" in
                        	        ipa ) temp=( ${ipa_array[@]} )
                                	      m="ipa_takeover";;
                          	      vipa ) temp=( ${vipa_array[@]} )
                                	      m="vipa";;
                               	 parp ) temp=( ${parp_array[@]} )
                                	      m="rxip";;
                        	esac
				if [ -n "$temp" ];then
					for j in ${temp[@]}
						do
			 				if [ "$(echo $j | grep ':')" ]; then
								echo "$m/add6 $j"
							else
								echo "$m/add4 $j"
							fi
	
						done
				fi
  	              done
	 fi
	echo ''
}

#
# check for sysfs default values
#
function __check_ccwgroup_value
{
	case "$1" in
		'' ) return 0;;
		0 ) return 0;;
		no ) return 0;;
		'always queue 2' ) return 0;;
		'no portname required' ) return 0;;
		'sw checksumming' ) return 0;;
		'16' ) if [ "$2" = "buffer_count" ]; then
			return 0
		       fi;;
		* ) return 1;;
	esac

}

#
# check if value should be printed because layer2 is enabled
#
function __layer2_print
{
	del_layer2=( route4 route6
		     fake_ll fake_broadcast )

	for l in ${del_layer2[@]}
 		do
			if [ "$1" = "$l" ]; then
				return 1
			fi
		done
	return 0
}
#---------------------------------------
# --           main                   --
#---------------------------------------

__check_input_parameter "$@"

#
# Check if qethconf is installed
#
if [ ! -e "$QETHCONF" ] && [ $format != 1 ]; then
	echo "WARNING: Qethconf is not installed !"
	echo "         No ipa_takeover, vipa or parp entries will be displayed."
	echo ""
fi

#
# get device list
#

if [ $device != 0 ]; then
 	device_list="`ls -ld $interface_dir$device/device/cdev0`"	
	device_list="${device_list##*/}"
else
	device_list="`ls $device_dir | grep [?\.?\.*]`"
fi

device_list_temp="`ls $interface_dir`"

#
# if kernel version 2.4 issue cat /proc/qeth
#
if [ "$kernel_version" =  2.4 ]; then
	if [ $device != 0 ]; then
		cat /proc/qeth | head -2
		cat /proc/qeth | sed -e '1,2D' | grep $device
	else
		cat /proc/qeth
	fi
	exit
fi

if [ $format = 1 ]; then
	echo "devices                    CHPID interface  cardtype       port chksum prio-q'ing rtr4 rtr6 fsz   cnt"
	echo "-------------------------- ----- ---------- -------------- ---- ------ ---------- ---- ---- ----- -----"
fi
#
# list entries for device
#
for k in ${device_list}
	do
	if_name="`cat $device_dir/$k/if_name`"
	if [ -z "$if_name" ]; then
		if_name=0
	fi

	__array_pos "$if_name" "$format"
	rc=$?
	if [ $rc != 100 ];then
		format_array_print[$rc]=${device_temp##*/}
        fi
	for i in `ls $device_dir/$k` 
		do
			# is file a directory (in our case this is happen for the cuu)
			if [ -h $device_dir/$k/$i ]; then
				device_temp="`ls -ld $device_dir/$k/$i`"
				__array_pos "$i" "$format"
				rc=$?
				if [ $rc != 100 ];then
					format_array_print[$rc]="${device_temp##*/}"
				fi
			# call qethconf if ipa/vipa/parp 
			elif [ "$i" = 'ipa_takeover' ] || [ "$i" = 'rxip' ] || [ "$i" = 'vipa' ]; then
				if [ $format = 0 ] || [ $format = 2 ]; then
					if [ "$i" = 'ipa_takeover' ] && [ -e "$QETHCONF" ]; then 
						i='ipa'
						ipa_array=( `$QETHCONF list_all | grep $if_name | grep ^$i | \
						sed -e s/$if_name//g | sed -e s/add//g | sed -e s/[' '$i]//g` )
					elif [ "$i" = 'rxip' ] && [ -e "$QETHCONF" ]; then 
							i='parp'
						parp_array=( `$QETHCONF list_all | grep $if_name | grep ^$i | \
						sed -e s/$if_name//g | sed -e s/add//g | sed -e s/[' '$i]//g` )
					elif [ -e "$QETHCONF" ]; then
						vipa_array=( `$QETHCONF list_all | grep $if_name | grep ^$i | \
						sed -e s/$if_name//g | sed -e s/add//g | sed -e s/[' '$i]//g` )
					fi
				fi
			else
				# show all other entries if the are not n/a
				# and readable
				device_temp="`cat $device_dir/$k/$i 2> /dev/null`"
				if [ "$?"  -eq 0 ]; then
					if [ "$device_temp" = 'n/a' ] && [ "$i" = 'route6' ]; then
						format_array_print[10]="no"
				        elif [ "$device_temp" != 'n/a' ];then
						__array_pos "$i" "$format"
						rc=$?
						if [ $rc != 100 ];then
							format_array_print[$rc]=${device_temp##*/}
						fi
					fi
				fi
			fi
			#
			# There is no entry for buffersize in sysfs
			# therefore n/a
			#
			if [ $format = 1 ]; then
				format_array_print[11]="n/a"
			fi
	done
case "$format" in
	1 ) __print_proc_format;;
	0 ) __print_normal_format $if_name
	    echo '';;
	2 ) __print_ccwgroup_format;;
esac
done
