#!/bin/bash
# SpeedTouch user-mode driver hotplug script, version 8
#
# This script is called by /etc/hotplug/usb.agent when the SpeedTouch modem is
# (re)connected to the computer. It should be put in /etc/hotplug/usb, along
# with the speedtouch.usermap file.
#
# This script has been developed and tested on Slackware, but should work on
# other distributions as well. Please contact me if this is not the case: tell
# me what is different on your distribution, so that I can correct the script
# and make it more generic.
#
# This script is (c) 2003, Adrien Beau. This version is being released to the
# general public under the GNU General Public License (GPL), version 2. You can
# read it at http://www.gnu.org/licenses/gpl.txt.
#
# This script, and the speedtouch.usermap file, can be downloaded from
# http://adrien.beau.free.fr/slackware/hotplug/
#
# AB   Adrien Beau, <adrien.beau@free.fr>
#
# 2003-04-29  AB   Minimalistic version. DSL starts on computer startup, this
#                  will do for now. Reconnections do not work, so this will
#                  have to be vastly improved, as soon as possible.
# 2003-05-08  AB   Rough version. A remover is created when then modem is
#                  connected, so reconnections work fine, now.
# 2003-06-10  AB   The new version of hotplug breaks this script. Added
#                  debugging messages. Something is wrong with coldplugging.
#                  Whatever I try, two connections happen upon startup, two
#                  instances of this script are run in parallel, which wreaks
#                  havoc.
# 2003-06-11  AB   Major cleanup. Added lockfile mechanism. Hotplug and
#                  coldplug work fine.
# 2003-06-12  AB   Minor cleanup. Be smarter about killing pppd, so that other
#                  connections (e.g. plain old modems) stay up when we
#                  reconnect.
# 2003-06-13  AB   The script takes a lot of time to run, so booting takes a
#                  lot of time. The last part of this script is now being run
#                  in the background, as a separate substarter. Argh! It still
#                  takes some time. What is the USB driver waiting for? Why is
#                  it only waiting upon bootup?
# 2003-06-22  AB   The new version of Linux breaks this script. It runs it
#                  three times in a row, which strangely makes expr return the
#                  wrong exit status. Wrote the offending line another way,
#                  which works. Since the remover is also run three times in a
#                  row, added the lockfile mechanism to the remover. Argh! This
#                  is a tricky timing issue, so even the rewritten line
#                  sometimes breaks. Plus, sometimes all the tests for the
#                  existence of the lockfile are done at the same time, so all
#                  three instances create the lockfile anyway.
# 2003-06-27  AB   That should do it: added the pid to the lockfile, so that an
#                  instance knows if another instance overwrote the lockfile.
#                  Create the lockfile as early as possible after the test for
#                  the existence of the lockfile. Mmm, everything seems ok now,
#                  except for the bootup delay. Argh! The remover is erased
#                  upon bootup, yet another problem to solve (this has the same
#                  cause as the bootup delay).
# 2003-07-06  AB   Initial release to the general public. No other change, so
#                  this is still version 8.


### This script has six settings that you might want to alter. ###

# Don't read first, don't pollute the logs ("-s" means "skip").
# Use the second line for the few SpeedTouch modems that don't work with "-s".
READ_FIRST="-s"
#READ_FIRST=""

# Location of the logfile. Use /dev/null if the logfile bothers you.
#LOGFILE="/dev/null"
LOGFILE="/var/log/speedtouch"

# Under which hierarchy modem_run and the firmware file are located.
PREFIX="/usr/local"
#PREFIX="/usr"

# If a lockfile is older than 60 seconds, ignore it.
# Note that modem_run can take up to 30 seconds to run. Really.
MAX_LOCK_AGE=60

# Name of the file in /etc/ppp/peers that contains the pppd settings for this
# DSL connection. The default is /etc/ppp/peers/adsl.
PEER="adsl"

LOCKFILE="/var/lock/speedtouch"


### You should not need to edit anything below this line. ###

function get_relevant_pppd_pids() {
   ps -eo pid,command | while read pid command; do
      if [ "$command" == "pppd call $PEER" ]; then
         echo -n "$pid "
      fi
   done
}

function log() {
   echo "`date '+%F %T'` starter-$$: $1" >> $LOGFILE
}

function create_lockfile() {
   log "Creating lockfile"
   echo "$currenttime $$" > $LOCKFILE
}

function read_lockfile() {
   unset timestamp pid
   read timestamp pid < $LOCKFILE
   # clean junk, be secure
   timestamp=`expr "$timestamp" : "\([0-9]*\)"`
   pid=`expr "$pid" : "\([0-9]*\)"`
}

currenttime=`date '+%s'`

SUBSTARTER="/tmp/`basename $0`.$currenttime-$$.sh"

# Acquire the lock. If the lock is old, go ahead anyway. Else, abort.
# Note that several instances of this script will be run in parallel,
# so some precautions have to be taken for this locking mechanism to
# merely work.
log "Trying to acquire the lock"

if [ ! -e $LOCKFILE ]; then
   create_lockfile
else
   if [ -f $LOCKFILE -a -r $LOCKFILE ]; then
      read_lockfile
      if [ "$timestamp" ]; then
         # First line fails, second line doesn't (most of the time).
         # Understand why, then please tell me why.
#        if expr $currenttime '-' $timestamp '<' $MAX_LOCK_AGE; then
         if [ `expr $currenttime '-' $timestamp` -lt $MAX_LOCK_AGE ]; then
            log "Found a recent lock, exiting"
            exit 0
         else
            log "Found a stale lock"
         fi
      else
         log "Corrupted lockfile"
      fi
   else
      log "Weird lockfile"
   fi

   log "Removing lockfile"
   rm -f $LOCKFILE
   if [ $? -gt 0 ]; then
      log "Cannot remove lockfile, exiting"
      exit 1
   fi
   create_lockfile
fi

sleep 2
log "Checking lockfile"
read_lockfile
if [ ! "$pid" ]; then
   log "Inexistant or corrupted lockfile, exiting"
   exit 1
fi
if [ "$pid" -ne $$ ]; then
   log "Process $pid overwrote lockfile, exiting"
   exit 1
fi


# Create /var/run/usb if it doesn't exist.
if [ ! -d /var/run/usb ]; then
   log "Creating /var/run/usb"
   mkdir -p /var/run/usb
   chmod 0755 /var/run/usb
fi


# Write the remover. Make it executable.
log "Writing remover"

cat << EOF > $REMOVER
#!/bin/bash
# SpeedTouch user-mode-driver remover
# Generated by /etc/hotplug/usb/speedtouch


function get_relevant_pppd_pids() {
   ps -eo pid,command | while read pid command; do
      if [ "\$command" == "pppd call $PEER" ]; then
         echo -n "\$pid "
      fi
   done
}

function log() {
   echo "\`date '+%F %T'\` remover-$$-\$\$: \$1" >> $LOGFILE
}

function create_lockfile() {
   log "Creating lockfile"
   echo "\$currenttime \$\$" > $LOCKFILE
}

function read_lockfile() {
   unset timestamp pid
   read timestamp pid < $LOCKFILE
   # clean junk, be secure
   timestamp=\`expr "\$timestamp" : "\\([0-9]*\\)"\`
   pid=\`expr "\$pid" : "\\([0-9]*\\)"\`
}

currenttime=\`date '+%s'\`


# Acquire the lock. If the lock is old, go ahead anyway. Else, abort.
# Note that several instances of this script will be run in parallel,
# so some precautions have to be taken for this locking mechanism to
# merely work.
log "Trying to acquire the lock"

if [ ! -e $LOCKFILE ]; then
   create_lockfile
else
   if [ -f $LOCKFILE -a -r $LOCKFILE ]; then
      read_lockfile
      if [ "\$timestamp" ]; then
         # First line fails, second line doesn't (most of the time).
         # Understand why, then please tell me why.
#        if expr \$currenttime '-' \$timestamp '<' $MAX_LOCK_AGE; then
         if [ \`expr \$currenttime '-' \$timestamp\` -lt $MAX_LOCK_AGE ]; then
            log "Found a recent lock, exiting"
            exit 0
         else
            log "Found a stale lock"
         fi
      else
         log "Corrupted lockfile"
      fi
   else
      log "Weird lockfile"
   fi

   log "Removing lockfile"
   rm -f $LOCKFILE
   if [ \$? -gt 0 ]; then
      log "Cannot remove lockfile, exiting"
      exit 1
   fi
   create_lockfile
fi

sleep 2
log "Checking lockfile"
read_lockfile
if [ ! "\$pid" ]; then
   log "Inexistant or corrupted lockfile, exiting"
   exit 1
fi
if [ "\$pid" -ne \$\$ ]; then
   log "Process \$pid overwrote lockfile, exiting"
   exit 1
fi


log "Killing all modem_run instances"
killall modem_run

pppd_pids=\`get_relevant_pppd_pids\`
if [ "\$pppd_pids" ]; then
   log "Killing relevant pppd instances: \$pppd_pids"
   kill \$pppd_pids
fi

if [ -e /var/run/pppoa3-modem1.pid ]; then
   log "Removing stale pppoa3 pid file"
   rm -f /var/run/pppoa3-modem1.pid
   if [ \$? -gt 0 ]; then
      log "Could not remove pid file"
   fi
fi


# Release the lock.
log "Releasing the lock"

rm -f $LOCKFILE
if [ \$? -gt 0 ]; then
   log "Could not remove lockfile"
fi

log "Done"
EOF
chmod 0755 $REMOVER


# Remove the current driver instance.

log "Killing all modem_run instances"
killall modem_run

pppd_pids=`get_relevant_pppd_pids`
if [ "$pppd_pids" ]; then
   log "Killing relevant pppd instances: $pppd_pids"
   kill $pppd_pids
fi

if [ -e /var/run/pppoa3-modem1.pid ]; then
   log "Removing stale pppoa3 pid file"
   rm -f /var/run/pppoa3-modem1.pid
   if [ $? -gt 0 ]; then
      log "Cannot remove pid file, exiting"
      exit 1
   fi
fi


# Write the substarter. Make it executable.
log "Writing substarter"

cat << EOF > $SUBSTARTER
#!/bin/bash
# SpeedTouch user-mode-driver substarter
# Generated by /etc/hotplug/usb/speedtouch


function log() {
   echo "\`date '+%F %T'\` substarter-$$-\$\$: \$1" >> $LOGFILE
}


# Run the user-mode driver.

log "Launching modem_run"
$PREFIX/sbin/modem_run -m $READ_FIRST -f $PREFIX/share/speedtouch/firmware

log "Launching pppd"
pppd call $PEER


# Release the lock.
log "Releasing the lock"

rm -f $LOCKFILE
if [ $? -gt 0 ]; then
   log "Could not remove lockfile"
fi

# The work is done.
log "Removing myself"

rm -f $SUBSTARTER

log "Done"
EOF
chmod 0755 $SUBSTARTER


# Run the substarter in the background.
log "Starting substarter"

$SUBSTARTER &

log "Done"

# vim: sts=3 sw=3 et