From 14d295871a93c37a33d558ec4e8d49a93b787d8e Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Mon, 5 Apr 2021 19:37:30 +0200 Subject: [PATCH] Use powershell for Tramp on MS Windows * lisp/net/tramp-sh.el (tramp-use-ssh-controlmaster-options): Nil on MS Windows. (tramp-connection-properties): Add "encoding-shell". (tramp-maybe-open-connection): Use it. Change exit handling. (tramp-actions-before-shell): Add `tramp-no-job-control-regexp'. * lisp/net/tramp.el (tramp-methods): Adapt docstring. (tramp-no-job-control-regexp): New defcustom. (tramp-get-debug-buffer): Set coding system. --- lisp/net/tramp-sh.el | 37 ++++++++++++++++++++++--------------- lisp/net/tramp.el | 25 ++++++++++++++++++------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index c3e1745d2f2..499bf8abe41 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -103,12 +103,12 @@ detected as prompt when being sent on echoing hosts, therefore.") (defconst tramp-end-of-heredoc (md5 tramp-end-of-output) "String used to recognize end of heredoc strings.") -(defcustom tramp-use-ssh-controlmaster-options t +(defcustom tramp-use-ssh-controlmaster-options (not (eq system-type 'windows-nt)) "Whether to use `tramp-ssh-controlmaster-options'. Set it to nil, if you use Control* or Proxy* options in your ssh configuration." :group 'tramp - :version "24.4" + :version "28.1" :type 'boolean) (defvar tramp-ssh-controlmaster-options nil @@ -389,7 +389,14 @@ The string is used in `tramp-methods'.") (regexp-opt '("rcp" "remcp" "rsh" "telnet" "nc" "krlogin" "fcp")) "\\'") - nil ,(user-login-name)))) + nil ,(user-login-name))) + + ;; MS Windows Openssh client does not cooperate well with cmdproxy. + (when-let ((encoding-shell + (and (eq system-type 'windows-nt) (executable-find "powershell")))) + (add-to-list 'tramp-connection-properties + `(,(regexp-opt '("/sshx:" "/scpx:")) + "encoding-shell" ,encoding-shell)))) ;;;###tramp-autoload (defconst tramp-completion-function-alist-rsh @@ -484,6 +491,7 @@ shell from reading its init file." '((tramp-login-prompt-regexp tramp-action-login) (tramp-password-prompt-regexp tramp-action-password) (tramp-wrong-passwd-regexp tramp-action-permission-denied) + (tramp-no-job-control-regexp tramp-action-permission-denied) (shell-prompt-pattern tramp-action-succeed) (tramp-shell-prompt-pattern tramp-action-succeed) (tramp-yesno-prompt-regexp tramp-action-yesno) @@ -4857,8 +4865,6 @@ connection if a previous connection has died for some reason." (setenv "HISTSIZE" "0")))) (setenv "PROMPT_COMMAND") (setenv "PS1" tramp-initial-end-of-output) - (unless (stringp tramp-encoding-shell) - (tramp-error vec 'file-error "`tramp-encoding-shell' not set")) (let* ((current-host tramp-system-name) (target-alist (tramp-compute-multi-hops vec)) ;; We will apply `tramp-ssh-controlmaster-options' @@ -4870,17 +4876,23 @@ connection if a previous connection has died for some reason." ;; W32 systems. (process-coding-system-alist nil) (coding-system-for-read nil) - (extra-args (tramp-get-sh-extra-args tramp-encoding-shell)) + (encoding-shell + (tramp-get-connection-property + vec "encoding-shell" tramp-encoding-shell)) + (extra-args (tramp-get-sh-extra-args encoding-shell)) ;; This must be done in order to avoid our file ;; name handler. (p (let ((default-directory (tramp-compat-temporary-file-directory))) + (unless (stringp encoding-shell) + (tramp-error + vec 'file-error "`tramp-encoding-shell' not set")) (apply #'start-process (tramp-get-connection-name vec) (tramp-get-connection-buffer vec) (append - (list tramp-encoding-shell) + (list encoding-shell) (and extra-args (split-string extra-args)) (and tramp-encoding-command-interactive (list tramp-encoding-command-interactive))))))) @@ -4899,8 +4911,7 @@ connection if a previous connection has died for some reason." ;; Check whether process is alive. (tramp-barf-if-no-shell-prompt - p 10 - "Couldn't find local shell prompt for %s" tramp-encoding-shell) + p 10 "Couldn't find local shell prompt for %s" encoding-shell) ;; Now do all the connections as specified. (while target-alist @@ -4974,12 +4985,8 @@ connection if a previous connection has died for some reason." ?h (or l-host "") ?u (or l-user "") ?p (or l-port "") ?c (format-spec options (format-spec-make ?t tmpfile)) ?l (concat remote-shell " " extra-args " -i")) - ;; Local shell could be a Windows COMSPEC. It - ;; doesn't know the ";" syntax, but we must - ;; exit always for `start-file-process'. It - ;; could also be a restricted shell, which does - ;; not allow "exec". - (when r-shell '("&&" "exit" "||" "exit"))) + ;; A restricted shell does not allow "exec". + (when r-shell '("; exit"))) " ")) ;; Send the command. diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 8141f026f74..99955b54598 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -354,12 +354,13 @@ Notes: All these arguments can be overwritten by connection properties. See Info node `(tramp) Predefined connection information'. -When using `su' or `sudo' the phrase \"open connection to a remote -host\" sounds strange, but it is used nevertheless, for consistency. -No connection is opened to a remote host, but `su' or `sudo' is -started on the local host. You should specify a remote host -`localhost' or the name of the local host. Another host name is -useful only in combination with `tramp-default-proxies-alist'.") +When using `su', `sudo' or `doas' the phrase \"open connection to +a remote host\" sounds strange, but it is used nevertheless, for +consistency. No connection is opened to a remote host, but `su', +`sudo' or `doas' is started on the local host. You should +specify a remote host `localhost' or the name of the local host. +Another host name is useful only in combination with +`tramp-default-proxies-alist'.") (defcustom tramp-default-method ;; An external copy method seems to be preferred, because it performs @@ -690,6 +691,15 @@ The regexp should match at end of buffer." :version "27.1" :type 'regexp) +;; Powershell requires "ssh -t -t" for terminal emulation. If it +;; doesn't fit, there is an error. +(defcustom tramp-no-job-control-regexp + (regexp-quote "Thus no job control in this shell.") + "Regular expression matching powershell's job control message. +The regexp should match at end of buffer." + :version "28.1" + :type 'regexp) + (defcustom tramp-operation-not-permitted-regexp (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*" (regexp-opt '("Operation not permitted") t)) @@ -1808,6 +1818,7 @@ The outline level is equal to the verbosity of the Tramp message." "Get the debug buffer for VEC." (with-current-buffer (get-buffer-create (tramp-debug-buffer-name vec)) (when (bobp) + (set-buffer-file-coding-system 'utf-8) (setq buffer-undo-list t) ;; Activate `outline-mode'. This runs `text-mode-hook' and ;; `outline-mode-hook'. We must prevent that local processes @@ -1848,7 +1859,7 @@ ARGUMENTS to actually emit the message (if applicable)." (when (bobp) (insert (format - ";; Emacs: %s Tramp: %s -*- mode: outline; -*-" + ";; Emacs: %s Tramp: %s -*- mode: outline; coding: utf-8; -*-" emacs-version tramp-version)) (when (>= tramp-verbose 10) (let ((tramp-verbose 0)) -- 2.39.5