isdn4linux-web/leafsite/scripts/connect

750 lines
16 KiB
Bash

#!/bin/bash
# connect: connects to / disconnects from provider
# Author: Bernhard Hailer <Bernhard.Hailer@lrz.uni-muenchen.de>
# Version: 1.0 (24-Feb-97)
# License: GNU General Public License V2 ("GPL")
# command line arguments
ARG=$1
if [ -n "$2" ]
then
shift
ARGV=$*
else
ARGV=""
fi
# Search paths
PATH=/sbin:/usr/sbin:/bin:/usr/bin
# Files (it is save to leave these untouched!)
BASE=/usr/lib/connect/base # basic definitions
PROV_DIR=/usr/lib/connect/providers # config files, once per provider
STATUS=/var/lib/connect/status # status file
STATUS_BAK=/var/lib/connect/status.bak # status file backup
IF_FILE=/var/lib/connect/interface # pppd interface - see /etc/ppp/ip-up!
PPP_PID_DIR=/var/run # PPP pid file/Linux: /var/run/pppx.pid
# Global variables
. $BASE
declare -i i # i: standard counter
NEW_CONN=false
declare -i RETURN # i: standard return value
RETURN=0
# wait before testing line (isdn4linux)
declare -i I4L_WAIT
I4L_WAIT=10
# wait before testing line (modems)
declare -i MODEM_WAIT
MODEM_WAIT=40
# process ID for lock file
declare -i PID
declare -i LCK_PID
PID=$$
# -----------------------------------------------------------------------------
# Functions
Fatal_Error()
# beeps, prints the "Usage:" message, removes lock file and exits (1)
{
echo -e "\a\nUsage:"
echo "connect <keyword> [<remote1> [<remote2> [<remote3> ...]]]"
echo "keywords:"
echo " [on], off [<remote(s)>] opens/closes connection"
echo " off all forced closing"
echo " status displays status of all defined remotes"
echo " route <IP>|default sets route for line"
echo " device <device> modem device (e.g. \"ttyS1\")"
echo " maxtries <tries|0> maximum number of dial attempts"
echo " help displays this message"
echo "<remote1> [<remote2> [<remote3> [... ]]]: remote(s) to open/close"
echo "---------------------------------------------------------------------"
echo "You have to edit these files for *each* remote:"
echo " $PROV_DIR/<remote>"
echo "$BASE: Default remote definitions"
echo "Remotes must not be named like keywords! Avoid the following names:"
echo " on, off, all, status, route, device, maxtries, help"
rm /var/lock/LCK..connect 2>/dev/null
exit 1
}
# -----------------------------------------------------------------------------
# command line parsing
OP_MODE=""
ROUTE=""
declare -i MAX_TRIES
MAX_TRIES=0
until [ -z "$ARG" ]
do
case $ARG in
on)
if [ -z "$OP_MODE" ]
then
OP_MODE=on
else
echo -e "\nOperation mode (on, off, status, help) set twice in command line."
Fatal_Error
fi
;;
off)
if [ -z "$OP_MODE" ]
then
OP_MODE=off
else
echo -e "\nOperation mode (on, off, status, help) set twice in command line."
Fatal_Error
fi
;;
status)
if [ -z "$OP_MODE" ]
then
OP_MODE=status
else
echo -e "\nOperation mode (on, off, status, help) set twice in command line."
Fatal_Error
fi
;;
help)
if [ -z "$OP_MODE" ]
then
OP_MODE=help
else
echo -e "\nOperation mode (on, off, status, help) set twice in command line."
Fatal_Error
fi
;;
route)
if [ -z "$ROUTE" ]
then
if [ -n "$ARGV" ]
then
set `echo $ARGV`
ARG=$1
shift
ARGV=$*
ROUTE="$ARG"
if [ `cat $STATUS | grep "$ROUTE" >/dev/null` ]
then
echo -e "\nRoute named in command line is already used!"
Fatal_Error
fi
else
echo -e "\nRoute command set without route in command line!"
Fatal_Error
fi
else
echo -e "\nRoute set twice in command line!"
Fatal_Error
fi
;;
device)
if [ -z "$DEVICE" ]
then
if [ -n "$ARGV" ]
then
set `echo $ARGV`
ARG=$1
shift
ARGV=$*
DEVICE="$ARG"
if [ `cat $STATUS | grep "$DEVICE" >/dev/null` ]
then
echo -e "\nDevice named in command line already used!"
Fatal_Error
fi
else
echo -e "\nDevice command set without device name in command line!"
Fatal_Error
fi
else
echo -e "\nDevice set twice in command line"
Fatal_Error
fi
;;
maxtries)
if [ $MAX_TRIES -eq 0 ]
then
if [ -n "$ARGV" ]
then
set `echo $ARGV`
ARG=$1
shift
ARGV=$*
MAX_TRIES=$ARG
else
echo -e "\nmaxtries command set without account of tries in command line!"
Fatal_Error
fi
else
echo -e "\nmaxtries set twice in command line!"
Fatal_Error
fi
;;
*)
REMOTE_LIST="$REMOTE_LIST $ARG"
;;
esac
# This construct is built against a bash bug.
if [ -z "$ARGV" ]
then
ARG=""
else
set `echo $ARGV`
ARG=$1
shift
ARGV=$*
fi
done
# -----------------------------------------------------------------------------
# now fill up some variables, if empty.
# is there any remote defined in command line / $DEFAULT_REMOTES?
if [ -z "$REMOTE_LIST" ]
then
REMOTE_LIST=$DEFAULT_REMOTES # defined in $BASE
if [ -z "$REMOTE_LIST" ]
then
echo -e "\a\nNo DEFAULT_REMOTES defined in $BASE! Exiting."
exit 1
fi
fi
# Operation mode. If none, then assume "on".
if [ -z "$OP_MODE" ]
then OP_MODE=on
fi
## tty device.
#if [ -z "$DEVICE" ]
#then
# DEVICE=$DEFAULT_DEVICE
#fi
# Maximum number of dial tries.
if [ $MAX_TRIES -eq 0 ]
then
MAX_TRIES=$DEFAULT_MAX_TRIES
if [ $MAX_TRIES -eq 0 ]
then
echo "DEFAULT_MAX_TRIES not set in $BASE!"
Fatal_Error
fi
fi
# Any route set?
if [ -z "$ROUTE" ]
then
ROUTE=default
fi
# -----------------------------------------------------------------------------
# More functions
Connect_Dial()
# Dials out, automatically chooses i4l or modem.
# Needs $INTERFACE, $IP_ADDRESS and $ROUTE, and $DEVICE if modem.
{
BUFFER=$DEVICE
. $PROV_DIR/$REMOTE
if [ -n "$BUFFER" ]
then
DEVICE=$BUFFER
else
if [ -z "$DEVICE" ]
then
DEVICE="$DEFAULT_DEVICE"
fi
fi
case $INTERFACE in
ippp*)
# ISDN4Linux syncPPP connection
ifconfig $INTERFACE up
isdnctrl dial $INTERFACE
echo "Sleeping $I4L_WAIT seconds for PPP handshaking..."
sleep $I4L_WAIT
;;
*)
# Modem asyncPPP connection
pppd connect "chat $CHAT_SCRIPT" file $OPTIONS_FILE /dev/$DEVICE &
# the interface name was saved now by /etc/ppp/ip-up in IF_FILE.
sleep 1
echo "Sleeping $MODEM_WAIT seconds for establishing connection..."
sleep $MODEM_WAIT
if [ -e $IF_FILE ]
then
read INTERFACE <$IF_FILE
else
INTERFACE="-----"
fi
;;
esac
if [ "$INTERFACE" != "-----" ]
then
if [ "$ROUTE" = "default" ]
then
route add $ROUTE $INTERFACE
else
route add $IP_ADDRESS
route add $ROUTE gw $IP_ADDRESS
fi
fi
}
Connect_Hangup()
# Hangs up device $INTERFACE. Automatically chooses i4l or modem.
# Needs $INTERFACE, $DEVICE, $REMOTE, $IP_ADDRESS and $ROUTE.
{
case $INTERFACE in
ippp*)
# ISDN4Linux hangup
echo -e "$REMOTE: \c"
isdnctrl hangup $INTERFACE
ifconfig $INTERFACE down
;;
*)
# Modem hangup
if [ -e $PPP_PID_DIR/$INTERFACE.pid ]
then
kill -HUP `cat $PPP_PID_DIR/$INTERFACE.pid`
echo "$REMOTE: $INTERFACE hung up"
else
echo "$REMOTE: $INTERFACE not connected"
fi
;;
esac
if [ "$ROUTE" != "default" ]
then
route del $IP_ADDRESS 2>/dev/null
fi
route del $ROUTE 2>/dev/null
rm $IF_FILE 2>/dev/null
}
Line_OK()
# Checks whether channel really is connected.
{
case $INTERFACE in
ippp*) # test i4l connection
# check whether physical connection is established:
echo -e "Physical connection... \c"
# Therefore get phone number used:
PHONE=`cat $PROV_DIR/$REMOTE | grep "PHONE="`
# Now we have a string like PHONE=08912345 - use it as command to set PHONE
export $PHONE;
if [ -n "`imontty | grep $PHONE | grep outgoing`" ]
then
echo -e "established; PPP negotiation... \c"
# check whether PPP negotiation was successful:
set `ping -qc3 -i1 $IP_ADDRESS 2>/dev/null | grep transmitted`
let RETURN=$4
if [ $RETURN -gt 0 ]
then
echo "succeeded."
else
echo "failed!"
fi
else
let RETURN=0
echo "not established!"
fi
;;
*) # test modem connection
echo -e "Physical connection... \c"
if [ "$INTERFACE" = "-----" ] # Modem connect failed
then
let RETURN=0
echo "not established!"
else
echo -e "established; PPP negotiation... \c"
set `ping -qc3 -i1 $IP_ADDRESS 2>/dev/null | grep transmitted`
let RETURN=$4
if [ $RETURN -gt 0 ]
then
echo "succeeded."
else
echo "failed!"
fi
fi
;;
esac
}
Rd_Status()
# Reads status file. Sets INTERFACE, DEVICE, IP_ADDRESS, TIMES_OPEN and ROUTE;
# needs $REMOTE.
# If you want to change the format, don't forget the init file (rc.connect)!
{
set `cat $STATUS | grep $REMOTE`
if [ -z "$2" ]
then
echo -e "$PROV_DIR/$REMOTE does not exist! Check also $BASE!"
Fatal_Error
fi
INTERFACE=$2
ACT_DEVICE=$3
IP_ADDRESS=$4
TIMES_OPEN=$5
ACT_ROUTE=$6
}
Wr_Status()
# Actualizes status file. Needs $REMOTE, $IP_ADDRESS and actualized
# $TIMES_OPEN. Also needs actual $ACT_ROUTE.
# If you want to change the format, don't forget the init file (rc.connect)!
{
# actualize $REMOTE line and save it as first line
echo "$REMOTE $INTERFACE $DEVICE $IP_ADDRESS $TIMES_OPEN $ACT_ROUTE" \
>$STATUS_BAK
# save all lines in status file but not the $REMOTE one.
cat $STATUS | grep -v $REMOTE >>$STATUS_BAK
# restore status file.
mv $STATUS_BAK $STATUS
}
# =============================================================================
# Main script
# -----------------------------------------------------------------------------
# Did rc.connect run?
if [ ! -e $STATUS ]
then
echo -e "$STATUS missing - did you run rc.connect? Exiting."
rm /var/lock/LCK..connect
exit 1
fi
# -----------------------------------------------------------------------------
# Lock script (against errors in status file)
let i=3
while [ $i -gt 0 ]
do
let i-=1
if [ -e /var/lock/LCK..connect ]
then
read LCK_PID </var/lock/LCK..connect
set `ps -a | grep $LCK_PID`
if [ $LCK_PID -eq $1 ]
then
echo "Script is locked - trying again in 30 seconds."
sleep 30
else
echo "Unclean shutdown - removing lock file /var/lock/LCK..connect"
rm /var/lock/LCK..connect
break
fi
else
break
fi
done
# also locked after three attempts?
if [ -e /var/lock/LCK..connect ]
then
echo -e "\aSorry - could not unlock for three times. Try later!"
exit 1
fi
# create lock file
echo $PID >/var/lock/LCK..connect
# -----------------------------------------------------------------------------
# Main loop.
case $OP_MODE in
on)
# check whether one of the remotes seem already open
BUFFER=$REMOTE_LIST
until [ -z "$BUFFER" ]
do
set `echo $BUFFER`
REMOTE=$1
shift
BUFFER=$*
Rd_Status
if [ $TIMES_OPEN -gt 0 ]
then
ALREADY_OPEN=TRUE
break
fi
done
# Now main loop: open channel, if necessary, and check it.
until [ $MAX_TRIES -eq 0 ]
do
if [ "$ALREADY_OPEN" = "TRUE" ]
then
ALREADY_OPEN=FALSE
else
# rotation of devices
set `echo $REMOTE_LIST`
REMOTE=$1
shift
REMOTE_LIST="$* $REMOTE"
# Pick REMOTE's data from status file.
Rd_Status
fi
# Found channel now. Already open?
case $TIMES_OPEN in
0)
echo -e "\nCalling $REMOTE"
Connect_Dial
NEW_CONN=true # this is to detect whether line was closed by HUPTIMEOUT.
;;
1)
echo "Line may be used already by an application - checking..."
;;
*)
echo "Line may be used already by $TIMES_OPEN applications - checking..."
;;
esac
# check channel.
echo "Line open - checking..."
Line_OK
if [ $RETURN -gt 0 ]
then
# channel is ok
if [ $TIMES_OPEN -eq 0 ]
then
ACT_ROUTE=$ROUTE
else
echo "Parameters set in command line will be ignored"
Rd_Status
DEVICE=$ACT_DEVICE
fi
if [ -n "`echo $INTERFACE | grep "ippp"`" ]
then
DEVICE="-----"
fi
let TIMES_OPEN+=1
Wr_Status
echo -e "8-) Line is ok - have fun!\n"
break
else
Connect_Hangup
if [ "$NEW_CONN" = "false" ]
then
# channel is closed - try to reopen
echo ":-| Hmm, no. Trying to rebuild..."
Connect_Dial
echo "Line open - checking..."
Line_OK
if [ $RETURN -gt 0 ]
then
#channel now open
if [ $TIMES_OPEN -eq 0 ]
then
ACT_ROUTE=$ROUTE
else
echo "Parameters set in command line will be ignored"
Rd_Status
DEVICE=$ACT_DEVICE
fi
if [ `echo $INTERFACE | grep "ippp"` ]
then
DEVICE="-----"
fi
let TIMES_OPEN+=1
Wr_Status
echo -e "8-) Line is ok - have fun!\n"
break
fi
fi
#channel could not be opened
if [ $MAX_TRIES -eq 1 ]
then
let TIMES_OPEN=0
ACT_ROUTE=""
if ! [ `echo $INTERFACE | grep "ippp"` ]
then
INTERFACE="-----"
fi
DEVICE="-----"
Wr_Status
echo -e ":-[ Sorry, all lines are down. Bad luck... Try later!\n"
rm /var/lock/LCK..connect
exit 1
fi
fi
echo ":-( This line is down. Trying next one."
let MAX_TRIES-=1
done
;;
# -----------------------------------------------------------------------------
off)
# parse device string
until [ -z "$REMOTE_LIST" ]
do
set `echo $REMOTE_LIST`
REMOTE=$1
shift
REMOTE_LIST=$*
case $REMOTE in
all)
# force closing of all channels and clear status file
for FILE in $PROV_DIR/*
do
REMOTE=`basename $FILE`
Rd_Status
TIMES_OPEN=0
ACT_ROUTE=""
Connect_Hangup
if ! [ `echo $INTERFACE | grep "ippp"` ]
then
INTERFACE="-----"
fi
DEVICE="-----"
Wr_Status
done
;;
*)
# Pick REMOTE's data from status file.
Rd_Status
if [ -z "$INTERFACE" ]
then
echo "$PROV_DIR/$REMOTE does not exist! Check also $BASE!"
echo "To force closing all channels use \"connect off all\"."
Fatal_Error
fi
# close $INTERFACE, if no other application running
case $TIMES_OPEN in
0)
echo "$REMOTE already closed! To force closing use \"connect off all\""
;;
1)
echo "Last application - hanging up $REMOTE ($INTERFACE)."
Connect_Hangup
let TIMES_OPEN=0
ACT_ROUTE=""
if [ -z "`echo $INTERFACE | grep "ippp"`" ]
then
INTERFACE="-----"
fi
DEVICE="-----"
Wr_Status
;;
2)
echo "One more application running - $REMOTE ($INTERFACE) left open."
let TIMES_OPEN-=1
ACT_ROUTE=$ROUTE
DEVICE=$ACT_DEVICE
Wr_Status
;;
*)
let TIMES_OPEN-=1
echo "$TIMES_OPEN more applications running - $REMOTE ($INTERFACE) left open."
ACT_ROUTE=$ROUTE
DEVICE=$ACT_DEVICE
Wr_Status
;;
esac
;;
esac
done
;;
# -----------------------------------------------------------------------------
status)
for INTERFACE in $PROV_DIR/*
do
REMOTE=`basename $INTERFACE`
Rd_Status
echo -e "$REMOTE ($INTERFACE): \c"
case $TIMES_OPEN in
0)
echo "closed";;
1)
echo "used by one application";;
*)
echo "used by $TIMES_OPEN applications";;
esac
done
;;
# -----------------------------------------------------------------------------
help)
Fatal_Error # I know this is dirty...
;;
# -----------------------------------------------------------------------------
*)
Fatal_Error
;;
esac
# -----------------------------------------------------------------------------
# unlock script
rm /var/lock/LCK..connect
# End of script.