(tramp-open-connection-setup-interactive-shell): Flush cache, and
restart `tramp-maybe-open-connection' when the remote system has been changed. Throw 'uname-changed event. (tramp-maybe-open-connection): Catch it.
This commit is contained in:
parent
6653c6b769
commit
d8ac123e39
2 changed files with 167 additions and 153 deletions
|
@ -29,6 +29,10 @@
|
|||
modification time of the connection buffer.
|
||||
(tramp-sh-file-name-handler): Reset `tramp-locked' in case of
|
||||
error.
|
||||
(tramp-open-connection-setup-interactive-shell): Flush cache, and
|
||||
restart `tramp-maybe-open-connection' when the remote system has
|
||||
been changed. Throw 'uname-changed event.
|
||||
(tramp-maybe-open-connection): Catch it.
|
||||
|
||||
* net/tramp-cmds.el (tramp-cleanup-all-connections): Reset
|
||||
`tramp-locked'.
|
||||
|
|
|
@ -5846,7 +5846,8 @@ process to set up. VEC specifies the connection."
|
|||
|
||||
;; Check whether the output of "uname -sr" has been changed. If
|
||||
;; yes, this is a strong indication that we must expire all
|
||||
;; connection properties.
|
||||
;; connection properties. We start again with
|
||||
;; `tramp-maybe-open-connection', it will be catched there.
|
||||
(tramp-message vec 5 "Checking system information")
|
||||
(let ((old-uname (tramp-get-connection-property vec "uname" nil))
|
||||
(new-uname
|
||||
|
@ -5854,12 +5855,20 @@ process to set up. VEC specifies the connection."
|
|||
vec "uname"
|
||||
(tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
|
||||
(when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
|
||||
(funcall (symbol-function 'tramp-cleanup-connection) vec)
|
||||
(signal
|
||||
'quit
|
||||
(list (format
|
||||
"Connection reset, because remote host changed from `%s' to `%s'"
|
||||
old-uname new-uname)))))
|
||||
(with-current-buffer (tramp-get-debug-buffer vec)
|
||||
;; Keep the debug buffer
|
||||
(rename-buffer " *temp*" 'unique)
|
||||
(funcall (symbol-function 'tramp-cleanup-connection) vec)
|
||||
(if (= (point-min) (point-max))
|
||||
(kill-buffer nil)
|
||||
(rename-buffer (tramp-debug-buffer-name vec) 'unique))
|
||||
;; We call `tramp-get-buffer' in order to keep the debug buffer.
|
||||
(tramp-get-buffer vec)
|
||||
(tramp-message
|
||||
vec 3
|
||||
"Connection reset, because remote host changed from `%s' to `%s'"
|
||||
old-uname new-uname)
|
||||
(throw 'uname-changed (tramp-maybe-open-connection vec)))))
|
||||
|
||||
;; Check whether the remote host suffers from buggy
|
||||
;; `send-process-string'. This is known for FreeBSD (see comment in
|
||||
|
@ -6222,167 +6231,168 @@ Gateway hops are already opened."
|
|||
"Maybe open a connection VEC.
|
||||
Does not do anything if a connection is already open, but re-opens the
|
||||
connection if a previous connection has died for some reason."
|
||||
(let ((p (tramp-get-connection-process vec))
|
||||
(process-environment (copy-sequence process-environment)))
|
||||
(catch 'uname-changed
|
||||
(let ((p (tramp-get-connection-process vec))
|
||||
(process-environment (copy-sequence process-environment)))
|
||||
|
||||
;; If too much time has passed since last command was sent, look
|
||||
;; whether process is still alive. If it isn't, kill it. When
|
||||
;; using ssh, it can sometimes happen that the remote end has hung
|
||||
;; up but the local ssh client doesn't recognize this until it
|
||||
;; tries to send some data to the remote end. So that's why we
|
||||
;; try to send a command from time to time, then look again
|
||||
;; whether the process is really alive.
|
||||
(condition-case nil
|
||||
(when (and (> (tramp-time-diff
|
||||
(current-time)
|
||||
(tramp-get-connection-property
|
||||
p "last-cmd-time" '(0 0 0)))
|
||||
60)
|
||||
p (processp p) (memq (process-status p) '(run open)))
|
||||
(tramp-send-command vec "echo are you awake" t t)
|
||||
(unless (and (memq (process-status p) '(run open))
|
||||
(tramp-wait-for-output p 10))
|
||||
;; The error will be catched locally.
|
||||
(tramp-error vec 'file-error "Awake did fail")))
|
||||
(file-error
|
||||
(tramp-flush-connection-property vec)
|
||||
(tramp-flush-connection-property p)
|
||||
(delete-process p)
|
||||
(setq p nil)))
|
||||
;; If too much time has passed since last command was sent, look
|
||||
;; whether process is still alive. If it isn't, kill it. When
|
||||
;; using ssh, it can sometimes happen that the remote end has
|
||||
;; hung up but the local ssh client doesn't recognize this until
|
||||
;; it tries to send some data to the remote end. So that's why
|
||||
;; we try to send a command from time to time, then look again
|
||||
;; whether the process is really alive.
|
||||
(condition-case nil
|
||||
(when (and (> (tramp-time-diff
|
||||
(current-time)
|
||||
(tramp-get-connection-property
|
||||
p "last-cmd-time" '(0 0 0)))
|
||||
60)
|
||||
p (processp p) (memq (process-status p) '(run open)))
|
||||
(tramp-send-command vec "echo are you awake" t t)
|
||||
(unless (and (memq (process-status p) '(run open))
|
||||
(tramp-wait-for-output p 10))
|
||||
;; The error will be catched locally.
|
||||
(tramp-error vec 'file-error "Awake did fail")))
|
||||
(file-error
|
||||
(tramp-flush-connection-property vec)
|
||||
(tramp-flush-connection-property p)
|
||||
(delete-process p)
|
||||
(setq p nil)))
|
||||
|
||||
;; New connection must be opened.
|
||||
(unless (and p (processp p) (memq (process-status p) '(run open)))
|
||||
;; New connection must be opened.
|
||||
(unless (and p (processp p) (memq (process-status p) '(run open)))
|
||||
|
||||
;; We call `tramp-get-buffer' in order to get a debug buffer for
|
||||
;; messages from the beginning.
|
||||
(tramp-get-buffer vec)
|
||||
(if (zerop (length (tramp-file-name-user vec)))
|
||||
;; We call `tramp-get-buffer' in order to get a debug buffer for
|
||||
;; messages from the beginning.
|
||||
(tramp-get-buffer vec)
|
||||
(if (zerop (length (tramp-file-name-user vec)))
|
||||
(tramp-message
|
||||
vec 3 "Opening connection for %s using %s..."
|
||||
(tramp-file-name-host vec)
|
||||
(tramp-file-name-method vec))
|
||||
(tramp-message
|
||||
vec 3 "Opening connection for %s using %s..."
|
||||
vec 3 "Opening connection for %s@%s using %s..."
|
||||
(tramp-file-name-user vec)
|
||||
(tramp-file-name-host vec)
|
||||
(tramp-file-name-method vec))
|
||||
(tramp-message
|
||||
vec 3 "Opening connection for %s@%s using %s..."
|
||||
(tramp-file-name-user vec)
|
||||
(tramp-file-name-host vec)
|
||||
(tramp-file-name-method vec)))
|
||||
(tramp-file-name-method vec)))
|
||||
|
||||
;; Start new process.
|
||||
(when (and p (processp p))
|
||||
(delete-process p))
|
||||
(setenv "TERM" tramp-terminal-type)
|
||||
(setenv "LC_ALL" "C")
|
||||
(setenv "PROMPT_COMMAND")
|
||||
(setenv "PS1" "$ ")
|
||||
(let* ((target-alist (tramp-compute-multi-hops vec))
|
||||
(process-connection-type tramp-process-connection-type)
|
||||
(process-adaptive-read-buffering nil)
|
||||
(coding-system-for-read nil)
|
||||
;; This must be done in order to avoid our file name handler.
|
||||
(p (let ((default-directory
|
||||
(tramp-compat-temporary-file-directory)))
|
||||
(start-process
|
||||
(or (tramp-get-connection-property vec "process-name" nil)
|
||||
(tramp-buffer-name vec))
|
||||
(tramp-get-connection-buffer vec)
|
||||
tramp-encoding-shell)))
|
||||
(first-hop t))
|
||||
;; Start new process.
|
||||
(when (and p (processp p))
|
||||
(delete-process p))
|
||||
(setenv "TERM" tramp-terminal-type)
|
||||
(setenv "LC_ALL" "C")
|
||||
(setenv "PROMPT_COMMAND")
|
||||
(setenv "PS1" "$ ")
|
||||
(let* ((target-alist (tramp-compute-multi-hops vec))
|
||||
(process-connection-type tramp-process-connection-type)
|
||||
(process-adaptive-read-buffering nil)
|
||||
(coding-system-for-read nil)
|
||||
;; This must be done in order to avoid our file name handler.
|
||||
(p (let ((default-directory
|
||||
(tramp-compat-temporary-file-directory)))
|
||||
(start-process
|
||||
(or (tramp-get-connection-property vec "process-name" nil)
|
||||
(tramp-buffer-name vec))
|
||||
(tramp-get-connection-buffer vec)
|
||||
tramp-encoding-shell)))
|
||||
(first-hop t))
|
||||
|
||||
(tramp-message
|
||||
vec 6 "%s" (mapconcat 'identity (process-command p) " "))
|
||||
(tramp-message
|
||||
vec 6 "%s" (mapconcat 'identity (process-command p) " "))
|
||||
|
||||
;; Check whether process is alive.
|
||||
(set-process-sentinel p 'tramp-process-sentinel)
|
||||
(tramp-set-process-query-on-exit-flag p nil)
|
||||
(tramp-message vec 3 "Waiting 60s for local shell to come up...")
|
||||
(tramp-barf-if-no-shell-prompt
|
||||
p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
|
||||
;; Check whether process is alive.
|
||||
(set-process-sentinel p 'tramp-process-sentinel)
|
||||
(tramp-set-process-query-on-exit-flag p nil)
|
||||
(tramp-message vec 3 "Waiting 60s for local shell to come up...")
|
||||
(tramp-barf-if-no-shell-prompt
|
||||
p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
|
||||
|
||||
;; Now do all the connections as specified.
|
||||
(while target-alist
|
||||
(let* ((hop (car target-alist))
|
||||
(l-method (tramp-file-name-method hop))
|
||||
(l-user (tramp-file-name-user hop))
|
||||
(l-host (tramp-file-name-host hop))
|
||||
(l-port nil)
|
||||
(login-program
|
||||
(tramp-get-method-parameter l-method 'tramp-login-program))
|
||||
(login-args
|
||||
(tramp-get-method-parameter l-method 'tramp-login-args))
|
||||
(gw-args
|
||||
(tramp-get-method-parameter l-method 'tramp-gw-args))
|
||||
(gw (tramp-get-file-property hop "" "gateway" nil))
|
||||
(g-method (and gw (tramp-file-name-method gw)))
|
||||
(g-user (and gw (tramp-file-name-user gw)))
|
||||
(g-host (and gw (tramp-file-name-host gw)))
|
||||
(command login-program)
|
||||
;; We don't create the temporary file. In fact, it
|
||||
;; is just a prefix for the ControlPath option of
|
||||
;; ssh; the real temporary file has another name, and
|
||||
;; it is created and protected by ssh. It is also
|
||||
;; removed by ssh, when the connection is closed.
|
||||
(tmpfile
|
||||
(tramp-set-connection-property
|
||||
p "temp-file"
|
||||
(make-temp-name
|
||||
(expand-file-name
|
||||
tramp-temp-name-prefix
|
||||
(tramp-compat-temporary-file-directory)))))
|
||||
spec)
|
||||
;; Now do all the connections as specified.
|
||||
(while target-alist
|
||||
(let* ((hop (car target-alist))
|
||||
(l-method (tramp-file-name-method hop))
|
||||
(l-user (tramp-file-name-user hop))
|
||||
(l-host (tramp-file-name-host hop))
|
||||
(l-port nil)
|
||||
(login-program
|
||||
(tramp-get-method-parameter l-method 'tramp-login-program))
|
||||
(login-args
|
||||
(tramp-get-method-parameter l-method 'tramp-login-args))
|
||||
(gw-args
|
||||
(tramp-get-method-parameter l-method 'tramp-gw-args))
|
||||
(gw (tramp-get-file-property hop "" "gateway" nil))
|
||||
(g-method (and gw (tramp-file-name-method gw)))
|
||||
(g-user (and gw (tramp-file-name-user gw)))
|
||||
(g-host (and gw (tramp-file-name-host gw)))
|
||||
(command login-program)
|
||||
;; We don't create the temporary file. In fact, it
|
||||
;; is just a prefix for the ControlPath option of
|
||||
;; ssh; the real temporary file has another name, and
|
||||
;; it is created and protected by ssh. It is also
|
||||
;; removed by ssh, when the connection is closed.
|
||||
(tmpfile
|
||||
(tramp-set-connection-property
|
||||
p "temp-file"
|
||||
(make-temp-name
|
||||
(expand-file-name
|
||||
tramp-temp-name-prefix
|
||||
(tramp-compat-temporary-file-directory)))))
|
||||
spec)
|
||||
|
||||
;; Add gateway arguments if necessary.
|
||||
(when (and gw gw-args)
|
||||
(setq login-args (append login-args gw-args)))
|
||||
;; Add gateway arguments if necessary.
|
||||
(when (and gw gw-args)
|
||||
(setq login-args (append login-args gw-args)))
|
||||
|
||||
;; Check for port number. Until now, there's no need for handling
|
||||
;; like method, user, host.
|
||||
(when (string-match tramp-host-with-port-regexp l-host)
|
||||
(setq l-port (match-string 2 l-host)
|
||||
l-host (match-string 1 l-host)))
|
||||
;; Check for port number. Until now, there's no need
|
||||
;; for handling like method, user, host.
|
||||
(when (string-match tramp-host-with-port-regexp l-host)
|
||||
(setq l-port (match-string 2 l-host)
|
||||
l-host (match-string 1 l-host)))
|
||||
|
||||
;; Set variables for computing the prompt for reading password.
|
||||
;; They can also be derived from a gatewy.
|
||||
(setq tramp-current-method (or g-method l-method)
|
||||
tramp-current-user (or g-user l-user)
|
||||
tramp-current-host (or g-host l-host))
|
||||
;; Set variables for computing the prompt for reading
|
||||
;; password. They can also be derived from a gatewy.
|
||||
(setq tramp-current-method (or g-method l-method)
|
||||
tramp-current-user (or g-user l-user)
|
||||
tramp-current-host (or g-host l-host))
|
||||
|
||||
;; Replace login-args place holders.
|
||||
(setq
|
||||
l-host (or l-host "")
|
||||
l-user (or l-user "")
|
||||
l-port (or l-port "")
|
||||
spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
|
||||
(?t . ,tmpfile))
|
||||
command
|
||||
(concat
|
||||
command " "
|
||||
(mapconcat
|
||||
'(lambda (x)
|
||||
(setq x (mapcar '(lambda (y) (format-spec y spec)) x))
|
||||
(unless (member "" x) (mapconcat 'identity x " ")))
|
||||
login-args " ")
|
||||
;; String to detect failed connection. Every single word must
|
||||
;; be enclosed with '\"'; otherwise it is detected
|
||||
;; during connection setup.
|
||||
;; Local shell could be a Windows COMSPEC. It doesn't know
|
||||
;; the ";" syntax, but we must exit always for `start-process'.
|
||||
;; "exec" does not work either.
|
||||
(if first-hop
|
||||
" && exit || exit"
|
||||
"; echo \"Tramp\" \"connection\" \"closed\"; sleep 1"))
|
||||
;; We don't reach a Windows shell. Could be initial only.
|
||||
first-hop nil)
|
||||
;; Replace login-args place holders.
|
||||
(setq
|
||||
l-host (or l-host "")
|
||||
l-user (or l-user "")
|
||||
l-port (or l-port "")
|
||||
spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
|
||||
(?t . ,tmpfile))
|
||||
command
|
||||
(concat
|
||||
command " "
|
||||
(mapconcat
|
||||
'(lambda (x)
|
||||
(setq x (mapcar '(lambda (y) (format-spec y spec)) x))
|
||||
(unless (member "" x) (mapconcat 'identity x " ")))
|
||||
login-args " ")
|
||||
;; String to detect failed connection. Every single
|
||||
;; word must be enclosed with '\"'; otherwise it is
|
||||
;; detected during connection setup.
|
||||
;; Local shell could be a Windows COMSPEC. It doesn't
|
||||
;; know the ";" syntax, but we must exit always for
|
||||
;; `start-process'. "exec" does not work either.
|
||||
(if first-hop
|
||||
" && exit || exit"
|
||||
"; echo \"Tramp\" \"connection\" \"closed\"; sleep 1"))
|
||||
;; We don't reach a Windows shell. Could be initial only.
|
||||
first-hop nil)
|
||||
|
||||
;; Send the command.
|
||||
(tramp-message vec 3 "Sending command `%s'" command)
|
||||
(tramp-send-command vec command t t)
|
||||
(tramp-process-actions p vec tramp-actions-before-shell 60)
|
||||
(tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
|
||||
;; Next hop.
|
||||
(setq target-alist (cdr target-alist)))
|
||||
;; Send the command.
|
||||
(tramp-message vec 3 "Sending command `%s'" command)
|
||||
(tramp-send-command vec command t t)
|
||||
(tramp-process-actions p vec tramp-actions-before-shell 60)
|
||||
(tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
|
||||
;; Next hop.
|
||||
(setq target-alist (cdr target-alist)))
|
||||
|
||||
;; Make initial shell settings.
|
||||
(tramp-open-connection-setup-interactive-shell p vec)))))
|
||||
;; Make initial shell settings.
|
||||
(tramp-open-connection-setup-interactive-shell p vec))))))
|
||||
|
||||
(defun tramp-send-command (vec command &optional neveropen nooutput)
|
||||
"Send the COMMAND to connection VEC.
|
||||
|
|
Loading…
Add table
Reference in a new issue