0

I am confused about what ssh -t does and why I will sometimes need the -t option. My understanding is that if I run ssh -t program, ssh is forced to allocate a pseudo tty, with which it passes the keyboard input to program's and passes the program's output to stdout.

But it seems I am wrong. For example, the following two seem to function identically as I can operate interactively with rclone using either one, even though the first command forces it to allocate a pseudo tty and the second command forces it not to allocate a pseudo tty:

  1. ssh -t user@my.server.com rclone config
  2. ssh -T user@my.server.com rclone config

So what does ssh -t actually do?

Update:

To illuminate this question further, I made the following python script called hello.py.

import sys, signal

def signal_handler(sig, frame): print('You pressed Ctrl+C!') sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

print(f"stdin is tty:{sys.stdin.isatty()}") print(f"stdout is tty:{sys.stdout.isatty()}")

s = input("Enter what you want:") print("Hello ", s)

On a remote machine, if I invoke it as ssh -t user@server.com "python hello.py", I get the following output:

stdin is tty: true
stdout is tty: true
Enter what you want: cat
Hello cat

If I invoke it as ssh -T user@server.com "python hello.py", I get the following:

stdin is tty: false
stdout is tty: false
Enter what you want: cat
Hello cat

In either case, I am able to interact with the program by typing in "cat" from the keyboard.

One difference I observe is that when I press CTRL-C, the -t version captures SIGINT but the -T version does not.

I'm curious why I can still interact with it even if stdin/stdout is not a tty. Also, isatty() is in fact a standard C library function. What does a (pseudo) TTY really mean here?

1 Answers1

1

ssh is forced to allocate a pseudo tty, with which it passes the keyboard input to program's and passes the program's output to stdout.

It does that, but a pseudo tty is not necessary for stdin/stdout to work. That can also be achieved using plain pipes. When you run ssh -T, the remote program's input and output are connected to sshd using anonymous pipes.

There are other functions that a tty does, however – it provides input and output translation (e.g. LF to CRLF, or Ctrl-C to the SIGINT signal), it has a concept of 'dimensions' (width × height are stored as tty parameters). The kernel also keeps specific track of processes attached to a particular tty so that job control (as in Ctrl-Z in the shell) could be implemented, as well as SIGHUP when sshd exits and the tty is "hung up" or SIGWINCH when the dimensions change.

(And since an interactive terminal means having a tty, many programs also check for the presence of a tty on stdin to determine whether to run in interactive mode or not. For example, you can run Bash without a tty, but – aside from not being able to perform job-control – it will also decide to disable its line-editing features and to use an empty 'prompt' by default. The buffered I/O of runtimes like Glibc fwrite() will check for a tty to know whether to buffer line-by-line for interactive output, or in large batches for file/pipe output.)

Use -t when you want to run a terminal-oriented program such as htop, and -T when you want a "clean" 8-bit channel for transferring binary data. (Generally the only time an explicit -T is needed is when the remote side has a forced command.)

grawity
  • 17,092