#! /bin/sh
# bash-login --- invoke bash when using /bin/sh as login shell

# Copyright (C) 1996, 1999 Noah S. Friedman

# Author: Noah Friedman <friedman@splode.com>
# Created: 1996-10-11

# $Id: bash-login,v 1.12 2000/01/23 01:57:35 friedman Exp $

# 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, 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, you can either send email to this
# program's maintainer or write to: The Free Software Foundation,
# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

# Commentary:

# This script allows you to set your login shell to /bin/sh, but invoke
# bash transparently on login.  If bash can't be found, restart the bourne
# shell.  This script should either be `execed' from .profile or else
# copied into it wholesale.  One possible .profile logic is:
#
#     case "${BASH_LOGIN_FAILED_P+set}:$LOGGED:$0" in
#       set:*:* | *:t:* ) : ;;
#       *:*:-sh | *:*:-*/sh )
#         case "${SINIT_MACHTYPE-unset}" in
#           unset )
#             hosttype=$HOME/etc/init/bin/hosttype
#             if test -f $hosttype; then
#               SINIT_MACHTYPE=`$hosttype`
#               export SINIT_MACHTYPE
#             fi ;;
#         esac
#         p=$HOME/bin/share/bash-login
#         if test -f "$p"; then
#           exec=exec
#           # If /bin/sh is bash 2.x, there is some lossage which prevents
#           # interactive shells from working correctly if we exec here.
#           case "$BASH_VERSION" in 2.* ) exec= ;; esac
#           $exec /bin/sh "$p"
#           exit $?
#         fi
#        ;;
#     esac
#
# This allows you to set your login shell to something safe in heterogenous
# environments where bash may not exist, but you want to use it if it's
# available.

# Code:

# Name by which this script was invoked.
progname=`echo "$0" | sed -e 's/[^\/]*\///g'`

# To prevent hairy quoting and escaping later.
bq='`'
eq="'"

usage="Usage: $progname {options}

Options are:
-D, --debug                  Turn on shell debugging ($bq${bq}set -x$eq$eq).
-h, --help                   You're looking at it.
-L, --no-login               Do not invoke bash as a login shell.
-p, --print-path             Print path of bash command that would be run.
                             Print nothing if bash cannot be found.
-S, --no-set-default-shell   Do not change value of \$SHELL.
-v, --verbose                Be verbose.
"

# Initialize variables.
# Don't use `unset' since old bourne shells don't have this command.
# Instead, assign them an empty value.
debug=
verbose=
printp=
setshellp=t
loginp=t

# Usage: eval "$getopt"; value=$optarg
# or     optarg_optional=t; eval "$getopt"; value=$optarg
#
# This function automatically shifts the positional args as appropriate.
# The argument to an option is optional if the variable `optarg_optional'
# is non-empty.  Otherwise, the argument is required and getopt will cause
# the program to exit on an error.  optarg_optional is reset to be empty
# after every call to getopt.  The argument (if any) is stored in the
# variable `optarg'.
#
# Long option syntax is `--foo=bar' or `--foo bar'.
# For optional args, you must use the `--foo=bar' long option syntax
# if the argument starts with `-', otherwise the argument will be ignored
# and treated as the next option.
#
# Note: because of broken bourne shells, using --foo=bar syntax can
# actually screw the quoting of args that end with trailing newlines.
# Specifically, most shells strip trailing newlines from substituted
# output, regardless of quoting.
getopt='
  {
    optarg=
    case "$1" in
      --*=* ) optarg=`echo "$1" | sed -e "1s/^[^=]*=//"` ; shift ;;
      -* )
        case "${2+set}:$optarg_optional" in
          set: ) optarg="$2" ; shift ; shift ;;
          set:?* )
            case "$2" in
              -* ) shift ;;
              * )  optarg="$2"; shift; shift ;;
            esac
           ;;
          : )
            option="$1"
            case "$option" in
              --*=* ) option=`echo "$option" | sed -e "1s/=.*//;q"` ;;
            esac
            echo "$progname: option $bq$option$eq requires argument." 1>&2
            echo "$progname: use $bq--help$eq to list option syntax." 1>&2
            exit 1
           ;;
          * ) shift ;;
        esac
       ;;
    esac
    optarg_optional=
  }'

# Parse command line arguments.
# Make sure that all wildcarded options are long enough to be unambiguous.
# It's a good idea to document the full long option name in each case.
# Long options which take arguments will need a `*' appended to the
# canonical name to match the value appended after the `=' character.
while : ; do
  case $# in 0) break ;; esac
  case "$1" in
    -D | --debug | --d* )
      debug=t
      shift
     ;;
    -h | --help | --h* )
      echo "$usage" 1>&2
      exit 0
     ;;
    -L | --no-login   | -no-l* )
      loginp=nil
      shift
     ;;
    -p | --print-path | --p* )
      printp=t
      shift
     ;;
    -S | --no-set-default-shell | --no-s* )
      setshellp=
      shift
     ;;
    -v | --verbose | --v* )
      verbose=t
      shift
     ;;
    -- )     # Stop option processing
      shift
      break
     ;;
    -? | --* )
      case "$1" in
        --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;;
        * )     arg="$1" ;;
      esac
      exec 1>&2
      echo "$progname: unknown or ambiguous option $bq$arg$eq"
      echo "$progname: Use $bq--help$eq for a list of options."
      exit 1
     ;;
    -??* )
      # Split grouped single options into separate args and try again
      optarg="$1"
      shift
      set fnord `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` ${1+"$@"}
      shift
     ;;
    * )
      break
     ;;
  esac
done

case "$debug" in t ) set -x ;; esac

# Directories where bash may exist.
# These should be specified in reverse order of preference.
pathdirs="
  /usr/sww/bin
  /usr/local/bin
  /usr/local/gnubin
  /usr/local/gnu/bin
  /tools/contrib/bin
  /tools/ns/bin
  /opt/gnu/bin
  /opt/local/bin
  /opt/lude/bin
  /usr/bin
  /bin
  $HOME/etc/arch/${SINIT_MACHTYPE-unknown}/bin
"

for d in $pathdirs; do
  case "$PATH" in
     "$d" | *":$d:"* | "$d:"* | *":$d" ) : ;;
     * ) PATH="$d:$PATH"; export PATH ;;
  esac
done

case "$printp" in
  t )
    path=`echo "$PATH" | sed -e 's/^:/.:/;s/::/:.:/g;s/:$/:./;s/:/ /g'`
    for p in $path ; do
      if test -f "$p/bash" && { "$p/bash" -c : ; } 2> /dev/null; then
        echo "$p/bash"
        exit 0
      fi
    done
    exit 1
   ;;
esac

# Not printing; actually execute bash
# The -norc option in the test is just to see if bash is really bash.
# On one system, bash was a symlink to a v7 bourne shell!
if { bash -norc -c : ; } 2> /dev/null ; then
  exec bash -norc -c '
    oSHELL="$SHELL"
    case "'"$setshellp"'" in
      t ) export SHELL=`type -path bash` ;;
    esac

    execflag=
    case "'"$loginp"':$BASH_VERSION" in
      t:1.*) execflag="-"  ;;
      t:2.*) execflag="-l" ;;
    esac

    no_exit_on_failed_exec=t
    exec $execflag bash ${1+"$@"}

    export SHELL="$oSHELL"
    export BASH_LOGIN_FAILED_P=t
    exec $execflag $SHELL ${1+"$@"}
  ' ${1+"$@"}
else
    exec /bin/sh ${1+"$@"}
fi

# bash-login ends here
