Re: tramp-hangs when command line exceeds 256 characters; MAX_CANON limit.

Stacey Marshall <[email protected]> Thu, 08 May 2025 13:40:10 +0100
Newsgroups gmane.emacs.tramp
Message-ID <[email protected]>
Sorry, I forgot to tell mail-mate.app I was sending text and not 
markdown.
This time as markdown then.

Cirlcing back to remote command execution command line length issue
seen with tramp upon connection to Solaris host.  Michael Albinus
observed the issue was due to a max line length of 256 characters.

-   [Re: tramp hangs opening a file, Emacs 30.1 tramp-version 
"2.7.1.30.1" 
an](https://lists.gnu.org/archive/html/tramp-devel/2025-04/msg00001.html)

Today I was wanting to use 
[Man-support-remote-systems](https://www.gnu.org/software/emacs/manual/html_node/emacs/Man-Page.html) 
to see Solaris
manual page within emacs running on Darmin (sequoia 15.4.1).  From the
debug buffer I could once again see the command being executed was
much longer than 256 characters, and the I/O buffer showing many ^G
characters. Which is what was also observed with the loooongish file
names issues.

Searching tramp-devel archive I came across [Re: tramp 2.26 emacs 24.3
plink](https://lists.gnu.org/archive/html/tramp-devel/2014-09/msg00041.html) 
which included a link to [Solaris limitation on command line -
Oracle 
Forums](https://forums.oracle.com/ords/apexds/post/solaris-limitation-on-command-line-9450)

Their testing showed that it wasn't down to shell input length, but
instead the setting of `MAX_CANON` (from limits.h):

     #define	MAX_CANON	256	/* max bytes in line for canonical processing 
*/

With a suggestion that `expect` script should include

     set stty_init raw

To which expect(1) states

> will cause further spawned processes's terminals to start in raw mode.

Looking at stty(1) **raw** on Solaris is:

     stty cs8 -icanon min 1 time 0 -isig -xcase -inpck -opost

Looking in tramp I see that `tramp-sh.el` runs `stty` a few times, and
nicely captures current settings to debug buffer too.  Of particular
note is `tramp-pipe-stty-setting`:

     (defcustom tramp-pipe-stty-settings "-icanon min 1 time 0"
       "How to prevent blocking read in pipeline processes.
     This is used in `make-process' with `connection-type' `pipe'."
       :group 'tramp
       :version "29.3"
       :type '(choice (const :tag "Use size limit" "-icanon min 1 time 
0")
     		 (const :tag "Use timeout" "-icanon min 0 time 1")
     		 string))

For a simple test then I modified `tramp-sh-handle-make-process` to
always apply it:

     $ git diff
     diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
     index 618fc386e58..3ecf92f7d28 100644
     --- a/lisp/net/tramp-sh.el
     +++ b/lisp/net/tramp-sh.el
     @@ -3115,7 +3115,7 @@ tramp-sh-handle-make-process
                             (let ((pid (tramp-send-command-and-read v 
"echo $$")))
                               (setq p (tramp-get-connection-process v))
                               (process-put p 'remote-pid pid))
     -                       (when (memq connection-type '(nil pipe))
     +;                      (when (memq connection-type '(nil pipe))
                               ;; Disable carriage return to newline
                               ;; translation.  This does not work on
                               ;; macOS, see Bug#50748.
     @@ -3137,7 +3137,8 @@ tramp-sh-handle-make-process
                                   "stty %s %s"
                                   (if (tramp-check-remote-uname v 
"Darwin")
                                       "" "-icrnl")
     -                             tramp-pipe-stty-settings)))
     +                             tramp-pipe-stty-settings))
     +;)
                             ;; `tramp-maybe-open-connection' and
                             ;; `tramp-send-command-and-read' could have
                             ;; trashed the connection buffer.  Remove

Evaluated that function, cleaned connections, accessed remote buffer and 
ran
man again, and it worked.

Clearly this is a limited test and I may well have broken something
else with these settings. Which from the manual page are:

-   **-icrnl:** do not map CR to NL on input.

-   **-icanon:** Disable canonical input (ERASE and KILL processing).  
Does
     not set MIN or TIME.

-   **`min number` / `time number`:** Set the value of min or time to 
number. MIN and TIME are used in
     Non-Canonical mode input processing (-icanon).

For the moment I shall carry-on and see what breaks, but hopefully
more of what works now!