tmux and when I run
gpg to sign or encrypt, gpg shows a blank screen where I would expect to type my passphrase. I've straced gpg and it shows that it's hanging waiting on a socket
read() (presumably from
gpg-agent. What's going on here?
If you are using bash, then Chris W.’s wrapper script is the way to go. If perchance you are using zsh, then you can exploit the
~/.zshenv startup script to set
GPG_TTY from there, no need for a wrapper. Since bash does not have a similar startup script (cf. Bash Startup Files), you’ll have to use the wrapper there.
Some background: Interactive and non-interactive shells
The gpg-agent expects
GPG_TTY to point to the tty from where it is invoked, such that it can display its passphrase prompts in a secure manner. The GnuPG manual suggests putting the following in
~/.bashrc (or similar):
GPG_TTY=$(tty) export GPG_TTY
If you invoke mutt directly from your shell, this will work:
GPG_TTY will be set, mutt will pick it up and pass it to gpg when it needs to.
However, when you launch mutt via tmux’s
new-window command or similar constructs, there is an important difference: Before, your mutt was in a so-called interactive shell—that is, you had a shell prompt open and launched mutt from there yourself.
tmux new-window launches a non-interactive shell, since your shell is only needed to launch mutt and you won‘t be able to interact with it. In this case, bath won‘t read
.bashrc at all, since they are designed to set up your shell for interactive use.
zsh does pretty much the same thing:
.zshrc is read for interactive shells and skipped for non-interactive ones. However, in zsh, you can supply a third startup file,
.zshenv, that is read for every shell, no matter whether it is interactive or not. Therefore, if you set
GPG_TTY from there, it will always be available, no matter in which way mutt is started. And since
$TTY is a shell builtin variable that always points to the current tty, you can avoid the overhead of spawning a
tty process every time the shell comes up.
I was launching
mutt by running
tmux neww mutt.
mutt was inheriting the environment set in
tmux. This includes
$GPG_TTY which is different for the new pane in which I'm running
mutt (or unset if not in the
tmux environment). I wrote a wrapper called
gpgtty that sets
$GPG_TTY correctly for new panes.
#!/bin/sh GPG_TTY=$(tty) $*
Then I launch
tmux neww gpgtty mutt.
gpg works correctly after that. FYI, this is all using
gpg passphrase input.