Setting up a multi-user system with Linux

By Paul Dunne paul@tiny1.demon.co.uk

I am writing this article in what I am pleased to call my library (though it is really a living room). It is marvelously quiet - no humming fans, no whirring disk drives - in fact, there is no computer in the room at all. I am typing on a ancient Wyse 30 terminal, linked to my Linux box in the office upstairs by ten meters of null modem cable. One of the disadvantages of the personal computer is that it really needs a room of its own, or at least a room with a considerable portion of space given over to it and its paraphernalia. This is clearly not an ideal way of using a computer: one would not think of going to a special room to read a magazine, so why do so when you wish to look at a web page? Linux's inherent multi-user capabilities and its support for terminals offers an answer. In this article, I shall describe how to set up a Linux box to support a number of terminals.

How Linux talks to terminals: getty

A stand-alone Linux box already supports multiple terminals, due to the virtual console support built into the kernel. Each of the screens accessible on the console monitor through an Alt-Fkey combination is treated as a separate terminal. This can be illustrated by a `ps' listing, which should show some lines like this:
 5831 p 5 S     0:00 /sbin/agetty 38400 tty5

Support for real terminals starts along similar lines. First, it is necessary to tell the system to run a `getty' process on each port to which a terminal will be attached. The ports would normally be serial lines. A normal PC has only two of these, but there are cheap multi-port serial cards available, which provide 4, 8, 16 or even more additional serial lines, while taking up only one interrupt ( and an expansion slot on the motherboard, of course ). I use a cheap clone of the AST Fourport card, which as the name implies gives me four extra serial ports.

Configuring the serial ports

The extra serial ports must have corresponding devices created in /dev, and these must be configured using the setserial program. The devices may already exist; if not, creating them is simple. The mknod command is used (look up the man page!) e.g.
	mknod -m 666 /dev/ttyS4 c 4 68

Where c says it is a character special device (the alternative is b for block, e.g. a disk), and the two numbers following the device file name are the major and minor numbers respectively. For serial input, the major number is 4; for serial output, 5. The minor number is the port number plus 64 (you ask why? I don't know!) The -m option, as you've probably guessed from the look of it, sets their permissions on the file.

Devices

The following devices exist on my system. Note the major and minor numbers. /dev/ttyS4-7 and /dev/cua4-7 are the control devices for my additional serial lines.

Input


crw--w--w-   1 root     root       4,  64 Sep 24 19:44 /dev/ttyS0
crw--w--w-   1 root     root       4,  65 Sep 20 19:42 /dev/ttyS1
crw-rw-rw-   1 root     root       4,  66 Jan 23  1980 /dev/ttyS2
crw-rw-rw-   1 root     root       4,  67 Sep 24 19:36 /dev/ttyS3
crw-rw-rw-   1 root     other      4,  68 Nov 17 16:53 /dev/ttyS4
crw-rw-rw-   1 root     other      4,  69 Nov 17 16:56 /dev/ttyS5
crw-rw-rw-   1 root     other      4,  70 Nov 17 16:56 /dev/ttyS6
crw-rw-rw-   1 root     other      4,  71 Nov 17 16:56 /dev/ttyS7

Output


crw-rw-rw-   1 root     tty        5,  64 Apr  1  1993 /dev/cua0
crw-rw-rw-   2 uucp     staff      5,  65 Oct  7 21:42 /dev/cua1
crw-rw-rw-   1 root     tty        5,  66 Apr 11  1993 /dev/cua2
crw-rw-rw-   1 paul     staff      5,  67 Nov 21 09:16 /dev/cua3
crw-rw-rw-   1 root     tty        5,  68 Sep 20 13:11 /dev/cua4
crw-r--r--   1 root     root       5,  69 Sep 20 13:12 /dev/cua5
crw-r--r--   1 root     root       5,  70 Sep 20 13:12 /dev/cua6
crw-r--r--   1 root     root       5,  71 Sep 20 13:12 /dev/cua7

Setserial

The setserial program is essential to configure the additional serial ports. The README file that comes with the source says it all, really: "[setserial] allows you to look at and change various attributes of a serial device, including its port, its IRQ, and other serial port options." It comes with an rc.serial script which with a little tuning will do everything you need.

In /etc/rc.local, I have the following lines:

	if [ -f /etc/rc.serial ]; then
		/etc/rc.serial
	fi

Configuring getty

  1. Add an entry for getty to use for your terminal in /etc/gettydefs. Here is a sample of some entries, from my system (I got them from the Serial HOWTO).
    # 38400 bps Dumb Terminal entry
    DT38400# B38400 CS8 CLOCAL # B38400 SANE -ISTRIP CLOCAL #@S @L login: #DT38400
    # 19200 bps Dumb Terminal entry
    DT19200# B19200 CS8 CLOCAL # B19200 SANE -ISTRIP CLOCAL #@S @L login: #DT19200
    # 9600 bps Dumb Terminal entry
    DT9600# B9600 CS8 CLOCAL # B9600 SANE -ISTRIP CLOCAL #@S @L login: #DT9600
    
    If you want, you can make getty print interesting things in the login banner. In my examples, I have the system name and the serial line printed. You can add other things (again, this stuff is from the Serial HOWTO):

    @B The current (evaluated at the time the @B is seen) bps rate. @D The current date, in MM/DD/YY. @L The serial line to which getty is attached. @S The system name. @T The current time, in HH:MM:SS (24-hour). @U The number of currently signed-on users. This is a count of the number of entries in the /etc/utmp file that have a non-null ut_name field. @V The value of VERSION, as given in the defaults file. To display a single '@' character, use either '\@' or '@@'.

  2. Edit your /etc/inittab file to run getty on the serial port (substituting in the correct information for your environment - port, speed, and default terminal type):
    	S1:456:respawn:/sbin/getty ttyS1 DT9600 vt100
    

  3. Restart your system.

How Linux knows what to say: termcap/terminfo

termcap

This was the first attempt at providing Unix with a device-independent interface for screen-handling. /etc/termcap is a simple text file, containing terse, machine-friendly descriptions of terminal capabilities.The idea is that the application queries the environment to find out what type of screen it is writing to ( typically defined in an environment variable called TERM or TERMCAP ), then looks up the matching definition in the termcap file. Here is the termcap definition I use for my Wyse 30's (I found it posted to comp.os.linux.hardware some time ago):
# wyse 50 stuff -- extracted from a sparc13 termcap file -- jiw 9/4/95
# Notes by tpm seem to indicate 'wyse' entry works best ... so did
# setup on terminal for 'ADDSVP' emulation and Enhance ON.  tpm notes:
# The following seems to be the best mode to run a Wyse-50 in.  It works
# with Emacs using this termcap entry.  Wyse mode seems to be a loser.
# Note that you have to manually set emulation mode to ADDSVP and turn
# ENHANCE on. --tpm
# Tab support, better is and rs, and wyse-nk added Jan85 by sun!gnu
# pd 23/10-del :am;del tabs entry

wyse-vp|wyse30|Wyse 30 in ADDS Viewpoint emulation mode with "enhance" on:\
        :do=^J:ho=:\
        :le=^H:bs:li#24:co#80:cm=\EY%+ %+ :cd=\Ek:ce=\EK:nd=^F:\
        :up=^Z:cl=^L:ho=^A:ll=^A^Z:kl=^U:kr=^F:kd=^J:ku=^Z:kh=^A:\
        :pt:so=^N:se=^O:us=^N:ue=^O:dl=\El:al=\EM:im=\Eq:ei=\Er:dc=\EW:\
        :is=\E`\072\E`9^O\Er:rs=\E`\072\E`9^O\Er:
#   This is the same as above, but with no keys.  This makes vi ^F, ^B, work.
wyse-vp-nk|wyse-nk|wyse30|addsviewpoint|Wyse 30 in ADDS Viewpoint enhanced mode with cursor keys gone:\
        :kl@:kr@:kd@:ku@:kh@:tc=wyse-vp:
#   The Wyse-50 does not correctly emulate a Televideo 925.
vw|w9|wyse925|wyse-925|Wyse-50 emulating tvi925:\
        :xn@:tc=tvi925:

terminfo

A more efficient system developed at Bell Labs. Look at the manual page for tic - the program that makes terminfo database entries from termcap descriptions.

Why you need both

Unless you have built all your applications yourself, and chosen only those that conform to your chosen method of handling the screen, you will likely have a mix of applications, some using termcap, some terminfo.

How the terminal hears, and talks back: cabling

The cabling needed for a basic serial connection to a terminal is very simple. Just three wires need to be connected, as follows:
	RxD   Receive Data          2 - 3       TxD   Transmit Data
	TxD   Transmit Data         3 - 2       RxD   Receive Data
	GND   Signal Ground         7 - 7       GND   Signal Ground

This will work, but allows for no hardware handshaking. A full null-modem configuration is as follows:
	DCD   Carrier Detect        1 - 20      DTR   Data Terminal Ready
	RxD   Receive Data          2 - 2       TxD   Transmit Data
	TxD   Transmit Data         3 - 3       RxD   Receive Data
	DTR   Data Terminal Ready   4 - 6       DSR   Data Set Ready
	DTR   Data Terminal Ready   4 - 8       DCD   Carrier Detect
	GND   Signal Ground         5 - 7       GND   Signal Ground
	DSR   Data Set Ready        6 - 20      DTR   Data Terminal Ready
	RTS   Request To Send       7 - 5       CTS   Clear To Send
	CTS   Clear To Send         8 - 4       RTS   Request To Send

As my terminals could be configured to use no handshaking, as I was fixing up my own cables with their appropriate connectors, and as I hate soldering, I took the former route! It works just fine.

Coping with difficult terminals

My Wyse 30's are not the most modern of devices, and I could not get a termcap / terminfo definition of them. Instead, I use their ADDS Viewpoint emulation mode instead, and use definitions intended for that terminal. This emulation appears to be less than perfect, however, and I have some problems. Some applications, such as emacs and some versions of vi (nvi in particular) are confused by the auto scroll feature. Therefore, I need to use a vi clone other than my usual nvi when I am working on a terminal. Also, the "less" pager loses a line per page from the viewed file, so I had to put up with using "more" instead. To set up all this automatically, I have the following code in /etc/profile.

excerpt from /etc/profile:

# chose appropriate terminal settings
basetty=`basename \`tty\``
case $basetty in
ttyS*)	export TERM=wyse-nk; alias vi='elvis'; export PAGER=more ;;
tty*)	export TERM=linux ;;
esac

For some reason, though, this alias doesn't work with applications that get their information about what text editor to use from a file e.g. MH with .mh_profile. To overcome this, I had to be a short shell script (named "vi", natch!) into my personal bin directory, and let that decide which real vi I should use. It's just the same code as in /etc/profile.

Conclusion

So, at the end of it all, we have a cheap and simple way to set up a multi-user system. I think that any REAL operating system has to offer this capability (multi-user support just "slots in" on top of multi-tasking, after all). Certainly, it has made my use of my Linux box much more productive, by allowing me access to it from several different locations in my house.