2

I'm trying to understand ssh's -t option:

-t Force pseudo-terminal allocation. This can be used to execute arbitrary screen- based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

So, TTY is a device. A way to refer to a TTY is by descriptor (which is obtained by opening the TTY device). STDIN, STDOUT and STDERR are descriptors. But they do not necessarily refer to a TTY device. -t option forces them to refer to a TTY device. Is this the correct way of reasoning in order to understand what this option does?

And what is so special about TTY which may not be achieved using ordinary STDIN, STDOUT and STDERR?

An example of use case of -t option is welcome.

By which mechanism does ssh allocate that TTY? Does ssh create new TTY on server or on client? How to check this? (a new node in /dev/ must appear or something...) And how this new TTY is tied to existing STDIN, STDOUT and STDERR?

4
  • "a tty is a particular kind of device file which implements a number of additional commands (ioctls) beyond read and write..."
    – muru
    Jul 29 '19 at 5:57
  • “TTY is a device. It has a descriptor” what do you mean by it has a descriptor? Jul 29 '19 at 6:00
  • @IgorLiferenko Midnight Commander, or dialog or whiptail or Vim, or Emacs, anything that tries to make a TUI.
    – muru
    Jul 29 '19 at 7:05
  • @IgorLiferenko you haven't asked for an example anywhere. You're just asking what's special about TTYs. Anyway: ssh -t some-server vim some-file
    – muru
    Jul 29 '19 at 8:20
5

-t option forces [the standard file descriptors] to refer to a TTY device. Is this the correct way of reasoning in order to understand what this option does?

No. The -t option will run the command on the remote machine with its stdin/out/err connected to a pseudo-tty slave instead of a pair of pipes.

Running it in a pty is the default if (a) no explicit command is given and (b) the stdin of the ssh client is itself a tty. You need a single -t to force tty allocation even when the (a) condition is not satisfied, and two of them (-tt) when (b) is not satisfied.

By which mechanism does ssh allocate that TTY?

By some system-dependent mechanism. Nowadays, it's mostly the standard master_fd = posix_openpt() followed by slave_fd = open(ptsname(master_fd)) [1]

Does ssh create new TTY on server or on client?

ssh always create the new pseudo-tty on the server, ie on the remote machine. If a pseudo-tty is allocated on the server and the local (client's) stdin is a tty, the local tty will be set to raw mode.

How to check this? (a new node in /dev/ must appear or something

Not necessarily. But on a regular linux machine of 2019, a new file will appear under /dev/pts for each new pseudo-tty.

And how this new TTY is tied to existing STDIN, STDOUT and STDERR?

Just like any other file descriptor, with dup2(slave_fd, 0), dup2(slave_fd, 1), etc. dup2(newfd, oldfd) will close whatever file oldfd was referring to. If a pty was allocated, it will also be made the controlling tty of the remote session.

An example of use case of -t option is welcome.

ssh -t /bin/bash on a system where your login shell is csh. If you leave out the -t, /bin/bash will run without prompt, job control, line editing capabilities, etc.

And what is so special about TTY which may not be achieved using ordinary STDIN, STDOUT and STDERR?

See above ;-)

And a pipe is no more of an "ordinary" stdin than a tty or some other kind of file.

[1] that itself has a lot of problems (with multiple devpts mounts and mount namespaces) that's why the TIOCGPTPEER ioctl was added to Linux, which returns a fd referring to the slave without going through the file system.

4
  • I do wonder what, exactly, are the things that can only be done on a tty. There's nothing stopping one from printing prompts or interpreting read bytes as codes for keypresses even if not connected to a tty. But the TTY ioctl's wouldn't be available, so you couldn't set raw/cooked mode or find out the window size? Or something like that, I'm not sure.
    – ilkkachu
    Jul 29 '19 at 18:51
  • @ilkkachu Everything could be done without a tty. Unix' successor (plan9) got rid of all kinds of ttys completely. But now go on and convince bash, vi, emacs, mc that they don't need a tty ;-)
    – mosvy
    Jul 29 '19 at 18:56
  • ... Sure, one can always create a system where something is possible. But I do mean real Unixy OS's, not hypotheticals (nor Plan 9 (I'm not sure I'd count it Unixy, and I'm also not sure if it's on-topic here))
    – ilkkachu
    Jul 29 '19 at 19:07
  • On a real Unix system, it's not only that the curses/etc facilities are assumed to be tied to the existence of a tty, it's also the whole job control/session api which has grown around the "controlling tty" abstraction. You cannot simply trash the compatibility with all that, that's why you may need a pty instead of a socket or a pair of pipes.
    – mosvy
    Jul 29 '19 at 19:14

Not the answer you're looking for? Browse other questions tagged or ask your own question.