#! /bin/bash
#
# Copyright (C) 1999 Guido Flohr <guido@freemint.de>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

# Requires: sh-utils, fileutils, textutils, /bin/bash.
VERSION="0.3.2"
PACKAGE="mint-util"
driver_dir=/boot/modules
install_dir="/boot/mint"
my_name=$0
action=
force=no
verbose=no
dry_run=no

# Display a help message.
help ()
{
  cat <<EOF
Usage: $my_name [OPTIONS] [FILES]
Manage file system and device drivers and network interfaces for MiNT.

  -i, --install             Install specified drivers
  -u, --uninstall           Uninstall specified drivers (if a 
                            a copy is present unless --force)
  -f, --force               Do things that look dangerous to the program
                            (you will get informed when to use this option)
  -U, --update              update driver directory and installation
                            directory.
  -n, --just-print, --dry-run, --recon
                            Don't actually run any commands; just print them.
  -v, --verbose             Verbose diagnostic output
  -h, --help                Display this help page and exit
  -V, --version             Display version information and exit

When called with no arguments the program will display all available
file system and device drivers and network interfaces, indicating by
\`(x)' that the driver is installed, by \`(-)' that the driver is
currently not installed and by \`(?)' that the driver is not under
control of this program.

Drivers will first be looked for relative to the current directory,
then in \`/usr/lib/mint/drivers', the extenders \`.xdd', \`.xfs' and
\`.xif' will get automatically appended if necessary.  Drivers will 
get installed in \`/boot/mint'.

Report bugs to Guido Flohr <guido@freemint.de>.
EOF
}

# Display version information and exit.
version ()
{
  cat <<EOF
drivers ($PACKAGE) $VERSION
Copyright (C) 1999, Guido Flohr <guido@freemint.de>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Guido Flohr.
EOF
  exit 0
}

# List stuff.
list ()
{
  # First check for available drivers.
  for file in $driver_dir/*.{xfs,xdd} $driver_dir/net/*.xif; do
    if test -f $file; then
      case $file in
        *.xfs)
          type="File system      "
          ;;
        *.xdd)
          type="Device driver    "
          ;;
        *.xif)
          type="Network interface"
          ;;
      esac
      
      short_name=`basename $file`
      if test -f "$install_dir/$short_name"; then
        if test "$install_dir/$short_name" -nt "$driver_dir/$short_name"; then
          installed="(O)"
        elif test "$install_dir/$short_name" -ot "$driver_dir/$short_name"; then
          installed="(N)"
        else
          installed="(x)"
        fi
      else
        installed="(-)"
      fi
      echo "$installed $type $file"
    fi
  done
  
  # Now check for drivers we currently don't control.
  for file in $install_dir/*.{xfs,xdd,xif}; do
    if test -f $file; then
      short_name=`basename $file`
      if test ! -f $driver_dir/$short_name; then
        case $file in
          *.xfs)
            type="File system      "
            ;;
          *.xdd)
            type="Device driver    "
            ;;
          *.xif)
            type="Network interface"
            ;;
        esac
        echo "(?) $type $file"
      fi
    fi
  done
}

install ()
{
  if test "x$files" = x; then
    exec 1>&2
    echo "$my_name: no drivers to install specified."
    echo "Try \`$my_name --help' for more information."
    exit 1
  fi
  errors=no
  for file in $files; do
    if test -f "./$file"; then
      file="./$file"
    elif test -f "./$file.xdd"; then
      file="./$file.xdd"
    elif test -f "./$file.xfs"; then
      file="./$file.xfs"
    elif test -f "./$file.xif"; then
      file="./$file.xif"
    elif test -f "$driver_dir/$file"; then
      file="$driver_dir/$file"
    elif test -f "$driver_dir/$file.xdd"; then
      file="$driver_dir/$file.xdd"
    elif test -f "$driver_dir/$file.xfs"; then
      file="$driver_dir/$file.xfs"
    elif test -f "$driver_dir/$file.xif"; then
      file="$driver_dir/$file.xif"
    fi
    
    short_name=`basename $file`
    if test ! -f "$file"; then
      exec 1>&2
      echo "$my_name: $file: file not found"
      echo "$my_name: (Search directories are $driver_dirs"
      echo "$my_name: and current directory)."
      errors=yes
      continue
    fi
    
    if test $force != yes -a "$file" -ot "$install_dir/$short_name"; then
      exec 1>&2
      echo "$my_name: $file is older than $install_dir/$short_name."
      echo "$my_name: use option \`--force' to force overwrite."
      errors=yes
      continue
    fi
    
    test $verbose = yes && echo "  Installing \`$file' as \`$install_dir/$short_name'."
    if test $dry_run = yes; then
      echo "cp $file $install_dir"
      echo "touch --file $file $install_dir/$short_name"
    else
      cp $file $install_dir && touch --file $file $install_dir/$short_name || errors=yes
    fi
  done
  
  test $errors = yes && exit 1
}

uninstall ()
{
  if test "x$files" = x; then
    exec 1>&2
    echo "$my_name: no drivers to uninstall specified."
    echo "Try \`$my_name --help' for more information."
    exit 1
  fi
  errors=no
  for file in $files; do
    if test -f "$install_dir/$file"; then
      file="$install_dir/$file"
    elif test -f "$install_dir/$file.xdd"; then
      file="$install_dir/$file.xdd"
    elif test -f "$install_dir/$file.xfs"; then
      file="$install_dir/$file.xfs"
    elif test -f "$install_dir/$file.xif"; then
      file="$install_dir/$file.xif"
    fi
    
    short_name=`basename $file`
    if test ! -f "$file"; then
      exec 1>&2
      echo "$my_name: $file: file not found"
      echo "$my_name: (Search directory is $install_dir)."
      errors=yes
      continue
    fi

    # Check if we have a backup of the driver.
    if test ! -f "$driver_dir/$short_name"; then
      if test $dry_run = yes; then
        echo "cp $install_dir/$short_name $driver_dir/$short_name"
        echo "touch --file $install_dir/$short_name $driver_dir/$short_name"
      else
        cp $install_dir/$short_name $driver_dir/$short_name \
          && touch --file $install_dir/$short_name $driver_dir/$short_name \
          || (errors=yes; continue)
      fi
    else
      if test $force != yes; then
        cmp $driver_dir/$short_name $install_dir/$short_name >/dev/null 2>&1
        if test $? != 0; then
          exec 1>&2
          echo "$my_name: $driver_dir/$short_name and $install_dir/$short_name differ."
          echo "$my_name: (Use option \`--force' to force removal, or rebuild"
          echo "$my_name: driver directory with option \`--rebuild' first.)"
          errors=yes
          continue
        fi
      fi
    fi
    
    test $verbose = yes && echo "  Removing \`$install_dir/$short_name'."
    if test $dry_run = yes; then
      echo "rm -f $install_dir/$short_name"
    else
      rm -f "$install_dir/$short_name" || errors=yes
    fi
  done
  
  test $errors = yes && exit 1
}

update ()
{
  if test "x$files" != x; then
    exec 1>&2
    echo "$my_name: no drivers must be specified in update mode."
    echo "Try \`$my_name --help' for more information."
    exit 1
  fi
  
  errors=no
  for file in $driver_dir/*.{xfs,xdd,xif}; do
    test -f "$file" || continue  # In case wildcard expansion failed.
    short_name=`basename $file`
    # Do nothing if driver is not activated.
    test -f "$install_dir/$short_name" || continue

    if test $force != yes; then
      # Check if files differ.    
      cmp "$driver_dir/$short_name" "$install_dir/$short_name" >/dev/null 2>&1
      if test $? = 0; then
        differ=no
      else
        differ=yes
      fi
      
      # Check whether we would overwrite a more recent driver.
      if test $differ = yes -a "$driver_dir/$short_name" -ot "$install_dir/$short_name"; then
        exec 1>&2
        echo "$my_name: $driver_dir/$short_name is older than $install_dir/$short_name."
        echo "(Use option \`--force' to force overwriting.)"
        errors=yes
        continue
      fi
     
      # We can safely overwrite the old version.
      do_copy=yes
    fi
    test $verbose = yes && echo "  Installing \`$file' as \`$install_dir/$short_name'."
    if test $dry_run = yes; then
      echo "cp $file $install_dir"
      echo "touch --file $file $install_dir/$short_name"
    else
      cp $file $install_dir && touch --file $file $install_dir/$short_name || errors=yes
    fi
  done
  
  test $errors = yes && exit 1
}

rebuild ()
{
  if test "x$files" != x; then
    exec 1>&2
    echo "$my_name: no drivers must be specified in rebuild mode."
    echo "Try \`$my_name --help' for more information."
    exit 1
  fi
  
  errors=no
  for file in $install_dir/*.{xfs,xdd,xif}; do
    test -f "$file" || continue  # In case wildcard expansion failed.
   short_name=`basename $file`
    # If driver is not installed we can safely copy.
    if test ! -f "$driver_dir/$short_name"; then
      :
    elif test $force != yes; then
      # Check if files differ.    
      cmp "$driver_dir/$short_name" "$install_dir/$short_name" >/dev/null 2>&1
      if test $? = 0; then
        differ=no
      else
        differ=yes
      fi
      
      # Check whether we would overwrite a more recent driver.
      if test $differ = yes -a "$driver_dir/$short_name" -nt "$install_dir/$short_name"; then
        exec 1>&2
        echo "$my_name: $driver_dir/$short_name is newer than $install_dir/$short_name."
        echo "(Use option \`--force' to force overwriting.)"
        errors=yes
        continue
      fi
    fi
     
    # We can safely overwrite the old version.
    test $verbose = yes && echo "  Storing \`$file' as \`$driver_dir/$short_name'."
    if test $dry_run = yes; then
      echo "cp $file $driver_dir"
      echo "touch --file $file $driver_dir/$short_name"
    else
      cp $file $driver_dir && touch --file $file $driver_dir/$short_name || errors=yes
    fi
  done
  
  test $errors = yes && exit 1
}

IFS="${IFS= 	}";
# Parse options.
files=""
while test $# -gt 0; do
  option=$1
  case $option in
    -i|--i|--in|--ins|--inst|--insta|--instal|--install)
      if test x$action != x -a x$action != xinstall; then
        exec 1>&2
        echo "$my_name: only one action may be specified at once."
        echo "Try \`$my_name --help' for more information."
        exit 1
      fi
      action=install
      ;;
    -u|--un|--uni|--unin|--unins|--uninst|--unista|--uninstal|--uninstall)
      if test x$action != x -a x$action != xuninstall; then
        exec 1>&2
        echo "$my_name: only one action may be specified at once."
        echo "Try \`$my_name --help' for more information."
        exit 1
      fi
      action=uninstall
      ;;
    -U|--u|--up|--upd|--upda|--updat|--update)
      if test x$action != x -a x$action != xupdate; then
        exec 1>&2
        echo "$my_name: only one action may be specified at once."
        echo "Try \`$my_name --help' for more information."
        exit 1
      fi
      action=update
      ;;
    -r|--reb|--rebu|--rebui|--rebuil|--rebuild)
      if test x$action != x -a x$action != xrebuild; then
        exec 1>&2
        echo "$my_name: only one action may be specified at once."
        echo "Try \`$my_name --help' for more information."
        exit 1
      fi
      action=rebuild
      ;;      
    -f|--f|--fo|--for|--force)
      force=yes
      ;;
    -n|--j|--ju|--jus|--just|--just-|--just-p|--just-pr|--just-pri|--just-prin|--just-print| \
       --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run| \
       --rec|--reco|--recon)
       dry_run=yes
       ;;
    -h|--h|--he|--hel|--help)
      help
      exit 0
      ;;
    --u|--v|--ve|--ver|--r|--re)
      exec 1>&2
      echo "$my_name: option \`$1' is ambiguous."
      echo "Try \`$my_name --help' for more information."
      exit 1
      ;;
    -v|--verb|--verbo|--verbos|--verbose)
      verbose=yes
      ;;
    -V|--vers|--versi|--versio|--version)
      version
      ;;
    -[^-]*)
      exec 1>&2
      echo "$my_name: invalid option -- ${option#-}."
      echo "Try \`$my_name --help' for more information."
      exit 1
      ;;
    --[^-]*)
      exec 1>&2
      echo "$my_name: unrecognized option \`$option'."
      echo "Try \`$my_name --help' for more information."
      exit 1
      ;;
    *)
      files="$files $option"
  esac
  shift
done

if test x"$action" = x; then
  action=list
fi

case $action in
  list)
    list
    ;;
  install)
    install
    ;;
  uninstall)
    uninstall
    ;;
  update)
    update
    ;;
  rebuild)
    rebuild
    ;;
esac

exit 0
