comparison lisp/net/tramp.el @ 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 a20bb74ebe03
children a99299e4d2de
comparison
equal deleted inserted replaced
95966:054335cbee3d 95967:13aa0133c5af
5844 (tramp-send-command vec "stty -onlcr" t)))) 5844 (tramp-send-command vec "stty -onlcr" t))))
5845 (tramp-send-command vec "set +o vi +o emacs" t) 5845 (tramp-send-command vec "set +o vi +o emacs" t)
5846 5846
5847 ;; Check whether the output of "uname -sr" has been changed. If 5847 ;; Check whether the output of "uname -sr" has been changed. If
5848 ;; yes, this is a strong indication that we must expire all 5848 ;; yes, this is a strong indication that we must expire all
5849 ;; connection properties. 5849 ;; connection properties. We start again with
5850 ;; `tramp-maybe-open-connection', it will be catched there.
5850 (tramp-message vec 5 "Checking system information") 5851 (tramp-message vec 5 "Checking system information")
5851 (let ((old-uname (tramp-get-connection-property vec "uname" nil)) 5852 (let ((old-uname (tramp-get-connection-property vec "uname" nil))
5852 (new-uname 5853 (new-uname
5853 (tramp-set-connection-property 5854 (tramp-set-connection-property
5854 vec "uname" 5855 vec "uname"
5855 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\"")))) 5856 (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
5856 (when (and (stringp old-uname) (not (string-equal old-uname new-uname))) 5857 (when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
5857 (funcall (symbol-function 'tramp-cleanup-connection) vec) 5858 (with-current-buffer (tramp-get-debug-buffer vec)
5858 (signal 5859 ;; Keep the debug buffer
5859 'quit 5860 (rename-buffer " *temp*" 'unique)
5860 (list (format 5861 (funcall (symbol-function 'tramp-cleanup-connection) vec)
5861 "Connection reset, because remote host changed from `%s' to `%s'" 5862 (if (= (point-min) (point-max))
5862 old-uname new-uname))))) 5863 (kill-buffer nil)
5864 (rename-buffer (tramp-debug-buffer-name vec) 'unique))
5865 ;; We call `tramp-get-buffer' in order to keep the debug buffer.
5866 (tramp-get-buffer vec)
5867 (tramp-message
5868 vec 3
5869 "Connection reset, because remote host changed from `%s' to `%s'"
5870 old-uname new-uname)
5871 (throw 'uname-changed (tramp-maybe-open-connection vec)))))
5863 5872
5864 ;; Check whether the remote host suffers from buggy 5873 ;; Check whether the remote host suffers from buggy
5865 ;; `send-process-string'. This is known for FreeBSD (see comment in 5874 ;; `send-process-string'. This is known for FreeBSD (see comment in
5866 ;; `send_process', file process.c). I've tested sending 624 bytes 5875 ;; `send_process', file process.c). I've tested sending 624 bytes
5867 ;; successfully, sending 625 bytes failed. Emacs makes a hack when 5876 ;; successfully, sending 625 bytes failed. Emacs makes a hack when
6220 6229
6221 (defun tramp-maybe-open-connection (vec) 6230 (defun tramp-maybe-open-connection (vec)
6222 "Maybe open a connection VEC. 6231 "Maybe open a connection VEC.
6223 Does not do anything if a connection is already open, but re-opens the 6232 Does not do anything if a connection is already open, but re-opens the
6224 connection if a previous connection has died for some reason." 6233 connection if a previous connection has died for some reason."
6225 (let ((p (tramp-get-connection-process vec)) 6234 (catch 'uname-changed
6226 (process-environment (copy-sequence process-environment))) 6235 (let ((p (tramp-get-connection-process vec))
6227 6236 (process-environment (copy-sequence process-environment)))
6228 ;; If too much time has passed since last command was sent, look 6237
6229 ;; whether process is still alive. If it isn't, kill it. When 6238 ;; If too much time has passed since last command was sent, look
6230 ;; using ssh, it can sometimes happen that the remote end has hung 6239 ;; whether process is still alive. If it isn't, kill it. When
6231 ;; up but the local ssh client doesn't recognize this until it 6240 ;; using ssh, it can sometimes happen that the remote end has
6232 ;; tries to send some data to the remote end. So that's why we 6241 ;; hung up but the local ssh client doesn't recognize this until
6233 ;; try to send a command from time to time, then look again 6242 ;; it tries to send some data to the remote end. So that's why
6234 ;; whether the process is really alive. 6243 ;; we try to send a command from time to time, then look again
6235 (condition-case nil 6244 ;; whether the process is really alive.
6236 (when (and (> (tramp-time-diff 6245 (condition-case nil
6237 (current-time) 6246 (when (and (> (tramp-time-diff
6238 (tramp-get-connection-property 6247 (current-time)
6239 p "last-cmd-time" '(0 0 0))) 6248 (tramp-get-connection-property
6240 60) 6249 p "last-cmd-time" '(0 0 0)))
6241 p (processp p) (memq (process-status p) '(run open))) 6250 60)
6242 (tramp-send-command vec "echo are you awake" t t) 6251 p (processp p) (memq (process-status p) '(run open)))
6243 (unless (and (memq (process-status p) '(run open)) 6252 (tramp-send-command vec "echo are you awake" t t)
6244 (tramp-wait-for-output p 10)) 6253 (unless (and (memq (process-status p) '(run open))
6245 ;; The error will be catched locally. 6254 (tramp-wait-for-output p 10))
6246 (tramp-error vec 'file-error "Awake did fail"))) 6255 ;; The error will be catched locally.
6247 (file-error 6256 (tramp-error vec 'file-error "Awake did fail")))
6248 (tramp-flush-connection-property vec) 6257 (file-error
6249 (tramp-flush-connection-property p) 6258 (tramp-flush-connection-property vec)
6250 (delete-process p) 6259 (tramp-flush-connection-property p)
6251 (setq p nil))) 6260 (delete-process p)
6252 6261 (setq p nil)))
6253 ;; New connection must be opened. 6262
6254 (unless (and p (processp p) (memq (process-status p) '(run open))) 6263 ;; New connection must be opened.
6255 6264 (unless (and p (processp p) (memq (process-status p) '(run open)))
6256 ;; We call `tramp-get-buffer' in order to get a debug buffer for 6265
6257 ;; messages from the beginning. 6266 ;; We call `tramp-get-buffer' in order to get a debug buffer for
6258 (tramp-get-buffer vec) 6267 ;; messages from the beginning.
6259 (if (zerop (length (tramp-file-name-user vec))) 6268 (tramp-get-buffer vec)
6269 (if (zerop (length (tramp-file-name-user vec)))
6270 (tramp-message
6271 vec 3 "Opening connection for %s using %s..."
6272 (tramp-file-name-host vec)
6273 (tramp-file-name-method vec))
6260 (tramp-message 6274 (tramp-message
6261 vec 3 "Opening connection for %s using %s..." 6275 vec 3 "Opening connection for %s@%s using %s..."
6276 (tramp-file-name-user vec)
6262 (tramp-file-name-host vec) 6277 (tramp-file-name-host vec)
6263 (tramp-file-name-method vec)) 6278 (tramp-file-name-method vec)))
6264 (tramp-message 6279
6265 vec 3 "Opening connection for %s@%s using %s..." 6280 ;; Start new process.
6266 (tramp-file-name-user vec) 6281 (when (and p (processp p))
6267 (tramp-file-name-host vec) 6282 (delete-process p))
6268 (tramp-file-name-method vec))) 6283 (setenv "TERM" tramp-terminal-type)
6269 6284 (setenv "LC_ALL" "C")
6270 ;; Start new process. 6285 (setenv "PROMPT_COMMAND")
6271 (when (and p (processp p)) 6286 (setenv "PS1" "$ ")
6272 (delete-process p)) 6287 (let* ((target-alist (tramp-compute-multi-hops vec))
6273 (setenv "TERM" tramp-terminal-type) 6288 (process-connection-type tramp-process-connection-type)
6274 (setenv "LC_ALL" "C") 6289 (process-adaptive-read-buffering nil)
6275 (setenv "PROMPT_COMMAND") 6290 (coding-system-for-read nil)
6276 (setenv "PS1" "$ ") 6291 ;; This must be done in order to avoid our file name handler.
6277 (let* ((target-alist (tramp-compute-multi-hops vec)) 6292 (p (let ((default-directory
6278 (process-connection-type tramp-process-connection-type) 6293 (tramp-compat-temporary-file-directory)))
6279 (process-adaptive-read-buffering nil) 6294 (start-process
6280 (coding-system-for-read nil) 6295 (or (tramp-get-connection-property vec "process-name" nil)
6281 ;; This must be done in order to avoid our file name handler. 6296 (tramp-buffer-name vec))
6282 (p (let ((default-directory 6297 (tramp-get-connection-buffer vec)
6283 (tramp-compat-temporary-file-directory))) 6298 tramp-encoding-shell)))
6284 (start-process 6299 (first-hop t))
6285 (or (tramp-get-connection-property vec "process-name" nil) 6300
6286 (tramp-buffer-name vec)) 6301 (tramp-message
6287 (tramp-get-connection-buffer vec) 6302 vec 6 "%s" (mapconcat 'identity (process-command p) " "))
6288 tramp-encoding-shell))) 6303
6289 (first-hop t)) 6304 ;; Check whether process is alive.
6290 6305 (set-process-sentinel p 'tramp-process-sentinel)
6291 (tramp-message 6306 (tramp-set-process-query-on-exit-flag p nil)
6292 vec 6 "%s" (mapconcat 'identity (process-command p) " ")) 6307 (tramp-message vec 3 "Waiting 60s for local shell to come up...")
6293 6308 (tramp-barf-if-no-shell-prompt
6294 ;; Check whether process is alive. 6309 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell)
6295 (set-process-sentinel p 'tramp-process-sentinel) 6310
6296 (tramp-set-process-query-on-exit-flag p nil) 6311 ;; Now do all the connections as specified.
6297 (tramp-message vec 3 "Waiting 60s for local shell to come up...") 6312 (while target-alist
6298 (tramp-barf-if-no-shell-prompt 6313 (let* ((hop (car target-alist))
6299 p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell) 6314 (l-method (tramp-file-name-method hop))
6300 6315 (l-user (tramp-file-name-user hop))
6301 ;; Now do all the connections as specified. 6316 (l-host (tramp-file-name-host hop))
6302 (while target-alist 6317 (l-port nil)
6303 (let* ((hop (car target-alist)) 6318 (login-program
6304 (l-method (tramp-file-name-method hop)) 6319 (tramp-get-method-parameter l-method 'tramp-login-program))
6305 (l-user (tramp-file-name-user hop)) 6320 (login-args
6306 (l-host (tramp-file-name-host hop)) 6321 (tramp-get-method-parameter l-method 'tramp-login-args))
6307 (l-port nil) 6322 (gw-args
6308 (login-program 6323 (tramp-get-method-parameter l-method 'tramp-gw-args))
6309 (tramp-get-method-parameter l-method 'tramp-login-program)) 6324 (gw (tramp-get-file-property hop "" "gateway" nil))
6310 (login-args 6325 (g-method (and gw (tramp-file-name-method gw)))
6311 (tramp-get-method-parameter l-method 'tramp-login-args)) 6326 (g-user (and gw (tramp-file-name-user gw)))
6312 (gw-args 6327 (g-host (and gw (tramp-file-name-host gw)))
6313 (tramp-get-method-parameter l-method 'tramp-gw-args)) 6328 (command login-program)
6314 (gw (tramp-get-file-property hop "" "gateway" nil)) 6329 ;; We don't create the temporary file. In fact, it
6315 (g-method (and gw (tramp-file-name-method gw))) 6330 ;; is just a prefix for the ControlPath option of
6316 (g-user (and gw (tramp-file-name-user gw))) 6331 ;; ssh; the real temporary file has another name, and
6317 (g-host (and gw (tramp-file-name-host gw))) 6332 ;; it is created and protected by ssh. It is also
6318 (command login-program) 6333 ;; removed by ssh, when the connection is closed.
6319 ;; We don't create the temporary file. In fact, it 6334 (tmpfile
6320 ;; is just a prefix for the ControlPath option of 6335 (tramp-set-connection-property
6321 ;; ssh; the real temporary file has another name, and 6336 p "temp-file"
6322 ;; it is created and protected by ssh. It is also 6337 (make-temp-name
6323 ;; removed by ssh, when the connection is closed. 6338 (expand-file-name
6324 (tmpfile 6339 tramp-temp-name-prefix
6325 (tramp-set-connection-property 6340 (tramp-compat-temporary-file-directory)))))
6326 p "temp-file" 6341 spec)
6327 (make-temp-name 6342
6328 (expand-file-name 6343 ;; Add gateway arguments if necessary.
6329 tramp-temp-name-prefix 6344 (when (and gw gw-args)
6330 (tramp-compat-temporary-file-directory))))) 6345 (setq login-args (append login-args gw-args)))
6331 spec) 6346
6332 6347 ;; Check for port number. Until now, there's no need
6333 ;; Add gateway arguments if necessary. 6348 ;; for handling like method, user, host.
6334 (when (and gw gw-args) 6349 (when (string-match tramp-host-with-port-regexp l-host)
6335 (setq login-args (append login-args gw-args))) 6350 (setq l-port (match-string 2 l-host)
6336 6351 l-host (match-string 1 l-host)))
6337 ;; Check for port number. Until now, there's no need for handling 6352
6338 ;; like method, user, host. 6353 ;; Set variables for computing the prompt for reading
6339 (when (string-match tramp-host-with-port-regexp l-host) 6354 ;; password. They can also be derived from a gatewy.
6340 (setq l-port (match-string 2 l-host) 6355 (setq tramp-current-method (or g-method l-method)
6341 l-host (match-string 1 l-host))) 6356 tramp-current-user (or g-user l-user)
6342 6357 tramp-current-host (or g-host l-host))
6343 ;; Set variables for computing the prompt for reading password. 6358
6344 ;; They can also be derived from a gatewy. 6359 ;; Replace login-args place holders.
6345 (setq tramp-current-method (or g-method l-method) 6360 (setq
6346 tramp-current-user (or g-user l-user) 6361 l-host (or l-host "")
6347 tramp-current-host (or g-host l-host)) 6362 l-user (or l-user "")
6348 6363 l-port (or l-port "")
6349 ;; Replace login-args place holders. 6364 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port)
6350 (setq 6365 (?t . ,tmpfile))
6351 l-host (or l-host "") 6366 command
6352 l-user (or l-user "") 6367 (concat
6353 l-port (or l-port "") 6368 command " "
6354 spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port) 6369 (mapconcat
6355 (?t . ,tmpfile)) 6370 '(lambda (x)
6356 command 6371 (setq x (mapcar '(lambda (y) (format-spec y spec)) x))
6357 (concat 6372 (unless (member "" x) (mapconcat 'identity x " ")))
6358 command " " 6373 login-args " ")
6359 (mapconcat 6374 ;; String to detect failed connection. Every single
6360 '(lambda (x) 6375 ;; word must be enclosed with '\"'; otherwise it is
6361 (setq x (mapcar '(lambda (y) (format-spec y spec)) x)) 6376 ;; detected during connection setup.
6362 (unless (member "" x) (mapconcat 'identity x " "))) 6377 ;; Local shell could be a Windows COMSPEC. It doesn't
6363 login-args " ") 6378 ;; know the ";" syntax, but we must exit always for
6364 ;; String to detect failed connection. Every single word must 6379 ;; `start-process'. "exec" does not work either.
6365 ;; be enclosed with '\"'; otherwise it is detected 6380 (if first-hop
6366 ;; during connection setup. 6381 " && exit || exit"
6367 ;; Local shell could be a Windows COMSPEC. It doesn't know 6382 "; echo \"Tramp\" \"connection\" \"closed\"; sleep 1"))
6368 ;; the ";" syntax, but we must exit always for `start-process'. 6383 ;; We don't reach a Windows shell. Could be initial only.
6369 ;; "exec" does not work either. 6384 first-hop nil)
6370 (if first-hop 6385
6371 " && exit || exit" 6386 ;; Send the command.
6372 "; echo \"Tramp\" \"connection\" \"closed\"; sleep 1")) 6387 (tramp-message vec 3 "Sending command `%s'" command)
6373 ;; We don't reach a Windows shell. Could be initial only. 6388 (tramp-send-command vec command t t)
6374 first-hop nil) 6389 (tramp-process-actions p vec tramp-actions-before-shell 60)
6375 6390 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host))
6376 ;; Send the command. 6391 ;; Next hop.
6377 (tramp-message vec 3 "Sending command `%s'" command) 6392 (setq target-alist (cdr target-alist)))
6378 (tramp-send-command vec command t t) 6393
6379 (tramp-process-actions p vec tramp-actions-before-shell 60) 6394 ;; Make initial shell settings.
6380 (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host)) 6395 (tramp-open-connection-setup-interactive-shell p vec))))))
6381 ;; Next hop.
6382 (setq target-alist (cdr target-alist)))
6383
6384 ;; Make initial shell settings.
6385 (tramp-open-connection-setup-interactive-shell p vec)))))
6386 6396
6387 (defun tramp-send-command (vec command &optional neveropen nooutput) 6397 (defun tramp-send-command (vec command &optional neveropen nooutput)
6388 "Send the COMMAND to connection VEC. 6398 "Send the COMMAND to connection VEC.
6389 Erases temporary buffer before sending the command. If optional 6399 Erases temporary buffer before sending the command. If optional
6390 arg NEVEROPEN is non-nil, never try to open the connection. This 6400 arg NEVEROPEN is non-nil, never try to open the connection. This