#!/bin/bash # connect: connects to / disconnects from provider # Author: Bernhard Hailer # 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 [ [ [ ...]]]" echo "keywords:" echo " [on], off [] opens/closes connection" echo " off all forced closing" echo " status displays status of all defined remotes" echo " route |default sets route for line" echo " device modem device (e.g. \"ttyS1\")" echo " maxtries maximum number of dial attempts" echo " help displays this message" echo " [ [ [... ]]]: remote(s) to open/close" echo "---------------------------------------------------------------------" echo "You have to edit these files for *each* remote:" echo " $PROV_DIR/" 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 # ----------------------------------------------------------------------------- # 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.