;;; tramp-sh.el --- Tramp access functions for (s)sh-like connections
-;; Copyright (C) 1998-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2012 Free Software Foundation, Inc.
;; (copyright statements below in code to be updated with the above notice)
;; `dired-insert-set-properties'.
(defcustom tramp-inline-compress-start-size 4096
- "*The minimum size of compressing where inline transfer.
+ "The minimum size of compressing where inline transfer.
When inline transfer, compress transferred data of file
whose size is this value or above (up to `tramp-copy-size-limit').
If it is nil, no compression at all will be applied."
:type '(choice (const nil) integer))
(defcustom tramp-copy-size-limit 10240
- "*The maximum file size where inline copying is preferred over an out-of-the-band copy.
-If it is nil, inline out-of-the-band copy will be used without a check."
+ "The maximum file size where inline copying is preferred over an \
+out-of-the-band copy.
+If it is nil, out-of-the-band copy will be used without a check."
:group 'tramp
:type '(choice (const nil) integer))
;;;###tramp-autoload
(defcustom tramp-terminal-type "dumb"
- "*Value of TERM environment variable for logging in to remote host.
+ "Value of TERM environment variable for logging in to remote host.
Because Tramp wants to parse the output of the remote shell, it is easily
confused by ANSI color escape sequences and suchlike. Often, shell init
files conditionalize this setup based on the TERM environment variable."
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-ssh") ("%h")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))
- (tramp-password-end-of-line "xy") ;see docstring for "xy"
(tramp-default-port 22)))
;;;###tramp-autoload
(add-to-list 'tramp-methods
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-1" "-ssh") ("%h")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))
- (tramp-password-end-of-line "xy") ;see docstring for "xy"
(tramp-default-port 22)))
;;;###tramp-autoload
(add-to-list 'tramp-methods
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))
(tramp-copy-program "pscp")
- (tramp-copy-args (("-P" "%p") ("-scp") ("-p" "%k")
+ (tramp-copy-args (("-l" "%u") ("-P" "%p") ("-scp") ("-p" "%k")
("-q") ("-r")))
(tramp-copy-keep-date t)
(tramp-copy-recursive t)
- (tramp-password-end-of-line "xy") ;see docstring for "xy"
(tramp-default-port 22)))
;;;###tramp-autoload
(add-to-list 'tramp-methods
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))
(tramp-copy-program "pscp")
- (tramp-copy-args (("-P" "%p") ("-sftp") ("-p" "%k")
+ (tramp-copy-args (("-l" "%u") ("-P" "%p") ("-sftp") ("-p" "%k")
("-q") ("-r")))
(tramp-copy-keep-date t)
- (tramp-copy-recursive t)
- (tramp-password-end-of-line "xy"))) ;see docstring for "xy"
+ (tramp-copy-recursive t)))
;;;###tramp-autoload
(add-to-list 'tramp-methods
'("fcp"
`(,(concat "\\`" (regexp-opt '("su" "sudo" "ksu")) "\\'")
nil "root"))
;; Do not add "ssh" based methods, otherwise ~/.ssh/config would be ignored.
+;; Do not add "plink" based methods, they ask interactively for the user.
;;;###tramp-autoload
(add-to-list 'tramp-default-user-alist
`(,(concat
"\\`"
- (regexp-opt
- '("rcp" "remcp" "rsh" "telnet" "krlogin"
- "plink" "plink1" "pscp" "psftp" "fcp"))
+ (regexp-opt '("rcp" "remcp" "rsh" "telnet" "krlogin" "fcp"))
"\\'")
nil ,(user-login-name)))
;;;###tramp-autoload
(defconst tramp-completion-function-alist-putty
- '((tramp-parse-putty
- "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"))
- "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.")
+ `((tramp-parse-putty
+ ,(if (memq system-type '(windows-nt))
+ "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions"
+ "~/.putty/sessions")))
+ "Default list of (FUNCTION REGISTRY) pairs to be examined for putty sessions.")
;;;###tramp-autoload
(eval-after-load 'tramp
;; GNU/Linux (Debian, Suse): /bin:/usr/bin
;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
;; IRIX64: /usr/bin
+;;;###tramp-autoload
(defcustom tramp-remote-path
- '(tramp-default-remote-path "/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin"
- "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
- "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
- "*List of directories to search for executables on remote host.
+ '(tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin"
+ "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin"
+ "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin"
+ "/opt/bin" "/opt/sbin" "/opt/local/bin")
+ "List of directories to search for executables on remote host.
For every remote host, this variable will be set buffer local,
keeping the list of existing directories on that host.
,(format "TERM=%s" tramp-terminal-type)
"EMACS=t" ;; Deprecated.
,(format "INSIDE_EMACS='%s,tramp:%s'" emacs-version tramp-version)
- "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH="
+ "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" "PAGER=\"\""
"autocorrect=" "correct=")
-
- "*List of environment variables to be set on the remote host.
+ "List of environment variables to be set on the remote host.
Each element should be a string of the form ENVVARNAME=VALUE. An
entry ENVVARNAME= disables the corresponding environment variable,
:type '(repeat string))
(defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile"))
- "*Alist specifying extra arguments to pass to the remote shell.
+ "Alist specifying extra arguments to pass to the remote shell.
Entries are (REGEXP . ARGS) where REGEXP is a regular expression
matching the shell file name and ARGS is a string specifying the
arguments.
(defconst tramp-perl-encode
"%s -e '
# This script contributed by Juanma Barranquero <lektu@terra.es>.
-# Copyright (C) 2002-2011 Free Software Foundation, Inc.
+# Copyright (C) 2002-2012 Free Software Foundation, Inc.
use strict;
my %%trans = do {
(defconst tramp-perl-decode
"%s -e '
# This script contributed by Juanma Barranquero <lektu@terra.es>.
-# Copyright (C) 2002-2011 Free Software Foundation, Inc.
+# Copyright (C) 2002-2012 Free Software Foundation, Inc.
use strict;
my %%trans = do {
(tramp-get-file-exists-command v)
(tramp-shell-quote-argument localname)))))))
-;; CCC: This should check for an error condition and signal failure
-;; when something goes wrong.
-;; Daniel Pittman <daniel@danann.net>
(defun tramp-sh-handle-file-attributes (filename &optional id-format)
"Like `file-attributes' for Tramp files."
(unless id-format (setq id-format 'integer))
(tramp-get-test-command vec)
(tramp-shell-quote-argument localname)
(tramp-get-remote-stat vec)
- (if (eq id-format 'integer) "%u" "\"%U\"")
- (if (eq id-format 'integer) "%g" "\"%G\"")
+ (if (eq id-format 'integer) "%ue0" "\"%U\"")
+ (if (eq id-format 'integer) "%ge0" "\"%G\"")
(tramp-shell-quote-argument localname))))
(defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
;; "-"; this would confuse xargs. "ls -aQ" might be a solution,
;; but it does not work on all remote systems. Therefore, we
;; quote the filenames via sed.
- "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | xargs "
- "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 \"%%A\" t %%ie0 -1)'); "
- "echo \")\"")
+ "cd %s; echo \"(\"; (%s -a | sed -e s/\\$/\\\"/g -e s/^/\\\"/g | "
+ "xargs %s -c "
+ "'(\"%%n\" (\"%%N\") %%h %s %s %%Xe0 %%Ye0 %%Ze0 %%se0 \"%%A\" t %%ie0 -1)'"
+ " 2>/dev/null); echo \")\"")
(tramp-shell-quote-argument localname)
(tramp-get-ls-command vec)
(tramp-get-remote-stat vec)
- (if (eq id-format 'integer) "%u" "\"%U\"")
- (if (eq id-format 'integer) "%g" "\"%G\""))))
+ (if (eq id-format 'integer) "%ue0" "\"%U\"")
+ (if (eq id-format 'integer) "%ge0" "\"%G\""))))
;; This function should return "foo/" for directories and "bar" for
;; files.
'copy-file (list filename newname ok-if-already-exists keep-date)))))
(defun tramp-sh-handle-copy-directory
- (dirname newname &optional keep-date parents)
+ (dirname newname &optional keep-date parents copy-contents)
"Like `copy-directory' for Tramp files."
(let ((t1 (tramp-tramp-file-p dirname))
(t2 (tramp-tramp-file-p newname)))
;; Set variables for computing the prompt for reading
;; password.
(setq tramp-current-method (tramp-file-name-method v)
- tramp-current-user (tramp-file-name-user v)
- tramp-current-host (tramp-file-name-real-host v))
+ tramp-current-user (or (tramp-file-name-user v)
+ (tramp-get-connection-property
+ v "login-as" nil))
+ tramp-current-host (tramp-file-name-real-host v))
;; Expand hops. Might be necessary for gateway methods.
(setq v (car (tramp-compute-multi-hops v)))
(setq port (string-to-number (match-string 2 host))
host (string-to-number (match-string 1 host))))
+ ;; Check for user. There might be an interactive setting.
+ (setq user (or (tramp-file-name-user v)
+ (tramp-get-connection-property v "login-as" nil)))
+
;; Compose copy command.
- (setq spec (format-spec-make
+ (setq host (or host "")
+ user (or user "")
+ port (or port "")
+ spec (format-spec-make
?h host ?u user ?p port
?t (tramp-get-connection-property
(tramp-get-connection-process v) "temp-file" "")
p v nil tramp-actions-copy-out-of-band)))
;; Reset the transfer process properties.
- (tramp-message orig-vec 6 "%s" (buffer-string))
+ (tramp-message orig-vec 6 "\n%s" (buffer-string))
(tramp-set-connection-property v "process-name" nil)
(tramp-set-connection-property v "process-buffer" nil)))
"Recursively delete the directory given.
This is like `dired-recursive-delete-directory' for Tramp files."
(with-parsed-tramp-file-name filename nil
- ;; Run a shell command 'rm -r <localname>'
+ ;; Run a shell command 'rm -r <localname>'.
;; Code shamelessly stolen from the dired implementation and, um, hacked :)
(unless (file-exists-p filename)
(tramp-error v 'file-error "No such directory: %s" filename))
- ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
+ ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>).
(tramp-send-command
v
(format "rm -rf %s" (tramp-shell-quote-argument localname))
method user host
(tramp-drop-volume-letter
(tramp-run-real-handler
- 'expand-file-name (list localname))))))))
+ 'expand-file-name (list localname)))
+ hop)))))
;;; Remote commands:
(bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
(name1 name)
(i 0))
- (unwind-protect
- (save-excursion
- (save-restriction
- (unless buffer
- ;; BUFFER can be nil. We use a temporary buffer.
- (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
- (while (get-process name1)
- ;; NAME must be unique as process name.
- (setq i (1+ i)
- name1 (format "%s<%d>" name i)))
- (setq name name1)
- ;; Set the new process properties.
- (tramp-set-connection-property v "process-name" name)
- (tramp-set-connection-property v "process-buffer" buffer)
- ;; Activate narrowing in order to save BUFFER contents.
- ;; Clear also the modification time; otherwise we might
- ;; be interrupted by `verify-visited-file-modtime'.
- (with-current-buffer (tramp-get-connection-buffer v)
- (let ((buffer-undo-list t))
+
+ (unless buffer
+ ;; BUFFER can be nil. We use a temporary buffer.
+ (setq buffer (generate-new-buffer tramp-temp-buffer-name)))
+ (while (get-process name1)
+ ;; NAME must be unique as process name.
+ (setq i (1+ i)
+ name1 (format "%s<%d>" name i)))
+ (setq name name1)
+ ;; Set the new process properties.
+ (tramp-set-connection-property v "process-name" name)
+ (tramp-set-connection-property v "process-buffer" buffer)
+
+ (with-current-buffer (tramp-get-connection-buffer v)
+ (unwind-protect
+ (save-excursion
+ (save-restriction
+ ;; Activate narrowing in order to save BUFFER
+ ;; contents. Clear also the modification time;
+ ;; otherwise we might be interrupted by
+ ;; `verify-visited-file-modtime'.
+ (let ((buffer-undo-list t)
+ (buffer-read-only nil)
+ (mark (point)))
(clear-visited-file-modtime)
(narrow-to-region (point-max) (point-max))
+ ;; We call `tramp-maybe-open-connection', in order
+ ;; to cleanup the prompt afterwards.
+ (tramp-maybe-open-connection v)
+ (widen)
+ (delete-region mark (point))
+ (narrow-to-region (point-max) (point-max))
+ ;; Now do it.
(if command
;; Send the command.
(tramp-send-command v command nil t) ; nooutput
;; Check, whether a pty is associated.
- (tramp-maybe-open-connection v)
(unless (tramp-compat-process-get
(tramp-get-connection-process v) 'remote-tty)
(tramp-error
v 'file-error
- "pty association is not supported for `%s'" name)))))
- (let ((p (tramp-get-connection-process v)))
- ;; Set query flag for this process.
- (tramp-compat-set-process-query-on-exit-flag p t)
- ;; Return process.
- p)))
- ;; Save exit.
- (with-current-buffer (tramp-get-connection-buffer v)
+ "pty association is not supported for `%s'" name))))
+ (let ((p (tramp-get-connection-process v)))
+ ;; Set query flag for this process. We ignore errors,
+ ;; because the process could have finished already.
+ (ignore-errors
+ (tramp-compat-set-process-query-on-exit-flag p t))
+ ;; Return process.
+ p)))
+
+ ;; Save exit.
(if (string-match tramp-temp-buffer-name (buffer-name))
(progn
(set-process-buffer (tramp-get-connection-process v) nil)
(kill-buffer (current-buffer)))
- (set-buffer-modified-p bmp)))
- (tramp-set-connection-property v "process-name" nil)
- (tramp-set-connection-property v "process-buffer" nil)))))
+ (set-buffer-modified-p bmp))
+ (tramp-set-connection-property v "process-name" nil)
+ (tramp-set-connection-property v "process-buffer" nil))))))
(defun tramp-sh-handle-process-file
(program &optional infile destination display &rest args)
'write-region
(list start end localname append 'no-message lockname confirm))
- (let ((modes (save-excursion (tramp-default-file-modes filename)))
- ;; We use this to save the value of
- ;; `last-coding-system-used' after writing the tmp
- ;; file. At the end of the function, we set
- ;; `last-coding-system-used' to this saved value. This
- ;; way, any intermediary coding systems used while
- ;; talking to the remote shell or suchlike won't hose
- ;; this variable. This approach was snarfed from
- ;; ange-ftp.el.
- coding-system-used
- ;; Write region into a tmp file. This isn't really
- ;; needed if we use an encoding function, but currently
- ;; we use it always because this makes the logic
- ;; simpler.
- (tmpfile (or tramp-temp-buffer-file-name
- (tramp-compat-make-temp-file filename))))
+ (let* ((modes (save-excursion (tramp-default-file-modes filename)))
+ ;; We use this to save the value of
+ ;; `last-coding-system-used' after writing the tmp
+ ;; file. At the end of the function, we set
+ ;; `last-coding-system-used' to this saved value. This
+ ;; way, any intermediary coding systems used while
+ ;; talking to the remote shell or suchlike won't hose
+ ;; this variable. This approach was snarfed from
+ ;; ange-ftp.el.
+ coding-system-used
+ ;; Write region into a tmp file. This isn't really
+ ;; needed if we use an encoding function, but currently
+ ;; we use it always because this makes the logic
+ ;; simpler. We must also set `temporary-file-directory',
+ ;; because it could point to a remote directory.
+ (temporary-file-directory
+ (tramp-compat-temporary-file-directory))
+ (tmpfile (or tramp-temp-buffer-file-name
+ (tramp-compat-make-temp-file filename))))
;; If `append' is non-nil, we copy the file locally, and let
;; the native `write-region' implementation do the job.
(let (last-coding-system-used (need-chown t))
;; Set file modification time.
(when (or (eq visit t) (stringp visit))
- (let ((file-attr (file-attributes filename)))
+ (let ((file-attr (tramp-compat-file-attributes filename 'integer)))
(set-visited-file-modtime
;; We must pass modtime explicitly, because filename can
;; be different from (buffer-file-name), f.e. if
;; `file-precious-flag' is set.
(nth 5 file-attr))
- (when (and (eq (nth 2 file-attr) uid)
- (eq (nth 3 file-attr) gid))
+ (when (and (= (nth 2 file-attr) uid)
+ (= (nth 3 file-attr) gid))
(setq need-chown nil))))
;; Set the ownership.
`((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
;; Here we collect only file names, which need an operation.
- (tramp-run-real-handler 'vc-registered (list file))
+ (ignore-errors (tramp-run-real-handler 'vc-registered (list file)))
(tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
;; Send just one command, in order to fill the cache.
((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append)
nil)
+ ;; `process-file' and `start-file-process' shall be ignored.
+ ((and fn (eq operation 'process-file) 0))
+ ((and fn (eq operation 'start-file-process) nil))
;; Tramp file name handlers like `expand-file-name'. They
;; must still work.
- (fn
- (save-match-data (apply (cdr fn) args)))
+ (fn (save-match-data (apply (cdr fn) args)))
;; Default file name handlers, we don't care.
(t (tramp-run-real-handler operation args)))))))
;; `/usr/bin/test'.
;; `/usr/bin/test -e' In case `/bin/test' does not exist.
(unless (or
- (and (setq result (format "%s -e" (tramp-get-test-command vec)))
- (tramp-send-command-and-check
- vec (format "%s %s" result existing))
- (not (tramp-send-command-and-check
- vec (format "%s %s" result nonexistent))))
- (and (setq result "/bin/test -e")
- (tramp-send-command-and-check
- vec (format "%s %s" result existing))
- (not (tramp-send-command-and-check
- vec (format "%s %s" result nonexistent))))
- (and (setq result "/usr/bin/test -e")
- (tramp-send-command-and-check
- vec (format "%s %s" result existing))
- (not (tramp-send-command-and-check
- vec (format "%s %s" result nonexistent))))
- (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
- (tramp-send-command-and-check
- vec (format "%s %s" result existing))
- (not (tramp-send-command-and-check
- vec (format "%s %s" result nonexistent)))))
+ (ignore-errors
+ (and (setq result (format "%s -e" (tramp-get-test-command vec)))
+ (tramp-send-command-and-check
+ vec (format "%s %s" result existing))
+ (not (tramp-send-command-and-check
+ vec (format "%s %s" result nonexistent)))))
+ (ignore-errors
+ (and (setq result "/bin/test -e")
+ (tramp-send-command-and-check
+ vec (format "%s %s" result existing))
+ (not (tramp-send-command-and-check
+ vec (format "%s %s" result nonexistent)))))
+ (ignore-errors
+ (and (setq result "/usr/bin/test -e")
+ (tramp-send-command-and-check
+ vec (format "%s %s" result existing))
+ (not (tramp-send-command-and-check
+ vec (format "%s %s" result nonexistent)))))
+ (ignore-errors
+ (and (setq result (format "%s -d" (tramp-get-ls-command vec)))
+ (tramp-send-command-and-check
+ vec (format "%s %s" result existing))
+ (not (tramp-send-command-and-check
+ vec (format "%s %s" result nonexistent))))))
(tramp-error
vec 'file-error "Couldn't find command to check if file exists"))
result))
(setq item (pop alist))
(when (string-match (car item) shell)
(setq extra-args (cdr item))))
- (when extra-args (setq shell (concat shell " " extra-args)))
(tramp-send-command
- vec (format "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s"
- (tramp-shell-quote-argument tramp-end-of-output) shell)
+ vec (format
+ "exec env ENV='' PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s"
+ (tramp-shell-quote-argument tramp-end-of-output)
+ shell (or extra-args ""))
t))
+ (tramp-set-connection-property
+ (tramp-get-connection-process vec) "remote-shell" shell)
;; Setting prompts.
(tramp-send-command
vec (format "PS1=%s" (tramp-shell-quote-argument tramp-end-of-output)) t)
(defun tramp-find-shell (vec)
"Opens a shell on the remote host which groks tilde expansion."
- (unless (tramp-get-connection-property vec "remote-shell" nil)
- (let (shell)
- (with-current-buffer (tramp-get-buffer vec)
- (tramp-send-command vec "echo ~root" t)
- (cond
- ((or (string-match "^~root$" (buffer-string))
- ;; The default shell (ksh93) of OpenSolaris and Solaris
- ;; is buggy. We've got reports for "SunOS 5.10" and
- ;; "SunOS 5.11" so far.
- (string-match (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
- (tramp-get-connection-property vec "uname" "")))
- (setq shell
- (or (tramp-find-executable
- vec "bash" (tramp-get-remote-path vec) t t)
- (tramp-find-executable
- vec "ksh" (tramp-get-remote-path vec) t t)))
- (unless shell
- (tramp-error
- vec 'file-error
- "Couldn't find a shell which groks tilde expansion"))
- (tramp-message
- vec 5 "Starting remote shell `%s' for tilde expansion" shell)
- (tramp-open-shell vec shell))
+ (with-current-buffer (tramp-get-buffer vec)
+ (let ((default-shell
+ (or
+ (tramp-get-connection-property
+ (tramp-get-connection-process vec) "remote-shell" nil)
+ (tramp-get-method-parameter
+ (tramp-file-name-method vec) 'tramp-remote-shell)))
+ shell)
+ (setq shell
+ (with-connection-property vec "remote-shell"
+ ;; CCC: "root" does not exist always, see QNAP 459.
+ ;; Which check could we apply instead?
+ (tramp-send-command vec "echo ~root" t)
+ (if (or (string-match "^~root$" (buffer-string))
+ ;; The default shell (ksh93) of OpenSolaris and
+ ;; Solaris is buggy. We've got reports for
+ ;; "SunOS 5.10" and "SunOS 5.11" so far.
+ (string-match (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
+ (tramp-get-connection-property
+ vec "uname" "")))
+
+ (or (tramp-find-executable
+ vec "bash" (tramp-get-remote-path vec) t t)
+ (tramp-find-executable
+ vec "ksh" (tramp-get-remote-path vec) t t)
+ ;; Maybe it works at least for some other commands.
+ (prog1
+ default-shell
+ (tramp-message
+ vec 2
+ (concat
+ "Couldn't find a remote shell which groks tilde "
+ "expansion, using `%s'")
+ default-shell)))
+
+ default-shell)))
+
+ ;; Open a new shell if needed.
+ (unless (string-equal shell default-shell)
+ (tramp-message
+ vec 5 "Starting remote shell `%s' for tilde expansion" shell)
+ (tramp-open-shell vec shell))
- (t (tramp-message
- vec 5 "Remote `%s' groks tilde expansion, good"
- (tramp-set-connection-property
- vec "remote-shell"
- (tramp-get-method-parameter
- (tramp-file-name-method vec) 'tramp-remote-shell)))))))))
+ ;; Busyboxes tend to behave strange. We check for the existence.
+ (with-connection-property vec "busybox"
+ (tramp-send-command vec (format "%s --version" shell) t)
+ (let ((case-fold-search t))
+ (and (string-match "busybox" (buffer-string)) t))))))
;; Utility functions.
;; discarded as well.
(tramp-open-shell
vec
- (tramp-get-method-parameter
- (tramp-file-name-method vec) 'tramp-remote-shell))
+ (or (tramp-get-connection-property vec "remote-shell" nil)
+ (tramp-get-method-parameter
+ (tramp-file-name-method vec) 'tramp-remote-shell)))
;; Disable echo.
(tramp-message vec 5 "Setting up remote shell environment")
vec "uname"
(tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
(when (and (stringp old-uname) (not (string-equal old-uname new-uname)))
- (with-current-buffer (tramp-get-debug-buffer vec)
- ;; Keep the debug buffer.
- (rename-buffer
- (generate-new-buffer-name tramp-temp-buffer-name) 'unique)
- (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)))))
+ (tramp-cleanup 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
(tramp-set-remote-path vec)
;; Search for a good shell before searching for a command which
- ;; checks if a file exists. This is done because Tramp wants to use
+ ;; checks if a file exists. This is done because Tramp wants to use
;; "test foo; echo $?" to check if various conditions hold, and
;; there are buggy /bin/sh implementations which don't execute the
;; "echo $?" part if the "test" part has an error. In particular,
(b64 "recode data..base64" "recode base64..data")
(b64 tramp-perl-encode-with-module tramp-perl-decode-with-module)
(b64 tramp-perl-encode tramp-perl-decode)
- (uu "uuencode xxx" "uudecode -o /dev/stdout")
+ (uu "uuencode xxx" "uudecode -o /dev/stdout" "test -c /dev/stdout")
(uu "uuencode xxx" "uudecode -o -")
(uu "uuencode xxx" "uudecode -p")
(uu "uuencode xxx" tramp-uudecode)
"List of remote coding commands for inline transfer.
Each item is a list that looks like this:
-\(FORMAT ENCODING DECODING\)
+\(FORMAT ENCODING DECODING [TEST]\)
FORMAT is symbol describing the encoding/decoding format. It can be
`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing.
If they are variables, this variable is a string containing a Perl
implementation for this functionality. This Perl program will be transferred
-to the remote host, and it is available as shell function with the same name.")
+to the remote host, and it is available as shell function with the same name.
+
+The optional TEST command can be used for further tests, whether
+ENCODING and DECODING are applicable.")
(defun tramp-find-inline-encoding (vec)
"Find an inline transfer encoding that works.
(save-excursion
(let ((local-commands tramp-local-coding-commands)
(magic "xyzzy")
- loc-enc loc-dec rem-enc rem-dec litem ritem found)
+ (p (tramp-get-connection-process vec))
+ loc-enc loc-dec rem-enc rem-dec rem-test litem ritem found)
(while (and local-commands (not found))
(setq litem (pop local-commands))
(catch 'wont-work-local
(when (equal format (nth 0 ritem))
(setq rem-enc (nth 1 ritem))
(setq rem-dec (nth 2 ritem))
+ (setq rem-test (nth 3 ritem))
+ ;; Check the remote test command if exists.
+ (when (stringp rem-test)
+ (tramp-message
+ vec 5 "Checking remote test command `%s'" rem-test)
+ (unless (tramp-send-command-and-check vec rem-test t)
+ (throw 'wont-work-remote nil)))
;; Check if remote encoding and decoding commands can be
;; called remotely with null input and output. This makes
;; sure there are no syntax errors and the command is really
(tramp-error
vec 'file-error "Couldn't find an inline transfer encoding"))
- ;; Set connection properties.
+ ;; Set connection properties. Since the commands are risky (due
+ ;; to output direction), we cache them in the process cache.
(tramp-message vec 5 "Using local encoding `%s'" loc-enc)
- (tramp-set-connection-property vec "local-encoding" loc-enc)
+ (tramp-set-connection-property p "local-encoding" loc-enc)
(tramp-message vec 5 "Using local decoding `%s'" loc-dec)
- (tramp-set-connection-property vec "local-decoding" loc-dec)
+ (tramp-set-connection-property p "local-decoding" loc-dec)
(tramp-message vec 5 "Using remote encoding `%s'" rem-enc)
- (tramp-set-connection-property vec "remote-encoding" rem-enc)
+ (tramp-set-connection-property p "remote-encoding" rem-enc)
(tramp-message vec 5 "Using remote decoding `%s'" rem-dec)
- (tramp-set-connection-property vec "remote-decoding" rem-dec))))
+ (tramp-set-connection-property p "remote-decoding" rem-dec))))
(defun tramp-call-local-coding-command (cmd input output)
"Call the local encoding or decoding command.
(save-excursion
(let ((commands tramp-inline-compress-commands)
(magic "xyzzy")
- item compress decompress
- found)
+ (p (tramp-get-connection-process vec))
+ item compress decompress found)
(while (and commands (not found))
(catch 'next
(setq item (pop commands)
;; Did we find something?
(if found
(progn
- ;; Set connection properties.
+ ;; Set connection properties. Since the commands are
+ ;; risky (due to output direction), we cache them in the
+ ;; process cache.
(tramp-message
vec 5 "Using inline transfer compress command `%s'" compress)
- (tramp-set-connection-property vec "inline-compress" compress)
+ (tramp-set-connection-property p "inline-compress" compress)
(tramp-message
vec 5 "Using inline transfer decompress command `%s'" decompress)
- (tramp-set-connection-property vec "inline-decompress" decompress))
+ (tramp-set-connection-property p "inline-decompress" decompress))
- (tramp-set-connection-property vec "inline-compress" nil)
- (tramp-set-connection-property vec "inline-decompress" nil)
+ (tramp-set-connection-property p "inline-compress" nil)
+ (tramp-set-connection-property p "inline-decompress" nil)
(tramp-message
vec 2 "Couldn't find an inline transfer compress command")))))
"Expands VEC according to `tramp-default-proxies-alist'.
Gateway hops are already opened."
(let ((target-alist `(,vec))
- (choices tramp-default-proxies-alist)
- item proxy)
+ (hops (or (tramp-file-name-hop vec) ""))
+ (item vec)
+ choices proxy)
+
+ ;; Ad-hoc proxy definitions.
+ (dolist (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
+ (let ((user (tramp-file-name-user item))
+ (host (tramp-file-name-host item))
+ (proxy (concat
+ tramp-prefix-format proxy tramp-postfix-host-format)))
+ (tramp-message
+ vec 5 "Add proxy (\"%s\" \"%s\" \"%s\")"
+ (and (stringp host) (regexp-quote host))
+ (and (stringp user) (regexp-quote user))
+ proxy)
+ ;; Add the hop.
+ (add-to-list
+ 'tramp-default-proxies-alist
+ (list (and (stringp host) (regexp-quote host))
+ (and (stringp user) (regexp-quote user))
+ proxy))
+ (setq item (tramp-dissect-file-name proxy))))
+ ;; Save the new value.
+ (when (and hops tramp-save-ad-hoc-proxies)
+ (customize-save-variable
+ 'tramp-default-proxies-alist tramp-default-proxies-alist))
;; Look for proxy hosts to be passed.
+ (setq choices tramp-default-proxies-alist)
(while choices
(setq item (pop choices)
proxy (eval (nth 2 item)))
(when (and
- ;; host
+ ;; Host.
(string-match (or (eval (nth 0 item)) "")
(or (tramp-file-name-host (car target-alist)) ""))
- ;; user
+ ;; User.
(string-match (or (eval (nth 1 item)) "")
(or (tramp-file-name-user (car target-alist)) "")))
(if (null proxy)
'target-alist
(vector
(tramp-file-name-method hop) (tramp-file-name-user hop)
- (tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil))
+ (tramp-compat-funcall 'tramp-gw-open-connection vec gw hop) nil nil))
;; For the password prompt, we need the correct values.
;; Therefore, we must remember the gateway vector. But we
;; cannot do it as connection property, because it shouldn't
;; Result.
target-alist))
+(defvar tramp-current-connection nil
+ "Last connection timestamp.")
+
(defun tramp-maybe-open-connection (vec)
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
(process-environment (copy-sequence process-environment))
(pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
+ ;; If Tramp opens the same connection within a short time frame,
+ ;; there is a problem. We shall signal this.
+ (unless (or (and p (processp p) (memq (process-status p) '(run open)))
+ (not (equal (butlast (append vec nil))
+ (car tramp-current-connection)))
+ (> (tramp-time-diff
+ (current-time) (cdr tramp-current-connection))
+ 5))
+ (throw 'suppress 'suppress))
+
;; 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
;; The error will be caught locally.
(tramp-error vec 'file-error "Awake did fail")))
(file-error
- (tramp-flush-connection-property vec)
- (tramp-flush-connection-property p)
- (delete-process p)
+ (tramp-cleanup vec)
(setq p nil)))
;; New connection must be opened.
;; We call `tramp-get-buffer' in order to get a debug
;; buffer for messages from the beginning.
(tramp-get-buffer vec)
+
+ ;; If `non-essential' is non-nil, don't reopen a new connection.
+ (when (and (boundp 'non-essential) (symbol-value 'non-essential))
+ (throw 'non-essential 'non-essential))
+
(tramp-with-progress-reporter
vec 3
(if (zerop (length (tramp-file-name-user vec)))
(tramp-set-connection-property p "vector" vec)
(set-process-sentinel p 'tramp-process-sentinel)
(tramp-compat-set-process-query-on-exit-flag p nil)
+ (setq tramp-current-connection
+ (cons (butlast (append vec nil)) (current-time))
+ tramp-current-host (system-name))
(tramp-message
vec 6 "%s" (mapconcat 'identity (process-command p) " "))
(expand-file-name
tramp-temp-name-prefix
(tramp-compat-temporary-file-directory)))))
- spec)
+ spec r-shell)
;; Add arguments for asynchronous processes.
(when (and process-name async-args)
(setq l-port (match-string 2 l-host)
l-host (match-string 1 l-host)))
+ ;; Check, whether there is a restricted shell.
+ (dolist (elt tramp-restricted-shell-hosts-alist)
+ (when (string-match elt tramp-current-host)
+ (setq r-shell t)))
+
;; Set variables for computing the prompt for
;; reading password. They can also be derived
;; from a gateway.
(concat
;; We do not want to see the trailing local
;; prompt in `start-file-process'.
- (unless (memq system-type '(windows-nt)) "exec ")
+ (unless r-shell "exec ")
command " "
(mapconcat
(lambda (x)
login-args " ")
;; Local shell could be a Windows COMSPEC. It
;; doesn't know the ";" syntax, but we must exit
- ;; always for `start-file-process'. "exec" does
- ;; not work either.
- (if (memq system-type '(windows-nt)) " && exit || exit")))
+ ;; always for `start-file-process'. It could
+ ;; also be a restricted shell, which does not
+ ;; allow "exec".
+ (when r-shell " && exit || exit")))
;; Send the command.
(tramp-message vec 3 "Sending command `%s'" command)
;; When the user did interrupt, we must cleanup.
(quit
- (let ((p (tramp-get-connection-process vec)))
- (when (and p (processp p))
- (tramp-flush-connection-property vec)
- (tramp-flush-connection-property p)
- (delete-process p)))
+ (tramp-cleanup vec)
;; Propagate the quit signal.
(signal (car err) (cdr err)))))))
;; We mark the command string that it can be erased in the output buffer.
(tramp-set-connection-property p "check-remote-echo" t)
(setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark)))
- (when (string-match "<<'EOF'" command)
+ (when (and (string-match "<<'EOF'" command)
+ (not (tramp-get-connection-property vec "busybox" nil)))
;; Unset $PS1 when using here documents, in order to avoid
;; multiple prompts.
(setq command (concat "(PS1= ; " command "\n)")))
If no corresponding command is found, nil is returned."
(when (and (integerp tramp-inline-compress-start-size)
(> size tramp-inline-compress-start-size))
- (with-connection-property vec prop
+ (with-connection-property (tramp-get-connection-process vec) prop
(tramp-find-inline-compress vec)
- (tramp-get-connection-property vec prop nil))))
+ (tramp-get-connection-property
+ (tramp-get-connection-process vec) prop nil))))
(defun tramp-get-inline-coding (vec prop size)
"Return the coding command related to PROP.
;; no inline coding is found.
(ignore-errors
(let ((coding
- (with-connection-property vec prop
+ (with-connection-property (tramp-get-connection-process vec) prop
(tramp-find-inline-encoding vec)
- (tramp-get-connection-property vec prop nil)))
+ (tramp-get-connection-property
+ (tramp-get-connection-process vec) prop nil)))
(prop1 (if (string-match "encoding" prop)
"inline-compress" "inline-decompress"))
compress)