[Gllug] Unsigned shell arithmetic

Steve Cobrin cobrin at highbury.net
Thu Dec 6 02:41:55 UTC 2001


ok, Bourne Shell and K Shell aren't strictly POSIX conforming, but then I'd be 
suprised if many commands, were. Most commands may imcompletely implement
the POSIX specs, and the remainder probably extend it.

Shell scripters have long known the restrictions of the Bourne Shell, so have relied
on the "expr" command as a handy glue command which extend it. (handy for all sorts
of neat things, do look at the man page, if you haven't alerady done so)

	foo=1
	foo=`expr $foo \* 2`

So the problem remains, what arithmetic is safe to solve your problem, logical ANDs may
not be supported without overflowing, with your version of expr), unfortunately this can be
further complicated by the fact there *may* be several versions of expr on your system.
Usually its /usr/bin/expr, sometimes however it may be a built-in command to your 
implementation of "sh"

blah blah blah

anyway to cut a long and boring story short here's something I wrote a while ago which
should give you some hints...

This obviously worked on Sun's but ..... Hell its a neat bit of code, so here enjoy!

(oh yeah, I know it would be so much simpler in Perl, but its too late for me to consider
thinking that now)

 -- Steve

#! /bin/sh
#
# Title:        calc_broadcast
#
# Author:       cobrin.sbd-e at rx.xerox.com (Steve Cobrin)
# Date:         18-Feb-92
#
# Version:      0.1
#
# Usage:        calc_broadcast ethernet_interface
#
# Purpose:      SunOS 4.x's calculation of broadcast addresses does not
#               work if you want to use an all 1's broadcast address.
#               This command returns the correct broadcast address
#
#               Not required for SunOS 5.x
#
# Bugs:         Not very heavily tested, and only against class A addresses
#
# Description:
#       This uses the values returned by ifconfig command as a
#       basis to calculate broadcast address
#
#       eg.
#
#               # ifconfig -a
#               le0: flags=63<UP,BROADCAST,NOTRAILERS,RUNNING>
#                       inet 13.200.0.53 netmask fffffc00 broadcast 13.200.3.255
#               lo0: flags=49<UP,LOOPBACK,RUNNING>
#                       inet 127.0.0.1 netmask ff000000
#
#       originally derived from a script (below), by David.Henderson at uk.sun.com
#
#
#               #! /bin/csh -f
#               set nmask = 255.255.252.0
#               set ipadd = 13.200.0.10
#               set nm = `echo $nmask | sed 's/\./ /g'`
#               set ip = `echo $ipadd | sed 's/\./ /g'`
#               set bc = ""
#               foreach i (1 2 3 4)
#                       set bc = ($bc `echo "0t$ip[$i]|~0t$nm[$i]&0t255=d" | adb`)
#               end
#               set bcst = `echo $bc | sed 's/ /\./g'`
#               echo "IP = $ipadd, NM = $nmask, BC = $bcst"
#
#       this version derives the ip address and netmask for itself, and is
#       a Bourne shell mostly because I hate C Shell scripts :-)
#
#       I would expect this script to be used via the following line in an 
#       /etc/rc.local
#
#               ifconfig -a netmask + broadcast +
#               ifconfig le0 broadcast `calc_broadcast le0`
#
################################################################################

PATH=/bin:/usr/bin:/usr/etc

CMD=`basename $0`
USAGE="usage: $CMD interface"

error() {
        echo "$@" 2>&1
        exit 1
}

[ $# -eq 1 ] || error $USAGE

interface=$1

ifconfig -a | grep "^${interface}:" | grep -s 'RUNNING' \
|| error "$CMD: interface \"${interface}\" is not running"

# I couldn't think of easy/safe way of getting hold of IP number and
# netmask so this is a bit of a fudge. This will force two variable
# assignments into this scripts scope

eval `ifconfig -a | nawk '
BEGIN           {
        pattern = "^" interface ":"
}
$0 ~ pattern    {
        getline
        inet    = substr($0, match($0, "inet [0-9.]+"), RLENGTH)
        sub(/ /,"=", inet);
        print inet
        netmask = substr($0, match($0, "netmask [a-f0-9]+"), RLENGTH)
        sub(/ /,"=", netmask)
        print netmask
}' interface=$interface`

# if neither of these variables are set all hell can break loose!
: netmask = ${netmask?}, inet = ${inet?}

# this works for class A addressing but not sure about others
netmask=`echo $netmask | sed 's/\(..\)\(..\)\(..\)\(..\)/\1 \2 \3 \4/g'`
inet=`echo $inet | sed 's/\./ /g'`

# I currently assume dotted notation has exactly 4 dots
for i in 1 2 3 4
do
        # bourne shell doesn't have arrays, but this is equivalent
        set $netmask
        eval    nm=\$$i
        set $inet
        eval    ip=\$$i
        # need dummy parameters (- -) to adb to stop it looking for core file
        # 0t says number is decimal, 0x hex
        # We assign to temp variable, since the back ticks help strip 
        # extraneous spaces off result from adb
        temp=`echo "0t${ip}|~0x${nm}&0t255=d" | /bin/adb - -`
        # ensure we put dots in the right place
        broadcast=${broadcast}${broadcast+.}`echo ${temp}`
done
echo $broadcast

exit 0
: done

 
O

-- 
Gllug mailing list  -  Gllug at linux.co.uk
http://list.ftech.net/mailman/listinfo/gllug




More information about the GLLUG mailing list