head 1.13; access; symbols; locks alexis:1.13; strict; comment @# @; 1.13 date 96.09.26.12.55.40; author alexis; state Exp; branches; next 1.12; 1.12 date 96.05.11.18.47.59; author alexis; state Exp; branches; next 1.11; 1.11 date 96.05.05.13.27.32; author alexis; state Exp; branches; next 1.10; 1.10 date 96.04.18.14.09.41; author alexis; state Exp; branches; next 1.9; 1.9 date 96.04.15.09.43.09; author alexis; state Exp; branches; next 1.8; 1.8 date 95.10.17.12.21.44; author alexis; state Exp; branches; next 1.7; 1.7 date 95.10.15.20.33.48; author alexis; state Exp; branches; next 1.6; 1.6 date 95.10.14.14.41.15; author alexis; state Exp; branches; next 1.5; 1.5 date 95.10.13.19.18.25; author alexis; state Exp; branches; next 1.4; 1.4 date 95.10.13.17.40.40; author alexis; state Exp; branches; next 1.3; 1.3 date 95.10.10.16.24.46; author root; state Exp; branches; next 1.2; 1.2 date 95.10.10.16.17.58; author root; state Exp; branches; next 1.1; 1.1 date 95.10.10.16.15.48; author root; state Exp; branches; next ; desc @INTERNET CONNECT PROGRAM @ 1.13 log @Changed idle timeout to 5 minutes on Demon's side. Turned tailing of logs off by default. @ text @#!/bin/sh VERSION="$Id: incp,v 1.12 1996/05/11 18:47:59 alexis Exp alexis $" PROGNAME=`basename $0` # This specifies the default level of message logging. 3 means you will # recieve informational messages, warnings and errors; 2 means just # the latter two; 1 means just the last one and 0 means no messages will # be displayed. Higher numbers will give debugging information. This number # may be overridden by using the "-v" or "-d" options on the command line. DFLT_INCP_DEBUG_LEVEL=2 # This is the default idle timeout in seconds. Again it can be overridden # by using the "-i" option on the command line. DFLT_INCP_IDLE_TIME_OUT=180 # This says that line quality should be checked and the internet provider # possibly redialled if the quality is bad DFLT_INCP_CHECK_QUALITY=true # This says that news should be got by default. It can be overridden with # the "-n" or "-nn" options on the command line. DFLT_INCP_GET_NEWS=true # This says that by default everyone should be "walled" when the connection # goes up or down. It can be overridden with the "-w" or "-nw" options on # the command line. DFLT_INCP_DO_WALL=true # This says that that the serial port should be set to 115200 and the modem # should be initialised as according to Demon. It may range from 1 to 4 and # may be modified with the '-cm' (connect mode) option. DFLT_INCP_CONN_MODE=1 # This says that the default behaviour is not to tail /var/adm/message log. DFLT_INCP_TAIL_LOG=false # Locations of various programs # This should work, but doesn't - pppd has a bug whereby it gets stuck in # sleep commands. #PPP_DAEMON=/usr/sbin/pppd PPP_DAEMON=/usr/local/lib/ppp/pppd-experimental SLIP_IDLE=/usr/local/lib/ppp/slip_idle XMITNEWS=/usr/local/lib/nntp/xmitnews NEWSRUNNING=/usr/lib/newsbin/input/newsrunning NEWSRUN=/usr/lib/newsbin/input/newsrun NNMASTER=/usr/lib/nn/nnmaster NNTP_DIR=/usr/local/lib/nntp SLURP=/usr/local/lib/nntp/slurp CHAT=/usr/sbin/chat MESSAGES_FILE=/var/adm/messages ############################ LEAVE THESE ALONE ############################### CONFIG_FILE=/usr/local/lib/ppp/$PROGNAME.cfg VERSION=`echo $VERSION | cut -d' ' -f3` CHAT_FILE=/tmp/$PROGNAME.$$.chat CONNECTED_FILE=/tmp/$PROGNAME.conn TERMREQ_FILE=/tmp/$PROGNAME.term LOCK_FILE=/var/run/$PROGNAME.pid ############################################################################### # # USEFUL FUNCTIONS FOR REPORTING MESSAGES # ############################################################################### usage() { # There are addition second parameters: upprocess, downprocess. But these # are not intended to be used by the user. { echo "Usage: $PROGNAME -V" echo " $PROGNAME [ -d dbglvl | -v ] [ -i timeout | -ni ] [ -n | -nn ] [ -q | -nq ] host connect" echo " $PROGNAME host disconnect" } >&2 exit 1 } error() { echo "$PROGNAME: ERROR: $1" exit 2 } internal() { echo "$PROGNAME: INTERNAL ERROR: $1" exit 3 } verbose() { [ $INCP_DEBUG_LEVEL -ge 3 ] && echo "$PROGNAME: INFO: $1" } debug() { [ $1 -le $INCP_DEBUG_LEVEL ] && echo "$PROGNAME[$$]: DEBUG[$1] $2" } incp_log() { logger -p local0.info -t "$PROGNAME[$INCP_MASTER_PID]" "$1" } ############################################################################### # # ENTRY POINT - PARSE OPTIONS, DO CHECKS AND CALL USER-DEFINED FUNCTION # ############################################################################### main() { # Set some things from the environment otherwise set their values from # defaults defined at the top of this file [ $INCP_DEBUG_LEVEL ] || INCP_DEBUG_LEVEL=$DFLT_INCP_DEBUG_LEVEL [ $INCP_CONN_MODE ] || INCP_CONN_MODE=$DFLT_INCP_CONN_MODE [ $INCP_TAIL_LOG ] || INCP_TAIL_LOG=$DFLT_INCP_TAIL_LOG [ $INCP_GET_NEWS ] || INCP_GET_NEWS=$DFLT_INCP_GET_NEWS [ $INCP_DO_WALL ] || INCP_DO_WALL=$DFLT_INCP_DO_WALL [ $INCP_CHECK_QUALITY ] || INCP_CHECK_QUALITY=$DFLT_INCP_CHECK_QUALITY [ $INCP_IDLE_TIME_OUT ] || INCP_IDLE_TIME_OUT=$DFLT_INCP_IDLE_TIME_OUT [ $INCP_MASTER_PID ] || INCP_MASTER_PID=$$ # process options - over-ruling any previous definition while [ "X$1" != X ]; do case "$1" in -d) [ "X$2" = X ] && usage INCP_DEBUG_LEVEL=$2 shift ;; -cm) [ "X$2" = X ] && usage INCP_CONN_MODE=$2 shift case $INCP_CONN_MODE in [1-4]) ;; *) usage ;; esac ;; -l) INCP_TAIL_LOG=true ;; -nl) INCP_TAIL_LOG=false ;; -v) INCP_DEBUG_LEVEL=3 ;; -i) [ "X$2" = X ] && usage INCP_IDLE_TIME_OUT=$2 shift ;; -ni) INCP_IDLE_TIME_OUT=0 ;; -q) INCP_CHECK_QUALITY=true ;; -nq) INCP_CHECK_QUALITY=false ;; -n) INCP_GET_NEWS=true ;; -nn) INCP_GET_NEWS=false ;; -w) INCP_DO_WALL=true ;; -nw) INCP_DO_WALL=false ;; -V) echo "$PROGNAME version $VERSION" exit 0 ;; -*) usage ;; *) break ;; esac shift done # Put some of the things we've just set into the environment so that # when this program (called with connect or disconnect) calls this # this program a second time (with upprocess or downprocess) then # certain values are accessible export INCP_IDLE_TIME_OUT export INCP_DEBUG_LEVEL export INCP_GET_NEWS export INCP_DO_WALL export INCP_CHECK_QUALITY export INCP_CONN_MODE export INCP_TAIL_LOG export INCP_MASTER_PID # Parse the first of the two required parameters [ "X$2" = X -o "X$3" != X ] && usage debug 50 "main: checking required parameters" case "$1" in demon) ;; *) error "valid hosts are: demon, you gave $1" ;; esac INCP_HOST=$1 export INCP_HOST # Parse the second of the two required parameters case "$2" in connect) lock_connect $INCP_HOST ;; disconnect|upprocess|downprocess) ;; *) usage ;; esac # Read in the config file and check it defines everything if [ -r $CONFIG_FILE ]; then . $CONFIG_FILE else error "can't read $CONFIG_FILE" fi [ $CONFIGURED = false ] && configure_me [ "X$PHONE_NUMBER" = X ] && configure_me [ "X$LOGIN" = X ] && configure_me [ "X$PASSWORD" = X ] && configure_me [ "X$PORT" = X ] && configure_me [ "X$NETMASK" = X ] && configure_me [ "X$NNTP_SERVER" = X ] && configure_me [ "X$TESTHOSTS" = X ] && configure_me [ "X$TESTLOSSES" = X ] && configure_me # Some non-host-specific sanity checks [ -x $PPP_DAEMON ] || error "can't execute $PPP_DAEMON" [ -x $SLIP_IDLE ] || error "can't execute $SLIP_IDLE" [ -x $SLURP ] || error "can't execute $SLURP" [ -x $NEWSRUNNING ] || error "can't execute $NEWSRUNNING" # Now call the function based on the two parameters, e.g. if we had # parameters "demon" and "connect", we know call "demon_connect" debug 20 "main: will call $1_$2" incp_log "$PROGNAME $VERSION started. ($INCP_HOST,$2,$LOGNAME)" $1_$2 incp_log "Exit ($INCP_HOST,$2,$LOGNAME)" case "$2" in connect) unlock_connect $INCP_HOST ;; esac exit } ############################################################################### # # USER DEFINED FUNCTIONS: HOST_CONNECT, HOST_DISCONNECT, HOST_UPPROCESS # HOST_DOWNPROCESS # ############################################################################### # # This function specifies how to establish the connection to a host # So if you want to connect to Microsoft Network then you will need to # write a function "msn_connect". This one details how to connect to # Demon. # demon_connect() { debug 50 "demon_connect: starting ..." [ $INCP_TAIL_LOG = true ] && tail -f $MESSAGES_FILE & # Flush outgoing newsbatches before we start if required to do so if [ $INCP_GET_NEWS = true ]; then enable_other_news_processing flush_batches_to_database_and_possibly_queue_out fi debug 50 "demon_connect: creating the chat script ..." # The chat script is now stored here and written out to a tmp file. This # means all the config stuff can be kept in this one file. OLDUMASK=`umask` umask 077 cat > $CHAT_FILE <> $CHAT_FILE <> $CHAT_FILE <> $CHAT_FILE < $TERMREQ_FILE kill_connected_pppd kill_stubborn_pppd } demon_upprocess() { debug 5 "demon_upprocess: starting ..." incp_log "CONNECTED" debug 5 "demon_upprocess: if quality check" if [ $INCP_CHECK_QUALITY != true ]; then debug 5 "demon_upprocess: no quality check" incp_log "no quality check" elif ! check_stable; then debug 5 "demon_upprocess: quality checked and unacceptable" kill_connected_pppd incp_log "DISCONNECTED - unacceptable quality" incp_log "Exit." exit fi debug 5 "demon_upprocess: quality not checked or acceptable" incp_log "acceptable quality" > $CONNECTED_FILE say_internet_up kick_send_mail_queue start_idle_timeout [ $INCP_GET_NEWS = true ] && { disable_other_news_processing send_out_queued_news get_new_news enable_other_news_processing flush_batches_to_database_and_possibly_queue_out update_nn_db } verbose "Connection processing completed." } demon_downprocess() { # The point of this "if" is that if the connection was up but not # a good quality link then we would have retried and never announced # to the users that the the connection was up. As such if connection # was bad then we also do not want to tell them it's gone down since # they never knew it was up. verbose "Disconnecting ..." if [ -f $CONNECTED_FILE ]; then say_internet_down fi } flush_batches_to_database_and_possibly_queue_out() { verbose "Flushing news buffers ..." su - news -c $NEWSRUN } kill_stubborn_pppd() { debug 5 "kill_stubborn_pppd: sof, getting pppd pid" PPPD_PID=`ps -ax | grep pppd | grep -v grep | sed 's/^ *\([0-9][0-9]*\) .*/\1/'` debug 5 "kill_stubborn_pppd: pppd pid is: $PPPD_PID" if [ "$PPPD_PID" ]; then debug 5 "kill_stubborn_pppd: killing running pppd with normal sig" kill $PPPD_PID debug 5 "kill_stubborn_pppd: about to repeatedly check if still running" for I in 1 2 3 4 5 6 7 8 9 10; do debug 5 "kill_stubborn_pppd: checking if pppd process directory still exists (check $I)" sleep 1 [ -d /proc/$PPPD_PID ] || { debug 5 "kill_stubborn_pppd: pppd exited"; return; } debug 5 "kill_stubborn_pppd: must be still running" done debug 5 "kill_stubborn_pppd: now getting process list again" PPPD_PID=`ps -ax | grep pppd | grep -v grep | sed 's/^ *\([0-9][0-9]*\) .*/\1/'` debug 5 "kill_stubborn_pppd: pppd pid is: $PPPD_PID" debug 5 "kill_stubborn_pppd: about to check if pppd process still running" if [ "$PPPD_PID" ]; then debug 5 "kill_stubborn_pppd: killing running pppd with -9" kill -9 $PPPD_PID fi debug 5 "kill_stubborn_pppd: fi 1" fi debug 5 "kill_stubborn_pppd: fi 2" } kill_connected_pppd() { if [ ! -f /var/run/ppp0.pid ]; then debug 5 "kill_connected_pppd: no pid file - connection probably wasn't established" return fi PPPD_PID=`cat /var/run/ppp0.pid` debug 5 "kill_connected_pppd: checking if pppd process dir exists" if [ ! -d /proc/$PPPD_PID ]; then debug 5 "kill_connected_pppd: stale pid file - connection probably wasn't established" return fi debug 5 "kill_connected_pppd: pid file valid - connection probably established - pppd will be terminated" kill $PPPD_PID } lock_connect() { # The complicated art of managing lock files! debug 5 "lock_connect: creating a private key" echo $$ > $LOCK_FILE.$$ debug 5 "lock_connect: sliding key into lock" ln $LOCK_FILE.$$ $LOCK_FILE 2>/dev/null && { rm $LOCK_FILE.$$; return; } debug 5 "lock_connect: another key in lock already" LOCKINGPID=`cat $LOCK_FILE` [ "X$LOCKINGPID" = X ] && error "corrupt lock file encountered" debug 5 "lock_connect: checking if locking pid proc dir exists" [ -d /proc/$LOCKINGPID ] && error "program already running!" rm -f $LOCK_FILE verbose "Removed stale lock file." ln $LOCK_FILE.$$ $LOCK_FILE && { rm $LOCK_FILE.$$; return; } error "still cannot lock after removing stale lock file" } unlock_connect() { rm -f $LOCK_FILE } check_stable() { verbose "Connected. Testing quality ..." incp_log "Testing quality" #debug 15 "check_stable: waiting 15 seconds for connection to settle" #sleep 15 # Now calculate the packet loss to a very close host MAXLOSSES="$TESTLOSSES" for HOST in $TESTHOSTS; do set $MAXLOSSES MAXLOSS=$1 shift MAXLOSSES="$*" debug 15 "check_stable: pinging $HOST, acceptable loss is $MAXLOSS%" #sleep 10 LOSS=`ping -c 10 -n -q $HOST | sed -n 's/^.*ed, \([0-9]*\)% pa.*$/\1/p'` if [ $LOSS -gt $MAXLOSS ]; then verbose "$LOSS% packet loss to $HOST, disconnecting ..." incp_log "$LOSS% packet loss to $HOST" return 1 fi done return 0 } say_internet_up() { verbose "Connected." [ $INCP_DO_WALL = true ] && wall < /dev/null 2>&1 & else incp_log "No idle timeout" verbose "No idle timeout set." fi } send_out_queued_news() { # Send news verbose "Dispatching outbound news ..." if [ $INCP_DEBUG_LEVEL -ge 3 ]; then su - news -c "$XMITNEWS -d -h $NNTP_SERVER -f /var/spool/news/out.going/$NNTP_SERVER/togo" else su - news -c "$XMITNEWS -d -h $NNTP_SERVER -f /var/spool/news/out.going/$NNTP_SERVER/togo" > /dev/null 2>&1 fi } fix_kacky_slurp_file() { [ `wc -l < $NNTP_DIR/slurp.$NNTP_SERVER` -gt 1 ] && { cp $NNTP_DIR/slurp.$NNTP_SERVER $NNTP_DIR/slurp.$NNTP_SERVER.bak head -1 $NNTP_DIR/slurp.$NNTP_SERVER.bak > $NNTP_DIR/slurp.$NNTP_SERVER verbose "Fixed corrupt slurp timestamp file." } } disable_other_news_processing() { su - news -c "$NEWSRUNNING off" } get_new_news() { fix_kacky_slurp_file # Get news SLURP_RC=1 verbose "Downloading news batches ..." while [ $SLURP_RC != 0 ]; do if [ $INCP_DEBUG_LEVEL -ge 3 ]; then su - news -c "$SLURP -d $NNTP_SERVER" else su - news -c "$SLURP -d $NNTP_SERVER" > /dev/null 2>&1 fi SLURP_RC=$? [ $SLURP_RC != 0 ] && debug 5 "get_new_news: failed - retrying" sleep 1 done } enable_other_news_processing() { su - news -c "$NEWSRUNNING on" } update_nn_db() { # Update the NN database verbose "Updating nn fast access database ..." su - news -c $NNMASTER } say_internet_down() { [ $INCP_DO_WALL = true ] && wall < /dev/null 2>&1 & d452 1 a452 1 incp_log "WARNING: No idle timeout" d461 1 a461 1 if [ $DEBUG_LEVEL -ge 3 ]; then d490 1 a490 1 if [ $DEBUG_LEVEL -ge 3 ]; then d515 1 a515 1 [ $DO_WALL = true ] && wall <