pty.c in 4.1BSD ? - (nf)

rpw3 at fortune.UUCP rpw3 at fortune.UUCP
Thu Mar 22 22:05:38 AEST 1984


#R:vaxwalle:-14000:fortune:26900033:000:9520
fortune!rpw3    Mar 22 02:38:00 1984

"What is a pty?"

[163 lines, but please, no flames, guys, it's history/tutorial time...]

The pseudo-teletype ("pty") is not a Berkeley-ism, nor even a UNIX-ism.
It's pretty widely industry standard on timesharing operating systems.
(My first exposure to them was back in 1970, on DEC PDP-10's, but they were
old even then. They pronounced the acronym "pity", to rhyme with "tty".)
((My apologies if I leave out earlier systems, maybe MULTICS, of which
I have no direct experience.))

A pseudo-teletype is a specialized form of a "virtual device", that is,
a "device" which is really manifested by a program ("Pay no attention to
the [process] behind the curtain!"). As said in the excerpt you quoted,
a pty normally has two ends, a "master" end and a "slave" end. Under UNIX,
the "master" end is normally named "/dev/ptyNN" while the slave end is named
"/dev/ttyNN". (On some systems the slaves are "/dev/ttypN".)

The point is that since (if the implementation of "pty.c" is correct, and
it should be) there is no way that a process can (easily) tell that the
"slave" end is not a real, live, physical piece of hardware, and a process
controlling the "master" end can EXACTLY emulate a physical human sitting
at a terminal typing and reading. In fact, this emulation is generally so
exact that the slave ends are simply listed in /etc/ttys with all the other
terminals, and get a "getty/login/shell" from "init" just like the rest,
with a line in /etc/ttys like "1mtty03" or "1mttyp3" (login port, 9600
baud, /dev/tty03 or /dev/ttyp3). [Here on, assume slaves named ttyNN.]

So (messy details of flag handling and synchronization omitted), some
process "X" opens the master side of a pty, say /dev/pty43. Since the
beginning of time, some copy of the program "getty" was trying to open
/dev/tty43 (since "init" forks a copy of "getty" for each line in /etc/ttys),
and that open now completes, since "somebody" (process X) just "dialed in".
"Getty" writes a banner on tty43, which X reads by reading pty43. X then
"types" its login name by writing on pty43 which "getty" reads on tty43,
and so on through the login process, running the shell, and then the user
programs, etc.  "Terminal input" is "typed" by X by writing on pty43,
"display output" is "read" by X by reading pty43, and all the user programs
are dumb and happy thinking there's a human on the other end of tty43.

So why would one want to do this? Basically, in historical order of
evolution, four reasons:

1. Batch (Background) Processing of Commands. On systems (not UNIX) which
   are NOT process oriented, and which therefore did NOT have the concept
   of a "fork", there was no easy way to have background (or "batch") jobs.
   The pty was a clever, elegant solution that left the basic "timesharing"
   nature of the system unchanged, while providing essentially what we now
   call shell scripts. Example: On a PDP-10, you said ".submit foo.ctl" and
   "foo.ctl" was fed to an operator program named BATCON (run from one of the
   operator's consoles) that opened a pty and "typed" your monitor commands
   in (including logging you in and out), and saved up the output in a file
   called "foo.log" for your later amusement and amazement (since Murphy's Law
   was true even back then ;-}).

Even with all that convenience (;-}), systems administrators got tired of
having a terminal in the machine room for EACH copy of EACH operator service
program (no "fork", remember, so one tty for each line printer spooler and
for each batch stream and for each card reader...), so...

2. Job Control - Multiple jobs active from one terminal. A new operator service
   program (named OPSER on PDP-10's, OPRCON on TOPS-20) was invented which
   incestuously used ptys to control all of the other operator service jobs!
   You could type a line into a given job by prefixing the line with the
   subjob number or mnemonic (set up by the operator), such as, to change
   forms on printer 3 you said "L3-forms payroll2" (or something). Since it
   was perfectly general, the operator could also do small utility tasks
   (like accounting, etc.) through the same terminal (except for the hassle
   of those other jobs sometimes yammering at you -- but there were commands
   to handle that). For convenience, if you typed a line that didn't start
   with "XX-" it assumed you meant the last one you explicitly talked to,
   so an extended conversation was fairly confortable.

   Eventually, ordinary users started using OPSER when they needed to multiplex
   several activities, or whenever they needed its script and logging features.
   (Like the "script" program.)

In modern terminology, what you had there was a line-oriented "window" manager,
similar to the "Maryland Windows" package, but for Teletype Model 33's.
Or, somewhat like Berkeley 4.1bsd job-control under the C-shell ("csh"), but
with processes NOT suspended just because you weren't typing at them (they
could still type out progress reports, if you didn't disable them).

	[Personal aside to any wizards who have made it this far:
	 having used both OPSER and 4.1 csh with job-control, I'll
	 take pty-based "job control" hands down, PROVIDED it's
	 always there and is the default. I understand the problem
	 in S5 is you have to decide ahead of time whether you're going
	 to need it (?).]

Home stretch...

3. Network Virtual Terminals. With the advent of networks of many strange
   and wonderful kinds, seldom being integrated into the operating system
   completely on first release, the ancient pty was again drawn into service
   [is this getting a little thick? ;-}] as a quick, simple, effective way
   of implementing a basic network service -- remote logins. The operating
   systems (including UNIX) rarely treated network connections as full
   citizens, and besides, there were many versions -- which one(s) to support?
   The answer (even today, often) is to have a program running on the target
   system (the one you're trying to login on) called a "network virtual
   terminal protocol server" (typically named "vtpsrv") which sits around
   waiting for people out in the network to connect to it (via whatever net
   hardware and software one might have). When someone does so, the "vtpsrv"
   handles all the network stuff, eventually passing characters typed by a
   user (or a program) out in the network to the master side of a pty as
   if the user were local to the target machine, and "displaying" output
   (read from the pty) by sending it back out into the network. Because
   of the local (target) "vtpsrv", the target operating system doesn't
   have to worry about "network terminals" -- it doesn't have any! (That's
   the "virtual" part.) Smarter versions of "vtpsrv" (or of the corresponding
   program that the real user runs out there in the network, usually called
   "vtp") can sometimes also handle some transformations from one terminal
   type to another (a different meaning of "virtual terminal").

   Naturally, there should be some standards around for how the various
   pieces talk to each other. There are, but of course they are network
   dependent. Within the ARPAnet (or other nets using IP/TCP protocols),
   the protocol between a "vtp" and a "vtpsrv" is called "Telnet" (NOT to
   be confused with the company Telenet!). Within the CCITT world (the "X.nn"
   and "V.nn" international standards), the protocol between the user and
   "vtp" (yes, users have to obey protocols, too!) is called X.28, the protocol
   between "vtp" and "vtpsrv" is called X.29, and the overall scheme is called
   X.3 (and sits on top of X.25 -- aren't you glad you asked?). Telenet (the
   company) uses protocols VERY close to the CCITT standards.

Of course, as efficiency becomes an issue, it is tempting to put all of
"vtpsrv" in the kernel of the operating system, and this is often cited
as a mark of a "integrated" network offering. Nevertheless, the flexibility
of the pty approach often wins over raw efficiency. (Various players do it
various ways.)

Finally (and this IS short),

4. Virtual Devices. Although the pty is a specialized virtual device, having
   (usually) just the set of "ioctl" calls needed to emulate a tty, sometimes
   people will use them to emulate hardware that hasn't been built yet (or
   for which the driver hasn't been written yet), in order to decouple the
   writing/building of the "system" side (driver/hardware) from the "user"
   side (applications programs). With a little tinkering (mostly just more
   general handling of ioctl's), ptys can be made to emulate any UNIX
   "character device". This hack has even been used occasionaly to execute
   programs that would only run on specific hardware or kernels, when
   equivalent (but unfortunately, different) systems were available.

SUMMARY

These days, #3 (networks) is the most common use of ptys, but the increasing
emphasis on "windows" is reviving #2 (multiplexing).

[May this lengthy, chatty, uneven reminiscence be of use to someone.]

Rob Warnock

UUCP:	{sri-unix,amd70,hpda,harpo,ihnp4,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphin Drive, Redwood City, CA 94065

p.s. I have completely ignored the issue of the so-called "mpx" device,
     found (partially) in UNIX Edition 7 (v.7) (and other UNIXs, as well as
     several non-UNIX systems), which could be used like a pty with one master
     side and many slave sides. Requicat In Pacem.  Who knows, it may become
     "popular" again some day, eh?



More information about the Comp.unix mailing list