I came up with my own solution, but it's a bit too complicated to post here. If anyone is interested, please comment on this answer, and I will find somewhere to post it.
Edit: Here is my solution, as requested.
Now, set up some functions for appending to the built-in argument lists stored in
(defun tramp-get-method-parameter (method param)
"Return the method parameter PARAM.
If the `tramp-methods' entry does not exist, return NIL."
(let ((entry (assoc param (assoc method tramp-methods))))
(when entry (cadr entry))))
(defun tramp-set-method-parameter (method param newvalue)
"Set the method paramter PARAM to VALUE for METHOD.
If METHOD does not yet have PARAM, add it.
If METHOD does not exist, do nothing."
(let ((method-params (assoc method tramp-methods)))
(let ((entry (assoc param method-params)))
(setcar (cdr entry) newvalue)
(setcdr (last method-params) '(param newvalue)))))))
(defun tramp-add-args (programs newargs)
"Append NEWARGS to the argument list for any of PROGRAMS in `tramp-methods'.
PROGRAMS can be a list of strings, or a single string."
;; Allow a single program string or a list of matching programs.
(when (stringp programs)
(setq programs (list programs)))
(message "%s" (list programs newargs))
(loop for method in (mapcar 'car tramp-methods) do
(let ((login-program (tramp-get-method-parameter method 'tramp-login-program))
(copy-program (tramp-get-method-parameter method 'tramp-copy-program))
(login-args (tramp-get-method-parameter method 'tramp-login-args))
(copy-args (tramp-get-method-parameter method 'tramp-copy-args)))
(message "Handling %s" method)
(message " Handling login program %s" login-program)
(when (find login-program programs :test 'string=)
(message " Adding to login program %s" login-program)
(tramp-set-method-parameter method 'tramp-login-args (append login-args newargs)))
(message " Handling copy program %s" login-program)
(when (find copy-program programs :test 'string=)
(message " Adding to copy program %s" copy-program)
(tramp-set-method-parameter method 'tramp-copy-args (append copy-args newargs))))))
tramp-add-args to add the arguments you want to all the ssh-based methods:
'("scp" "scp1" "scp2" "scp1_old" "scp2_old" "sftp" "rsync" "ssh" "ssh1" "ssh2" "ssh1_old" "ssh2_old" "scpx" "sshx")
'(("-o" "ControlPath=~/.ssh/control/emacs-master-%%r@%%h:%%p" "-o" "ControlMaster=auto")))
The code that I show above sets up connection sharing for ssh. If you want this to work reliably, you need to clear the socket files when your internet connection goes down. The following can accomplish this
First, create a script called
ssh-cleanup and put it in your
$PATH and put the following in it:
find "$CONTROL_DIR" -type s | xargs --no-run-if-empty -- rm -f
This script cleans up stale control files, since these will get left behind when ssh dies because you unplugged your network cable or disconnected your wireless.
Now set up emacs to run this script at the appripriate time:
(defun ssh-cleanup ()
(defadvice tramp-cleanup-all-connections (after cleanup-control-files activate)
Now, when you run
tramp-cleanup-all-connections, you'll also clean up the ssh socket directory. You should run this whenever you disconnect and reconnect to the internet.
Or, you could set up your computer to do it for you automatically.
Super Bonus Round
If you use Network Manager on Linux, you can have emacs do things for you when you connect or disconnect.
(defcustom network-manager-connect-hook nil
"List of functions to execute upon successful establishment of
a network connection."
(defcustom network-manager-disconnect-hook nil
"List of functions to execute upon disconnection from the
;; Only enable all of this if dbus is found
(when (require 'dbus nil nil)
(defun network-manager-dbus-signal-handler (nmstate)
"Execute the appropriate hook when Network Manager connects or
((4 1) (run-hooks 'network-manager-disconnect-hook))
(3 (run-hooks 'network-manager-connect-hook))))
(defvar network-manager-dbus-registration nil)
(defun network-manager-integration-enable ()
(network-manager-integration-disable) ; Make sure to clean up first
(defun network-manager-integration-disable ()
(setq network-manager-dbus-registration nil)))
;; Finally, enable it
Now add set
tramp-cleanup-all-connections to run when you disconnect.
(add-hook 'network-manager-disconnect-hook 'tramp-cleanup-all-connections)