#!/bin/sh
# $Id: ssh-agent-stuff,v 1.6 2020/10/26 16:08:18 nocturne Exp $

################################################################
## Usage:
## for bourne shell and ksh, put this somewhere in your dotfiles:
##    eval `path/to/ssh-agent-stuff`
##    alias ressh='eval `path/to/ssh-agent-stuff`'
##
## for tcsh/csh, put this somewhere in your dotfiles
##    eval `path/to/ssh-agent-stuff`
##    alias ressh 'eval `path/to/ssh-agent-stuff`'
##
## In a shell with no agent, or whose agent has died, you can run
## "ressh" to point that shell at your latest valid agent. (The info
## for that agent will be recorded in ~/.ssh/.current-agent .)
################################################################

AGENT='ssh-agent -s'

VALUEFILE=~/.ssh/.current-agent

have_local_keys() {
    if [ -n "$(find $HOME/.ssh -maxdepth 1 -name internal-\* -print -quit)" ]; then
	return 0 # yes keys
    else
	return 1 # no keys
    fi
}

confirm_agent () {
    if [ -n "${SSH_AGENT_PID}" -a -n "${SSH_AUTH_SOCK}" ] \
	&& kill -0 ${SSH_AGENT_PID} >/dev/null 2>&1; then
	## ssh-add returns 0 if there are identities and 1 if not.
	## It returns 2 if there is no agent running.
	ssh-add -l >/dev/null 2>&1
	case "$?" in
	    0|1)
		return 0 # we have a live agent! Success.
		;;
	    *)
		echo "Agent found to be bad. Restarting." 1>&2
		return 1
		;;
	esac
    else
	return 1 # variables unset, or no such pid
    fi ;
}

tell_values () {
    case `basename "$SHELL"` in
	sh|ksh*|zsh*|bash*)
	    cat <<EOF
SSH_AUTH_SOCK="${SSH_AUTH_SOCK}" ;
SSH_AGENT_PID="${SSH_AGENT_PID}" ;
export SSH_AUTH_SOCK SSH_AGENT_PID ;
EOF
	    ;;
	tcsh*|csh*)
	    cat <<EOF
setenv SSH_AUTH_SOCK "${SSH_AUTH_SOCK}" ;
setenv SSH_AGENT_PID "${SSH_AGENT_PID}" ;
EOF
	    ;;
    esac
}

record_values () {
    # Update the live file atomically to avoid read/write race conditions.
    # Use a unique tempfile, to avoid the same race conditions.
    tell_values > "$VALUEFILE".$$.tmp
    mv -f "$VALUEFILE".$$.tmp "$VALUEFILE"
}

#### Common cases:
if have_local_keys; then
    if confirm_agent; then
	record_values
	# No need to tell_values because our parent has the good values.
	exit 0 # yay
    fi
else
    exit 0 # we have no keys here (engVM?), don't start an agent
fi

#### Problem case: env variables were incorrect/missing.

################################################################

#### Utilities for more detailed work

snarf_value () {
    # Pretend we're sourcing the file.
    grep "^${1}=" "$VALUEFILE" \
     | tail -1 \
     | sed -e 's/.*=//' -e "s/^[\"']\(.*\)[\"']$/\1/" ;
}

import_variable () {
    eval "${1}=`snarf_value ${1}`"
    eval export "$1" ;
}

################################################################

#### Deal with corner cases...

if [ -f "$VALUEFILE" ]; then
    import_variable SSH_AUTH_SOCK
    import_variable SSH_AGENT_PID
fi

if confirm_agent; then
    : # The file had a good agent. Yay.
else
    eval `$AGENT` >/dev/null
    record_values
fi

tell_values
