changeset 95967:13aa0133c5af

(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.
author Michael Albinus <michael.albinus@gmx.de>
date Sun, 15 Jun 2008 16:57:03 +0000
parents 054335cbee3d
children f0936583f93c
files lisp/net/tramp.el
diffstat 1 files changed, 176 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/net/tramp.el	Sun Jun 15 14:58:24 2008 +0000
+++ b/lisp/net/tramp.el	Sun Jun 15 16:57:03 2008 +0000
@@ -5846,7 +5846,8 @@
 
   ;; 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 @@
 	  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 @@
   "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)))
-
-    ;; 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)))
-
-      ;; 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)))
+  (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)))
+
+      ;; 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)))
+	    (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)))
-
-      ;; 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) " "))
-
-	;; 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)
-
-	    ;; 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)))
-
-	    ;; 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)
-
-	    ;; 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)))))
+	   (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))
+
+	  (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)
+
+	  ;; 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)))
+
+	      ;; 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))
+
+	      ;; 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)))
+
+	  ;; 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.