On Fri, Jul 18, 2003 at 20:20:58 -0500, Jesse Meyer wrote:
> On Fri, 18 Jul 2003, Vincent Lefevre wrote:
> > I wrote some zsh scripts to start ssh-agent if one is not running,
> > and call ssh-add only when needed (ssh, slogin and scp are wrappers).
> > The ssh-agent is killed when it isn't needed any longer (but this
> > doesn't work very well with screen, perhaps unless one chooses to
> > make all shells login shells).
> 
> I'm curious - mind showing us the scripts?

I've attached the two ssh functions _call_sshagent and _call_sshadd
(put them in your fpath). Use these scripts at your own risks. I tried
to avoid race conditions but there may still be something I forgot.

The .zlogin should contain a call to _call_sshagent. The .zlogout
should contain something like:

# Unregister from ssh-agent and kill it if need be.
if [[ -n $SSH_AUTH_SOCK ]] then
  if [[ `whence -w _call_sshagent` == '_call_sshagent: function' ]] then
    _call_sshagent -r
  elif [[ -n $SSH_AGENT_PID ]] then
    eval `ssh-agent -k`
  fi
fi

Alternativement, if you use programs like screen, you could put the
call to _call_sshagent into the .zshrc and use a trap to clean up.

And wrappers to automatically call ssh-add if need be:

ssh()
{
  _call_sshadd "$@"
  command ssh "$@"
}

slogin()
{
  _call_sshadd "$@"
  command slogin "$@"
}

scp()
{
  _call_sshadd "$@"
  command scp "$@"
}

I also have a wrapper scripts/ssh that contains:

#!/usr/bin/env zsh

# Note: put this script in ~/scripts (not in path)

source ~/.zshenv
source ~/.zalias
unset DISPLAY
ssh "$@"

# $Id: ssh 11 2003-06-18 19:30:04Z lefevre $

(the .zalias file contains the definitions of the above 3 functions).
This is useful for some programs like cvs or svn:

export CVS_RSH=$HOME/scripts/ssh
export SVN_SSH=$HOME/scripts/ssh

-- 
Vincent Lefèvre <[EMAIL PROTECTED]> - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA
#!/usr/bin/env zsh

# Usage: _call_sshagent [ -l | -r ]
#   -l: try to use an existing ssh-agent and change SSH_AUTH_SOCK
#       accordingly. This is useful for some non-login shells (no
#       possible clean-up by the .zlogout).
#   -r: remove the socket associated with the current process and
#       kill ssh-agent if there are no sockets any longer.

emulate -LR zsh

local link=/tmp/ssh-agent-$USER

local i=4
until (ln -s /dev/null $link.lock)
do
  if [[ $((--i)) -eq 0 ]] then
    echo "$0: can't lock $link"
    return
  fi
  sleep 2
done

local dir=`readlink $link`

if [[ $1 == -r ]] then

  if [[ -O $link && -d $dir && -O $dir && $SSH_AUTH_SOCK == $link/* ]] then
    local others
    rm -f $SSH_AUTH_SOCK
    unset SSH_AUTH_SOCK
    others=($dir/agent.*(N=))
    if [[ -z $others ]] then
      local pid=$(<$dir/ssh-agent.pid)
      rm -f $link $dir/ssh-agent.pid
      kill -TERM $pid
    fi
  else
    # Inconsistent data, try to kill ssh-agent in the standard way
    eval `ssh-agent -k`
  fi

elif [[ $1 == -l ]] then

  if [[ -O $link && -d $dir && -O $dir ]] then
    local old
    old=($link/agent.*(N=[1]))
    if [[ -S $old ]] then
      SSH_AUTH_SOCK=$old ssh-add -l >& /dev/null
      if [[ $? -ne 2 ]] then
        export SSH_AUTH_SOCK=$old
        unset SSH_AGENT_PID
      fi
    else
      echo "$0: $old isn't a socket"
    fi
  fi

else

  if [[ -O $link && -d $dir && -O $dir ]] then
    local old
    old=($link/agent.*(N=[1]))
    if [[ -S $old ]] then
      SSH_AUTH_SOCK=$old ssh-add -l >& /dev/null
      if [[ $? -eq 2 ]] then
        # The agent could not be contacted, assume that it has died
        rm -f $dir/agent.*(N) $dir/ssh-agent.pid && rmdir $dir
        rm -f $link
        rm -f $link.lock
        $0
        return
      fi
      local new=$link/agent.$$
      if [[ $new == $old ]] || ln -f $old $new; then
        export SSH_AUTH_SOCK=$new
        unset SSH_AGENT_PID
      else
        echo "$0: can't link $new -> $old"
      fi
    else
      echo "$0: $old isn't a socket"
    fi
  elif eval `ssh-agent`; then
    if ln -fs $SSH_AUTH_SOCK:h $link; then
      local old=$SSH_AUTH_SOCK
      echo $SSH_AGENT_PID > $link/ssh-agent.pid
      rm -f $link.lock
      $0 && rm -f $old
      return
    else
      echo "$0: can't symlink $dir -> $SSH_AUTH_SOCK:h"
    fi
  else
    echo "$0: can't call ssh-agent"
  fi

fi

rm -f $link.lock

# $Id: _call_sshagent 11 2003-06-18 19:30:04Z lefevre $
#!/usr/bin/env zsh

emulate -LR zsh

ssh-add -l >& /dev/null
local err=$?

if [[ $err -eq 2 ]] then
  _call_sshagent -l
  ssh-add -l >& /dev/null
  err=$?
fi

if [[ $err -eq 1 ]] then
  local file i
  file=()
  for i in id_rsa id_rsa-internal identity
  do
    [[ -f $HOME/.ssh/$i ]] && file=($file $HOME/.ssh/$i)
  done
  ssh-add $file
fi

true

# $Id: _call_sshadd 11 2003-06-18 19:30:04Z lefevre $

Reply via email to