#!/bin/bash

# lsmcode - list microcode level
#
# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2003, 2004

# Maintained by Martin Schwenke <martins@au.ibm.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, 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.
    
# $Id: lsmcode.in,v 1.18 2004/06/16 06:41:11 martins Exp $

PATH="/lib/lsvpd:/sbin:${PATH}:/usr/sbin:/usr/local/sbin" ; export PATH

. "/lib/lsvpd/lsvpd-functions.bash"

shopt -s nullglob

######################################################################

do_setup ()
{
    local d i

    for d in common query lsmcode ; do
	for i in /lib/lsvpd/${d}.d/* ; do
	    . "$i"
	done
    done
}

######################################################################

usage ()
{
    cat <<EOF 1>&2
usage: $0 [ -A | -d name ] [ -r | -c ] [ -D db | -z tgz ]
options: -h      print this usage message
         -c      Do not use menus.  This is the default (no menus implemented).
         -r      Use a tabular format.  Overrides -c.
         -A      Display microcode level for as many devices as possible.
                 This implies -r.
	 -d name Only display microcode level for specified device.
	 -D db   Directory db contains database, instead of default.
	 -z tgz  File tgz contains database archive (overrides -d).
EOF
    exit 1
}



# Options handling
tabular=false
all=false
name=""
tgz=""

options=':'
options="${options}h"
options="${options}c"
options="${options}r"
options="${options}A"
options="${options}d:"
options="${options}D:"
options="${options}z:"
while getopts ${options} opt
do
    case ${opt}
    in
	h ) usage
	    ;;
        c ) : # Default.
            ;;
        r ) tabular=true
            ;;
        A ) all=true
	    tabular=true
            ;;
        d ) name="$OPTARG"
            ;;
        D ) db="$OPTARG"
	    if [ ! -d "$db" ] ; then
		echo "no such directory: \"${db}\"" 1>&2
		echo 1>&2
		usage
	    fi
            ;;
        z ) tgz="$OPTARG"
	    if [ ! -f "$tgz" ] ; then
		echo "no such file: \"${tgz}\"" 1>&2
		echo 1>&2
		usage
	    fi
	    ;;
        \?) echo "unknown option \`${OPTARG}'" 1>&2
	    echo 1>&2
	    usage
            ;;
    esac
done
shift $((${OPTIND} - 1))

[ -n "$1" ] && usage

"$all" && [ -n "$name" ] && usage

######################################################################

nl="
"

######################################################################

render_all ()
{
    local sys_output other_output

    while read vpd ; do
	render_linux_vpd "$vpd"
    done
    
    [ -n "$sys_output" ]   && echo "sys0!${sys_output}"
    [ -n "$other_output" ] && echo -n "$other_output"
}

render_linux_vpd ()
{
    local x="$1"

    local vpd_subdirs
    vpd_subdirs_list_hook "${x%/linux,vpd}"
    local vpd_dir
    for vpd_dir in $vpd_subdirs ; do
	local ax=$(vpd_field_get "$vpd_dir" "AX")
	[ -n "$ax" ] && ax="${ax#/dev/}"
	local ds=$(vpd_field_get "$vpd_dir" "DS")

	if should_render "$ax" "$ds" ; then
	    render_vpd "$vpd_dir" "$ax" "$ds"
	fi
    done
}

is_service_processor ()
{
    local ds="$1"

    [   "$ds" = "Service Processor" -o \
	"$ds" = "Platform Firmware" -o \
	"$ds" = "SP_CARD_" -o \
	"$ds" = "Service Processor Firmware" ]
}

should_render ()
{
    local ax="$1"
    local ds="$2"

    if [ -n "$name" ] ; then
	case "$ax" in
	    ($name) return 0 ;;
	esac
    elif $all || \
	[ "$ds" = "System Firmware" ] || \
	is_service_processor "$ds" ; then
	return 0;
    fi

    return 1;
}    

render_vpd ()
{
    local vpd_dir="$1"
    local ax="$2"
    local ds="$3"

    if [ "$ds" = "System Firmware" ] || \
	is_service_processor "$ds" ; then
	render_sys_vpd "$vpd_dir" "$ax" "$ds"
    else
	render_other_vpd "$vpd_dir" "$ax" "$ds"
    fi
}

render_sys_vpd ()
{
    local vpd_dir="$1"
    local ax="$2"
    local ds="$3"

    local version

    if [ "$ds" = "System Firmware" ] ; then
	version=$(vpd_field_get "$vpd_dir" "MI")
	if [ -n "$version" ] ; then
	    version="${version%% *}"

	    # Get service processor version too.
	    local s v spv
	    s=0
	    local v=$(vpd_field_get "$vpd_dir" "CL" $s)
	    while [ -z "$spv" -a -n "$v" ] ; do
		case "$v" in
		    (PFW\ *) spv="${v#* }" ;;
		    *)  s=$(($s + 1))
			v=$(vpd_field_get "$vpd_dir" "CL" $s)
			;;
		esac
	    done
	    if [ -n "$spv" ] ; then
		if $tabular ; then
		    sys_output="service:${spv}"
		else
		    echo "Version of PFW is ${spv}"
		fi
	    fi
	else
	    version=$(vpd_field_get "$vpd_dir" "RM")
	fi

	if [ -n "$version" ] ; then
	    if $tabular ; then
		local t="system:${version}"
		[ -n "$sys_output" ] && t="${t}|"
		sys_output="${t}${sys_output}"
	    else
		echo "Version of ${ds} is ${version}"
	    fi
	fi
    elif is_service_processor "$ds" ; then
	version=$(vpd_field_get "$vpd_dir" "RM")
	[ -n "$version" ] || \
	    version=$(vpd_field_get "$vpd_dir" "RL")
	if [ -n "$version" ] ; then
	    if $tabular ; then
		local t="service:${version}"
		[ -n "$sys_output" ] && t="|${t}"
		sys_output="${sys_output}${t}"
	    else
		echo "Version of ${ds} is ${version}"
	    fi
	fi
    else
	: "render_sys_vpd: unhandled DS=\"${ds}\""
    fi
}

render_other_vpd ()
{
    local vpd_dir="$1"
    local ax="$2"
    local ds="$3"

    local version

    version=$(vpd_field_get "$vpd_dir" "RM")
    [ -z "$version" ] && \
	version=$(vpd_field_get "$vpd_dir" "RL")
    [ -n "$version" ] || return
    
    local tm=$(vpd_field_get "$vpd_dir" "TM")
    if [ -n "$tm" ] ; then
	local zm=$(vpd_field_get "$vpd_dir" "ZM")
	if [ -n "$zm" ] ; then
	    local zm_hex=$(echo -n $zm | tdump | sed -e 's@ @@'g)
	    version="${tm:0:7}.${zm_hex}.${version}"
	else
	    version="${tm}.${version}"
	fi
    fi

    local label="$ds"
    $tabular && [ -n "$ax" ] && label="$ax"
	
    if $tabular ; then
	other_output="${label}!${version}${nl}${other_output}"
    else
	echo "Version of ${ds} is ${version}"
    fi
}

######################################################################

if [ -n "$tgz" ] ; then
    unpack_device_tree_archive "$tgz"
fi

do_setup
ensure_db

######################################################################

run_dynamic_vpd_hooks

list_linux_vpd |
render_all
