#!/bin/bash
# $Header: /var/local/cvs/debian/ifupdown-scripts-zg2/scripts/ifupdown-scripts-zg2.d/common-functions,v 1.1 2004/09/12 18:00:04 mh Exp $

# set global vars, make statefile existent, and do basic sanity checks

VERBOSE=$IF_VERBOSE
[ -z "$VERBOSE" ] && unset VERBOSE

#set -x

me="$0"
[ $VERBOSE ] && echo "$me $IFACE $MODE"

[ "$METHOD" = "manual" ] || exit 0
[ "$ADDRFAM" = "inet" ] || exit 0

# common functions for interface scripts

#
# misc helper functions
#

error()
{
  echo "$me: ERR: $1" >&2
}

warn()
{
  echo "$me: WARN: $1" >&2
}

abort()
{
  error "$1"
  add_down "abort" "1"
  exit 1
}

msg()
{
  echo "$me: $1" >&2
}

verbose()
{
  [ $VERBOSE ] && echo "$me: $*"
}

cmd()
{
  local RET
  [ $VERBOSE ] && echo "$me: $*"
  SHOW_ERRORS=1
  if [ "$1" == "--no-errors" ]; then
    shift
    SHOW_ERRORS=0
  fi
  eval $1
  RET=$?
  if [ "$RET" -ne 0 -a "$NO_ERRORS" == "1" ]; then
    echo >&2 "$me: $1 returned return value $RET"
  fi
  return $RET
}

#
# functions for handling the state
#

# add_down KEY VAL
add_down()
{
  KEY="$1"
  VAL="$2"
  # add ip commands to down script
  touch $STATEFILE
  chown root $STATEFILE
  chmod 644 $STATEFILE

  verbose "add_down $1 $2"
  echo "$1: $2" >> $STATEFILE
}

get_down()
{
  KEY="$1"
  
  # execute and remove commands from state file
  
  if [ "$STATEFILE" != "`find $STATEFILE -type f -and -user root -and -group root -and -not -perm +0022`" ]; then
    abort "$STATEFILE isn't a plain file, or is writeable by non-root user" >&2
  fi

  # read state file and return commands

  < $STATEFILE sed -n "/^$KEY:/s/^[^\:]*\:[[:space:]]\(.*\)/\1/p"
}

exec_down()
{
  KEY="$1"
  CMD="$2"
  verbose "exec_down $KEY $CMD"
  
  # execute and remove commands from state file
  
  if [ "$STATEFILE" != "`find $STATEFILE -type f -and -user root -and -group root -and -not -perm +0022`" ]; then
    abort "$STATEFILE isn't a plain file, or is writeable by non-root user" >&2
  fi

  # get temp file name
  
  TMPFILE=`mktemp $STATEDIR/$IFACE.state.XXXXXX`
  if [ $? -ne 0 ]; then
    abort "Can't create temp file $TMPFILE. This shouldn't happen" >&2
  fi
  chmod 644 $TMPFILE

  # read state file and execute commands _in_ _reverse_ _order_

  COMMAND="$CMD"
  if [ "$CMD" == "exec" ]; then
    COMMAND=""
  fi
  if [ -n "$CMD" ]; then
    < $STATEFILE sed -n "/^$KEY:/s/^[^\:]*\:[[:space:]]\(.*\)/\1/p" \
    | tac | while read line; do
      verbose "exec_down $COMMAND $line"
      eval "cmd \"$COMMAND $line\""
    done
  fi
  
  # remove commands from STATEFILE
  
  grep -v "^${KEY}:" $STATEFILE > $TMPFILE
  mv -f $TMPFILE $STATEFILE
}

remove_state()
{
  rm -f "/var/lib/ifupdown-scripts-zg2/$IFACE.state"
}

# dev_state_entry DEVICE KEY
dev_state_entry()
{
  local dev key
  dev="$1"; key="$2"

  # check parameter
  local state
  state="$STATEDIR/$dev.state"
  [ ! -f "$state" ] && return 1

  < $state awk -F ':[ \t]*' "/^$key: / "'{ sub("^[^:]*:[ \t]*", ""); print; }'
}

# state_entry KEY
state_entry()
{
  dev_state_entry "$IFACE" "$1"
  return $?
}

# find_if_by_state KEY PATTERN
list_if_by_state()
{
  local key pat
  key="$1"; pat="$2"; shift 2

  [ -z "$key" -o -z "$pat" ] && return 1

  local sfile dev
  if [ $# -eq 0 ]; then
    for sfile in $STATEDIR/*.state; do
      dev="${sfile%.state}"
      dev="${dev##*/}"

      if dev_state_entry "$dev" "$key" | grep -q "$pat"; then
        echo "$dev"
      fi
    done
  else
    for dev; do
      if dev_state_entry "$dev" "$key" | grep -q "$pat"; then
        echo "$dev"
      fi
    done
  fi
}

#
# helper functions for network interfaces
#

# list_ifaces
list_ifaces()
{
  < /proc/net/dev awk -F ':' '/^.*:/ { print $1; }'
}

# if_exists IFACE
if_exists()
{
  for iface in `list_ifaces`; do
    [ "$iface" = "$1" ] && return 0
  done
  return 1
}

# is_if_up IFACE
is_if_up()
{
  local state

  ip link show "$1" \
  | sed -n '/<.*>/s/^[^<]*<\([^>]*+\)>.*$/\1/p' \
  | tr ',' '\n' \
  | while read state; do
    if [ "$state" = "UP" ]; then
      true
      break
    else
      false
    fi
  done
  return $?
}

# get_if_mac IFACE
get_if_mac()
{
  ip link show "$1" 2>/dev/null | awk -F " " '/link\/ether/ { print $2; }'
}

#
# helper functions for vlan management
#

VLAN_CFG=/proc/net/vlan/config

if [ ! -r "$VLAN_CFG" ]; then
  VLAN_SUPPORT=no
  # provide dummy functions
  find_vlan() { return 0; }
  get_vlan_id() { echo 0; }
  is_active_vlan_master() { return 1; }
else
VLAN_SUPPORT=yes

# the real functions
read_vlan_config()
{
  < "$VLAN_CFG" awk -F '|' 'NR>2 { print $1" "$2" "$3; }'
}

#find_vlan MASTER VLANID
find_vlan()
{
  local iface vlanid master
  read_vlan_config \
  | while read iface vlanid master; do
    if [ "$master" = "$1" -a "$vlanid" = "$2" ]; then
      echo "$iface"
      break
    fi
  done
}

# get_vlan_id IFACE
get_vlan_id()
{
  local iface vlanid master
  read_vlan_config \
  | while read iface vlanid master; do
    if [ "$iface" = "$1" ]; then
      echo "$vlanid"
      exit 42
    fi
  done
  [ $? -eq 42 ] || echo 0
  return 0
}

# is_active_vlan_master IFACE
is_active_vlan_master()
{
  local iface vlanid master
  read_vlan_config | (
    while read iface vlanid master; do
      if [ "$master" = "$1" ]; then
        exit 0
      fi
    done
    exit 1
  )
  return $?
}

fi

# init code that should be executed for every script

# physical device defaults to logical
if [ -z "$IF_DEVICE" ]; then
  IF_DEVICE="$IFACE"
  export IF_DEVICE
fi

STATEDIR="/var/lib/ifupdown-scripts-zg2"
STATEFILE="$STATEDIR/$IFACE.state"

if ! [ -e $STATEFILE ]; then 
  touch $STATEFILE
  chown root $STATEFILE
  chmod 644 $STATEFILE
  echo "" > $STATEFILE
fi

if [ "$STATEFILE" != "`find $STATEFILE -type f -and -user root -and -group root -and -not -perm +0022`" ]; then
  abort "$STATEFILE isn't a plain file, or is writeable by non-root user" >&2
fi

# check for abort condition
if [ -f "$STATEFILE" -a "$MODE" = 'start' ]; then
  if grep -q '^abort:' $STATEFILE; then
    exit 0
  fi
fi

# Sanitize VLAN id
IF_VLAN_ID=$[$IF_VLAN_ID+0]

# vi:sw=2

# end of file
