1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Fix Tramp bug#78508

* lisp/net/tramp-container.el (tramp-methods) <docker, dockercp, podman>
<podmancp, apptainer, nspawn>:
* lisp/net/tramp-sh.el (tramp-methods) <scp, scpx, rsync>
<ssh, sshx, sudo>:
* lisp/net/tramp-sshfs.el (tramp-methods) <sshfs>: Set TERM environment.
(Bug#78508)

* lisp/net/tramp-sh.el (tramp-find-executable): Handle superlong PATH.
(tramp-set-remote-path): Simplify command.
(tramp-timeout-session): Add ;;;###tramp-autoload cookie.

* lisp/net/tramp-smb.el (tramp-smb-errors): Add string.
(tramp-smb-winexe-program): Adapt docstring.
(tramp-smb-handle-copy-directory, tramp-smb-handle-file-acl)
(tramp-smb-handle-set-file-acl, tramp-smb-maybe-open-connection):
Simplify argument handling.
(tramp-smb-handle-process-file): Flush " process-exit-status" property.
(tramp-smb-call-winexe): Set $winsize.Width to 102 only.

* lisp/net/tramp.el (tramp-process-sentinel): Adapt docstring.
Set " process-exit-status" property.

* test/lisp/net/tramp-tests.el (tramp--test-enabled):
Make it more robust.
(tramp-test18-file-attributes)
(tramp-test26-interactive-file-name-completion)
(tramp-test26-file-name-completion-boundaries)
(tramp-test35-remote-path): Adapt tests.
This commit is contained in:
Michael Albinus 2025-05-31 15:08:06 +02:00
parent b247b1e0b1
commit 5ce0e1372b
7 changed files with 158 additions and 88 deletions

View file

@ -713,5 +713,7 @@ for all methods. Resulting data are derived from connection history."
;;; TODO:
;;
;; * Use multisession.el, starting with Emacs 29.1.
;;
;; Use `with-memoization', starting with Emacs 29.1.
;;; tramp-cache.el ends here

View file

@ -551,6 +551,7 @@ see its function help for a description of the format."
(tramp-login-args (("exec")
("-it")
("-u" "%u")
("-e" ,(format "TERM=%s" tramp-terminal-type))
("%h")
("%l")))
(tramp-direct-async (,tramp-default-remote-shell "-c"))
@ -565,6 +566,7 @@ see its function help for a description of the format."
(tramp-login-args (("exec")
("-it")
("-u" "%u")
("-e" ,(format "TERM=%s" tramp-terminal-type))
("%h")
("%l")))
(tramp-direct-async (,tramp-default-remote-shell "-c"))
@ -583,6 +585,7 @@ see its function help for a description of the format."
(tramp-login-args (("exec")
("-it")
("-u" "%u")
("-e" ,(format "TERM=%s" tramp-terminal-type))
("%h")
("%l")))
(tramp-direct-async (,tramp-default-remote-shell "-c"))
@ -597,6 +600,7 @@ see its function help for a description of the format."
(tramp-login-args (("exec")
("-it")
("-u" "%u")
("-e" ,(format "TERM=%s" tramp-terminal-type))
("%h")
("%l")))
(tramp-direct-async (,tramp-default-remote-shell "-c"))
@ -754,6 +758,8 @@ see its function help for a description of the format."
`(,tramp-apptainer-method
(tramp-login-program ,tramp-apptainer-program)
(tramp-login-args (("shell")
("--env"
,(format "TERM=%s" tramp-terminal-type))
("instance://%h")
("%h"))) ; Needed for multi-hop check.
(tramp-remote-shell ,tramp-default-remote-shell)
@ -777,6 +783,8 @@ see its function help for a description of the format."
(tramp-login-args (("shell")
("-q")
("--uid" "%u")
("-E"
,(format "TERM=%s" tramp-terminal-type))
("%h")))
(tramp-remote-shell ,tramp-default-remote-shell)
(tramp-remote-shell-login ("-l"))

View file

@ -190,7 +190,10 @@ The string is used in `tramp-methods'.")
`("scp"
(tramp-login-program "ssh")
(tramp-login-args (("-l" "%u") ("-p" "%p") ("%c")
("-e" "none") ("%h")))
("-e" "none")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("%h")))
(tramp-async-args (("-q")))
(tramp-direct-async ("-t" "-t"))
(tramp-remote-shell ,tramp-default-remote-shell)
@ -208,6 +211,8 @@ The string is used in `tramp-methods'.")
(tramp-login-args (("-l" "%u") ("-p" "%p") ("%c")
("-e" "none") ("-t" "-t")
("-o" "RemoteCommand=\"%l\"")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("%h")))
(tramp-async-args (("-q")))
(tramp-remote-shell ,tramp-default-remote-shell)
@ -223,7 +228,10 @@ The string is used in `tramp-methods'.")
`("rsync"
(tramp-login-program "ssh")
(tramp-login-args (("-l" "%u") ("-p" "%p") ("%c")
("-e" "none") ("%h")))
("-e" "none")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("%h")))
(tramp-async-args (("-q")))
(tramp-direct-async t)
(tramp-remote-shell ,tramp-default-remote-shell)
@ -254,7 +262,10 @@ The string is used in `tramp-methods'.")
`("ssh"
(tramp-login-program "ssh")
(tramp-login-args (("-l" "%u") ("-p" "%p") ("%c")
("-e" "none") ("%h")))
("-e" "none")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("%h")))
(tramp-async-args (("-q")))
(tramp-direct-async ("-t" "-t"))
(tramp-remote-shell ,tramp-default-remote-shell)
@ -265,6 +276,8 @@ The string is used in `tramp-methods'.")
(tramp-login-program "ssh")
(tramp-login-args (("-l" "%u") ("-p" "%p") ("%c")
("-e" "none") ("-t" "-t")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("-o" "RemoteCommand=\"%l\"")
("%h")))
(tramp-async-args (("-q")))
@ -301,6 +314,7 @@ The string is used in `tramp-methods'.")
;; remote host echoes the command.
;; The "-p" argument doesn't work reliably, see Bug#50594.
(tramp-login-args (("SUDO_PROMPT=P\"\"a\"\"s\"\"s\"\"w\"\"o\"\"r\"\"d\"\":")
(,(format "TERM=%s" tramp-terminal-type))
("sudo") ("-u" "%u") ("-s") ("-H")
("%l")))
(tramp-remote-shell ,tramp-default-remote-shell)
@ -4123,12 +4137,33 @@ This function expects to be in the right *tramp* buffer."
(unless (char-equal ?~ (aref d 0))
(setq newdl (cons d newdl))))
(setq dirlist (nreverse newdl))))
(when (tramp-send-command-and-check
vec (format "(unalias %s; %s command -v %s)"
progname
(if dirlist (concat "PATH=" (string-join dirlist ":")) "")
progname))
(string-trim (tramp-get-buffer-string (tramp-get-connection-buffer vec)))))
(let ((command
(concat
(when dirlist (format "PATH=%s " (string-join dirlist ":")))
"command -v " progname))
(pipe-buf (tramp-get-remote-pipe-buf vec))
tmpfile chunk chunksize)
(when (if (length< command pipe-buf)
(tramp-send-command-and-check vec command)
;; Use a temporary file. We cannot use `write-region'
;; because setting the remote path happens in the early
;; connection handshake, and not all external tools are
;; determined yet.
(setq command (concat command "\n")
tmpfile (tramp-make-tramp-temp-file vec))
(while (not (string-empty-p command))
(setq chunksize (min (length command) (/ pipe-buf 2))
chunk (substring command 0 chunksize)
command (substring command chunksize))
(tramp-send-command
vec (format "printf \"%%b\" \"$*\" %s >>%s"
(tramp-shell-quote-argument chunk)
(tramp-shell-quote-argument tmpfile))))
(tramp-send-command-and-check
vec (format ". %s && rm -f %s" tmpfile tmpfile)))
(string-trim
(tramp-get-buffer-string (tramp-get-connection-buffer vec))))))
;; On hydra.nixos.org, the $PATH environment variable is too long to
;; send it. This is likely not due to PATH_MAX, but PIPE_BUF. We
@ -4162,12 +4197,11 @@ variable PATH."
(setq chunksize (min (length command) (/ pipe-buf 2))
chunk (substring command 0 chunksize)
command (substring command chunksize))
(tramp-send-command vec (format
"printf \"%%b\" \"$*\" %s >>%s"
(tramp-shell-quote-argument chunk)
(tramp-shell-quote-argument tmpfile))))
(tramp-send-command vec (format ". %s" tmpfile))
(tramp-send-command vec (format "rm -f %s" tmpfile))))))
(tramp-send-command
vec (format "printf \"%%b\" \"$*\" %s >>%s"
(tramp-shell-quote-argument chunk)
(tramp-shell-quote-argument tmpfile))))
(tramp-send-command vec (format ". %s && rm -f %s" tmpfile tmpfile))))))
;; ------------------------------------------------------------
;; -- Communication with external shell --
@ -5108,6 +5142,7 @@ Goes through the list `tramp-inline-compress-commands'."
(t "-3")))
;;;###tramp-autoload
(defun tramp-timeout-session (vec)
"Close the connection VEC after a session timeout.
If there is just some editing, retry it after 5 seconds."

View file

@ -162,6 +162,7 @@ this variable \"client min protocol=NT1\"."
"NT_STATUS_PASSWORD_MUST_CHANGE"
"NT_STATUS_RESOURCE_NAME_NOT_FOUND"
"NT_STATUS_REVISION_MISMATCH"
"NT_STATUS_RPC_SS_CONTEXT_MISMATCH"
"NT_STATUS_SHARING_VIOLATION"
"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE"
"NT_STATUS_UNSUCCESSFUL"
@ -316,7 +317,7 @@ Operations not mentioned here will be handled by the default Emacs primitives.")
;; Options for remote processes via winexe.
(defcustom tramp-smb-winexe-program "winexe"
"Name of winexe client to run.
If it isn't found in the local $PATH, the absolute path of winexe
If it isn't found in the local $PATH, the absolute path of \"winexe\"
shall be given. This is needed for remote processes."
:group 'tramp
:version "24.3"
@ -488,12 +489,13 @@ arguments to pass to the OPERATION."
(args (list (concat "//" host "/" share) "-E"))
(options tramp-smb-options))
(if (tramp-string-empty-or-nil-p user)
(setq args (append args (list "-N")))
(setq args (append args (list "-U" user))))
(setq args
(append args
(if (tramp-string-empty-or-nil-p user)
(list "-N")
(list "-U" (if domain (concat domain "/" user) user)))
(when port (list "-p" port))))
(when domain (setq args (append args (list "-W" domain))))
(when port (setq args (append args (list "-p" port))))
(when tramp-smb-conf
(setq args (append args (list "-s" tramp-smb-conf))))
(while options
@ -779,12 +781,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(args (list (concat "//" host "/" share) "-E"))
(options tramp-smb-options))
(if (tramp-string-empty-or-nil-p user)
(setq args (append args (list "-N")))
(setq args (append args (list "-U" user))))
(setq args
(append args
(if (tramp-string-empty-or-nil-p user)
(list "-N")
(list "-U" (if domain (concat domain "/" user) user)))
(when port (list "-p" port))))
(when domain (setq args (append args (list "-W" domain))))
(when port (setq args (append args (list "-p" port))))
(when tramp-smb-conf
(setq args (append args (list "-s" tramp-smb-conf))))
(while options
@ -1251,6 +1254,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(tramp-set-connection-property
v " process-buffer"
(or outbuf (generate-new-buffer tramp-temp-buffer-name)))
(tramp-flush-connection-property v " process-exit-status")
(with-current-buffer (tramp-get-connection-buffer v)
;; Preserve buffer contents.
(narrow-to-region (point-max) (point-max))
@ -1366,12 +1370,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(string-replace "\n" "," acl-string)))
(options tramp-smb-options))
(if (tramp-string-empty-or-nil-p user)
(setq args (append args (list "-N")))
(setq args (append args (list "-U" user))))
(setq args
(append args
(if (tramp-string-empty-or-nil-p user)
(list "-N")
(list "-U" (if domain (concat domain "/" user) user)))
(when port (list "-p" port))))
(when domain (setq args (append args (list "-W" domain))))
(when port (setq args (append args (list "-p" port))))
(when tramp-smb-conf
(setq args (append args (list "-s" tramp-smb-conf))))
(while options
@ -1906,16 +1911,19 @@ If ARGUMENT is non-nil, use it as argument for
(share (setq args (list (concat "//" host "/" share))))
(t (setq args (list "-g" "-L" host ))))
(if (tramp-string-empty-or-nil-p user)
(setq args (append args (list "-N")))
(setq args (append args (list "-U" user))))
(setq args
(append args
(if (tramp-string-empty-or-nil-p user)
(list "-N")
(list "-U" (if domain (concat domain "/" user) user)))
(when port (list "-p" port))))
(when domain (setq args (append args (list "-W" domain))))
(when port (setq args (append args (list "-p" port))))
(when tramp-smb-conf
(setq args (append args (list "-s" tramp-smb-conf))))
(dolist (option options)
(setq args (append args (list "--option" option))))
;; For debugging.
(setq args (append args (list "-d" "1")))
(when argument
(setq args (append args (list argument))))
@ -2026,6 +2034,8 @@ Removes smb prompt. Returns nil if an error message has appeared."
(when (tramp-file-name-port vec)
(tramp-error vec 'file-error "Port not supported for remote processes"))
;; In case of "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", the remote server
;; is a Samba server. winexe cannot install the respective service there.
(tramp-smb-maybe-open-connection
vec
(format
@ -2037,12 +2047,14 @@ Removes smb prompt. Returns nil if an error message has appeared."
;; Suppress "^M". Shouldn't we specify utf8?
(set-process-coding-system (tramp-get-connection-process vec) 'raw-text-dos)
;; Set width to 128. This avoids mixing prompt and long error messages.
;; Set width to 128 ($bufsize.Width) or 102 ($winsize.Width),
;; respectively. $winsize.Width cannot be larger. This avoids
;; mixing prompt and long error messages.
(tramp-smb-send-command vec "$rawui = (Get-Host).UI.RawUI")
(tramp-smb-send-command vec "$bufsize = $rawui.BufferSize")
(tramp-smb-send-command vec "$winsize = $rawui.WindowSize")
(tramp-smb-send-command vec "$bufsize.Width = 128")
(tramp-smb-send-command vec "$winsize.Width = 128")
(tramp-smb-send-command vec "$winsize.Width = 102")
(tramp-smb-send-command vec "$rawui.BufferSize = $bufsize")
(tramp-smb-send-command vec "$rawui.WindowSize = $winsize"))
@ -2069,5 +2081,7 @@ Removes smb prompt. Returns nil if an error message has appeared."
;; several places, especially in `tramp-smb-handle-insert-directory'.
;;
;; * Keep a separate connection process per share.
;;
;; * Keep a permanent connection process for `process-file'.
;;; tramp-smb.el ends here

View file

@ -62,6 +62,8 @@
(tramp-login-program "ssh")
(tramp-login-args (("-q") ("-l" "%u") ("-p" "%p")
("-e" "none") ("%a" "%a")
("-o" ,(format "SetEnv=\"TERM=%s\""
tramp-terminal-type))
("%h") ("%l")))
(tramp-direct-async t)
(tramp-remote-shell ,tramp-default-remote-shell)

View file

@ -6255,15 +6255,22 @@ the remote host use line-endings as defined in the variable
(process-send-string p string)))))))
(defun tramp-process-sentinel (proc event)
"Flush file caches and remove shell prompt."
"Flush file caches and remove shell prompt.
Set exit status of PROC as connection property \" process-exit-status\"."
(unless (process-live-p proc)
(let ((vec (process-get proc 'tramp-vector))
(buf (process-buffer proc))
(prompt (tramp-get-connection-property proc "prompt")))
(when vec
(tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
(tramp-message
vec 5 "Sentinel called: `%S' event: `%s' status: %s"
proc event (process-exit-status proc))
(tramp-flush-connection-properties proc)
(tramp-flush-directory-properties vec "/"))
(tramp-flush-directory-properties vec "/")
;; Sometimes, the process has been deleted already before we
;; can retrieve the exit status.
(tramp-set-connection-property
vec " process-exit-status" (process-exit-status proc)))
(when (buffer-live-p buf)
(with-current-buffer buf
(when (and prompt (tramp-search-regexp (rx (literal prompt))))

View file

@ -278,9 +278,10 @@ being the result.")
(| "rclone" "sshfs") ".")
(file-name-nondirectory file)))
(tramp--test-message "Delete %s" file)
(if (file-directory-p file)
(delete-directory file 'recursive)
(delete-file file))))))
(ignore-errors ;; Wrong permissions?
(if (file-directory-p file)
(delete-directory file 'recursive)
(delete-file file)))))))
;; Cleanup connection.
(tramp-cleanup-connection tramp-test-vec nil 'keep-password))
@ -3761,11 +3762,7 @@ This tests also `access-file', `file-readable-p',
(tmp-name2 (tramp--test-make-temp-name nil quoted))
;; File name with "//".
(tmp-name3
(format
"%s%s"
(file-remote-p tmp-name1)
(replace-regexp-in-string
"/" "//" (file-remote-p tmp-name1 'localname))))
(replace-regexp-in-string "/" "//" (file-local-name tmp-name1)))
;; `file-ownership-preserved-p' is implemented only in tramp-sh.el.
(test-file-ownership-preserved-p (tramp--test-sh-p))
attr)
@ -3887,28 +3884,13 @@ This tests also `access-file', `file-readable-p',
;; symlinked files to a non-existing or cyclic target.
(when test-file-ownership-preserved-p
(should (file-ownership-preserved-p tmp-name2 'group)))
(delete-file tmp-name2)))
(delete-file tmp-name2))
;; Check, that "//" in symlinks are handled properly.
(with-temp-buffer
(let ((default-directory ert-remote-temporary-file-directory))
(shell-command
(format
"ln -s %s %s"
(tramp-file-name-localname
(tramp-dissect-file-name tmp-name3))
(tramp-file-name-localname
(tramp-dissect-file-name tmp-name2)))
t)))
(when (file-symlink-p tmp-name2)
;; Check, that "//" in symlinks are handled properly.
(make-symbolic-link tmp-name3 tmp-name2)
(should (file-symlink-p tmp-name2))
(setq attr (file-attributes tmp-name2))
(should
(string-equal
(file-attribute-type attr)
(funcall
(if (tramp--test-sshfs-p) #'file-name-nondirectory #'identity)
(tramp-file-name-localname
(tramp-dissect-file-name tmp-name3)))))
(should (string-equal (file-attribute-type attr) tmp-name3))
(delete-file tmp-name2))
(when test-file-ownership-preserved-p
@ -5164,7 +5146,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; (tramp--test-message "%s" (tramp-get-buffer-string trace-buffer))
;; (untrace-function #'tramp-completion-file-name-handler)
;; (untrace-function #'completion-file-name-table)
(tramp-change-syntax orig-syntax))))
(tramp-change-syntax orig-syntax)
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password))))
(defun tramp--test-split-on-boundary (s)
"Return completion boundaries for string S."
@ -5177,15 +5160,12 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; boundaries are always incorrect before that.
(skip-unless (tramp--test-emacs31-p))
(should (equal (tramp--test-split-on-boundary "/ssh:user@host:foo")
'("/ssh:user@host:" . "foo")))
(should (equal (tramp--test-split-on-boundary "/ssh:user@host:/~/foo")
'("/ssh:user@host:/~/" . "foo")))
(should (equal (tramp--test-split-on-boundary "/ssh:user@host:/usr//usr/foo")
'("/ssh:user@host:/usr//usr/" . "foo")))
(should (equal (tramp--test-split-on-boundary
"/ssh:user@host:/ssh:user@host://usr/foo")
'("/ssh:user@host:/ssh:user@host://usr/" . "foo"))))
(let ((remote (file-remote-p ert-remote-temporary-file-directory)))
(dolist
(file `(,remote ,(concat remote "/~/")
,(concat remote "/usr//usr/") ,(concat remote remote "//usr/")))
(should (equal (tramp--test-split-on-boundary (concat file "foo"))
`(,file . "foo"))))))
(ert-deftest tramp-test27-load ()
"Check `load'."
@ -6511,6 +6491,7 @@ INPUT, if non-nil, is a string sent to the process."
(file-remote-p default-directory 'localname)))
;; The shell "sh" shall always exist.
(should (executable-find "sh" 'remote))
;; Since the last element in `exec-path' is the current
;; directory, an executable file in that directory will be
;; found.
@ -6539,19 +6520,19 @@ INPUT, if non-nil, is a string sent to the process."
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-crypt-p)))
(let* ((tmp-name (tramp--test-make-temp-name))
(let* ((tmp-name1 (tramp--test-make-temp-name))
(default-directory ert-remote-temporary-file-directory)
(orig-exec-path (exec-path))
(tramp-remote-path tramp-remote-path)
(orig-tramp-remote-path tramp-remote-path)
path)
tmp-name2 path)
;; The "flatpak" method modifies `tramp-remote-path'.
(skip-unless (not (tramp-compat-connection-local-p tramp-remote-path)))
(unwind-protect
(progn
;; Non existing directories are removed.
(setq tramp-remote-path
(cons (file-remote-p tmp-name 'localname) tramp-remote-path))
(cons (file-remote-p tmp-name1 'localname) tramp-remote-path))
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(should (equal (exec-path) orig-exec-path))
(setq tramp-remote-path orig-tramp-remote-path)
@ -6564,11 +6545,11 @@ INPUT, if non-nil, is a string sent to the process."
;; We make a super long `tramp-remote-path'.
(unless (tramp--test-container-oob-p)
(make-directory tmp-name)
(should (file-directory-p tmp-name))
(make-directory tmp-name1)
(should (file-directory-p tmp-name1))
(while (length< (string-join orig-exec-path ":") 5000)
(let ((dir (make-temp-file
(file-name-as-directory tmp-name) 'dir)))
(file-name-as-directory tmp-name1) 'dir)))
(should (file-directory-p dir))
(setq tramp-remote-path
(append
@ -6591,12 +6572,33 @@ INPUT, if non-nil, is a string sent to the process."
(should
(string-equal path (string-join (butlast orig-exec-path) ":"))))
;; The shell "sh" shall always exist.
(should (executable-find "sh" 'remote))))
(should (executable-find "sh" 'remote))
;; Since the last element in `exec-path' is the current
;; directory, an executable file in that directory will be
;; found.
(setq tmp-name2
(expand-file-name
"foo"
(concat (file-remote-p default-directory)
(car (last orig-exec-path 2)))))
(write-region "foo" nil tmp-name2)
(should (file-exists-p tmp-name2))
(set-file-modes tmp-name2 #o777)
(should (file-executable-p tmp-name2))
(should
(string-equal
(executable-find (file-name-nondirectory tmp-name2) 'remote)
(file-remote-p tmp-name2 'localname)))
(should-not
(executable-find
(concat (file-name-nondirectory tmp-name2) "foo") 'remote))))
;; Cleanup.
(ignore-errors (delete-directory tmp-name1 'recursive))
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(setq tramp-remote-path orig-tramp-remote-path)
(ignore-errors (delete-directory tmp-name 'recursive)))))
(setq tramp-remote-path orig-tramp-remote-path))))
(tramp--test-deftest-direct-async-process tramp-test35-remote-path)