#!/bin/bash

#-------------------------------------------------------------------------------
# bstream - convert a hex character string to a binary stream
# input: hex character string
#
function bstream()
{
  local stream byte inp="${1// }"

  while [ "${inp}" != "" ]; do
    byte="${inp:0:2}"
    inp="${inp:2}"
    stream="${stream}\x${byte}"
  done

  echo -ne "${stream}"
}

#
# Modify kernel memory in /dev/kmem.
# Addresses can be numeric or symbolic.
# For example:
#
#   > wkmem grimReaper_holdOff 0x28
#   0xf10f9208+0000: 00000028
#

if [ "$#" != "2" -a "$#" != "3" -a "$#" != "4" ]; then
  echo "usage: $0 [ /path/to/mem ] <address|symbol>[+offset] <value> [ <size, default 4> ]"
  exit 1
fi

memdev="/dev/kmem"

if [ "${1#/}" != "${1}" -a -w "${1}" ]; then
   memdev="${1}"
   shift
fi

if [ ! -w "${memdev}" ]; then
   echo "$0: no ${memdev}"
   exit 1
fi

match="$(grep -e '[0-9a-f]* . '${1/+*}'[\s]*' /proc/kallsyms 2>/dev/null)"
if [ "0" = "$?" ]; then
  let addr=0x${match/ *}
else
  let addr=${1/+*}
fi

if [ "$1" != "${1/+*}" ]; then
  let addr+=${1/*+}
fi
hexaddr=$(printf "0x%x" $addr)

value=${2}
let size=${3:-4}
let width=2*${size}

# modifying the kernel memory can be fatal: keep a record of this
logger -p user.warning "wkmem ${memdev} $* --> $hexaddr $value $size"

# bstream twice to preserve endian-ness
bstream $(bstream $(printf "%.${width}x" ${value}) | \
                    od -v -t x${size} | head -n1 | \
                    cut -f2 -d" ") | \
  /ciena/bin/skipper -w ${memdev} $hexaddr ${size} ${size} 2>/dev/null

if [ "$?" = "0" ]; then
  dkmem ${memdev} ${addr} 1 ${size}
fi
