Problem
runWithPTY in tailcat_ssh.go blocks on io.Copy(sess, ptmx) (stdout) before calling cmd.Wait(). If the shell does not exit immediately, the function never reaches cmd.Wait(), and the deferred ptmx.Close() never runs. The whole SSH session hangs.
This is the underlying issue that PR #8 fixes.
Reproduction
I added TestSSHSuite/PTYExitReturnsPromptly to exercise a short-lived interactive command through a PTY. Running it against main (commit c04c5afee) reproduces the hang:
// In tailcat_ssh_test.go, inside TestSSHSuite
{
name: "PTYExitReturnsPromptly",
run: func(t *testing.T, env *testSSHEnv) {
sess := env.newSession(t, true)
defer sess.Close()
if err := sess.Run("echo hello"); err != nil {
t.Fatalf("Run: %v", err)
}
if got := strings.TrimSpace(stdout.String()); got != "hello" {
t.Fatalf("stdout = %q, want hello", got)
}
},
}
Test run on main:
=== RUN TestSSHSuite/PTYExitReturnsPromptly
--- FAIL: TestSSHSuite (???) // test times out / hangs
Verification that PR #8 fixes it
Checking out PR #8 (commit bb7fc094e) and running the same test:
=== RUN TestSSHSuite/PTYExitReturnsPromptly
--- PASS: TestSSHSuite (2.34s)
Suggested fix
Apply the restructure from PR #8: run cmd.Wait() and the stdout io.Copy concurrently, cancel the window-resize goroutine and drain stdout when the command exits, and kill the shell when the client disconnects first. Also close the pty slave fd after cmd.Start and set tty = nil so deferred cleanup does not double-close it.
References
Problem
runWithPTYintailcat_ssh.goblocks onio.Copy(sess, ptmx)(stdout) before callingcmd.Wait(). If the shell does not exit immediately, the function never reachescmd.Wait(), and the deferredptmx.Close()never runs. The whole SSH session hangs.This is the underlying issue that PR #8 fixes.
Reproduction
I added
TestSSHSuite/PTYExitReturnsPromptlyto exercise a short-lived interactive command through a PTY. Running it againstmain(commitc04c5afee) reproduces the hang:Test run on
main:Verification that PR #8 fixes it
Checking out PR #8 (commit
bb7fc094e) and running the same test:Suggested fix
Apply the restructure from PR #8: run
cmd.Wait()and the stdoutio.Copyconcurrently, cancel the window-resize goroutine and drain stdout when the command exits, and kill the shell when the client disconnects first. Also close the pty slave fd aftercmd.Startand settty = nilso deferred cleanup does not double-close it.References
main@c04c5afeebb7fc094e