1

I'm trying to use elisp as a shell script language. I'm writing a script where I need access to a file encrypted with gpg. I'm not sure how to handle the password prompt. In the examples below, he program is called from the command line (bash).

First try:

#!/usr/bin/emacs --script 
(setq passwd-file "~/password.gpg") 
  (save-excursion   
    (let ((passwd-buffer (find-file passwd-file)))
      (switch-to-buffer passwd-buffer)
      (princ (buffer-substring 1 30))))

This lets me enter the password in the terminal, but the password is shown in plaintext.

Second try

#!/usr/bin/emacs --script
(setq passwd-file "~/password.gpg") 
(setq pstring (shell-command-to-string (concat "gpg -d " passwd-file)))
(princ pstring)

This gives the error gpg: cannot open tty /dev/tty: No such device or address

snowape
  • 1,274
  • 10
  • 23
  • Do *not* use `find-file` for file IO. It may cause arbitrary side-effects, and could block Emacs in non-interactive sessions. –  Jun 22 '14 at 15:35
  • Would something like this help? `(read-passwd "Password: ")` Here is the printout of the available arguments for this function: `(read-passwd PROMPT &optional CONFIRM DEFAULT)` – lawlist Jun 22 '14 at 15:36
  • lunaryorn: What should I use instead? I had a look in the elisp manual but didn't find anything explicitly for IO. – snowape Jun 22 '14 at 15:49
  • lawlist: That function doesn't seem to work when called from the terminal. – snowape Jun 22 '14 at 15:52
  • Use `with-temp-buffer` and `insert-file-contents`. –  Jun 22 '14 at 21:45
  • 1
    @snowape Reported at http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17839. You may want to join the discussion to voice your support. –  Jun 23 '14 at 16:26

1 Answers1

2

You are likely out of luck. You first example suggests that even read-passwd does not hide the password input in a non-interactive session, as insert-file calls out to EPA for encrypted files, which in turn uses read-passwd for GPG password input.

Try to report this to the Emacs maintainers with M-x report-emacs-bug, asking them to suppress input echo in read-passwd in non-interactive sessions. That'd be the behaviour I'd expect.

For now, you cannot work around this limitation, because Emacs does not expose the underlying TTY to Emacs Lisp code, so you have no chance to manually disable input echo on the underlying TTY device.

From my experience in writing and contributing quite some non-interactive Emacs Lisp programs, I'd personally advise against using Emacs for non-interactive scripts. It's a poor platform for such programs. The API is limited, and there is a lot of implicit behaviour standing in the way of non-interactive programs, which you can't get rid of.

For instance, you cannot safely pass command line arguments to Emacs, since Emacs will automatically visit any existing file in its command line arguments, triggering all sorts of side effects such as prompts for unsafe local variables, etc.

  • I agree that elisp isn't an optimal scripting language, but FWIW you need only pass the `--` argument to prevent Emacs processing subsequent arguments. See http://stackoverflow.com/a/6807133/324105 (and for a robust standard approach, http://stackoverflow.com/a/6259330/324105 ). – phils Jun 22 '14 at 21:58
  • 1
    @phils `--` separates options from arguments, but does not actually stop Emacs from trying to visit all arguments as files. See https://gist.github.com/lunaryorn/66b2e9ad35ffb4bad8c2. –  Jun 23 '14 at 09:57
  • 2
    Apologies, you're absolutely right. I believe I'd never noticed that. Jurijs Oniscuks has the solution to that (in the same linked Q&A), which is to `(setq argv nil)` (or indeed `command-line-args-left`) before the script exits. – phils Jun 23 '14 at 17:29
  • 1
    @phils Thank you, I didn't know that. It's a fancy trick, indeed, but imho shows all the more why you should not use Emacs Lisp for scripts. It's just too flaky, in very subtle ways. –  Jun 23 '14 at 17:42