Building X terminals with Linux

Building X terminals

I hate the sound of fans. The PC in its modern guise is an evil thing, sitting underneath most peoples' desks, polluting the office with heat and noise, as well as costing an arm and a leg to maintain. I've always wanted to get rid of the monstrosity under my desk and to be able to work in peace and quiet. The classic way to do that is to get rid of the PC and install a diskless workstation of some kind, ideally one with low power consumption and particularly no fans. So I did.

There are lots of forms of workstation: the dreaded NC (now thankfully an idea that is largely defunct), ‘real’ expensive (i.e. Sun or similar) workstations, various other makes and models and those supported by The Linux Terminal Server Project. I decided to have a go at building the latter.

How X Works

Lots of people use Linux, happily accepting the X graphical environment but not really understanding how it works. I was largely in that category myself, but with a least an inkling of what it tries to do.

Unlike the window systems that most people are familiar with, X is inherently networked — the idea is that the display is remote (over the network) from the programs that use it to show their output. As a consequence, an X display provides graphical services to programs that choose to use them, so the X display is called the X server and the programs the clients. This seriously confuses anyone used to thinking of Netscape (for example) as being the client and the remote computer as the server. In the X world client and server are the other way around.

diagram of X

Most Linux users use the internal network of their PC or laptop to replace the network component shown above, so it looks just like an ‘ordinary’ window system, but even when the client programs and the graphical server are located on the same computer, internal networking is being used. If you know how to authorise a remote client, you can tell it to use your chosen display to do its output. It's way beyond the scope of a note like this to go into the ins and outs of it, but we find that the ability to run remote client packages is extremely useful. As just one example, we have a small number of licensed commercial software packages sitting on a central server. Our users don't need minute-by-minute access to those packages on a daily basis, but when they do need it, they simply telnet over to the host that has the package and run it from there, displaying on their own desktop.

If you haven't done this before and want to try it, get X running on one system on your network (we'll call it ‘serverbox’) and follow these steps to run an application on another system (called ‘clientbox’), replacing names as necessary:

Beware: this is a poor model for granting authority to clientbox; it gives everyone on clientbox the opportunity to grab your keyboard and mouse. Only use it in a trusted environment or for a demo.To learn more about X authentication and permissions, you will have to do some serious background reading.

The Linux Terminal Server Project

The Linux Terminal Server Project provides a specialised kernel and configuration that is intended to run on a stripped-down PC with no hard disk. You can boot it from a floppy or a network card with a boot ROM and it will find a suitably configured server on your network, download the kernel and support files, then start the PC running as a stand-alone X server. The first one I built used a floppy disk, a cast-off 486/DX-66 motherboard and 16MB of RAM. I powered it from a standard PC power supply that had been removed because of a noisy fan: I took off the lid and cut the wires to the fan.

Installing the LTSP distribution was pretty easy, simply following the instructions had the X terminal running a couple of hours into the start of the project. They have done a good job of packaging it up (if you are using Red Hat 6 or later) and the instructions are pretty clear. Making the floppy bootdisk wasn't too difficult either.

It's not ideal to have to boot from floppy, so the next step was to put a boot ROM into the network card. Downloading the Etherboot distribution had been a part of creating the boot floppy — there is some good documentation about how to create bootproms. I looked around and the lowest-cost devices I could find were 27C512 chips, these are 64KB EPROMs. Most boot cards don't need to be this big, but the smaller EPROMS actually cost more, presumably because of lower volume production.

I found that the most effective way of creating the boot ROM was to copy the 16KB of boot image from the Etherboot software into the ROM four times to fill it. This takes care of any confusion by the BIOS about where it should look for the bootable image if the ROM is larger than expected. It takes just a couple of seconds to program the boot ROM in a programmer (if you have one) and the images for ne2000 ISA cards and ne2000 PCI cards both worked well on a motley assortment of odd ethernet cards in the junk box.

I found that the cards had to be set up to recognise the boot ROM — none of them did it automatically, so I had to dig hard for the original setup disks, all of which needed to be run under DOS — but once the cards have been told they have a ROM they remember their configuration.

Running the X Terminals

The X terminals run with their root filesystems in RAM disk. Workstation-specific files are stored on the RAM disk and the the other files they need retrieved using NFS file sharing over the network — so it's important to have a reliable NFS server for them to use, that's the price of doing without a hard disk.

Logging-in is a completely different matter when you have a set of X terminals and no real notion of a ‘home’ system. The standard way of doing it is to use xdm — the X Display Manager. Although it is doubtless a lean, mean and cleverly designed piece of architecture, all I can say as an outsider is that it seems far too complicated for its own good and by no means easy to get to grips with. Here's my understanding of using the brute:

  1. xdm can be used to start the local X server on your PC (as Red Hat now does by default for many users) then offer the option of logging-in. This can be arranged to run on boot-up so that the system behaves rather like a Mac or Windows PC: it starts up and gives you a windowed interface immediately.
  2. xdm can also be run as a remote service — when your X station starts, you will configure it to contact an xdm server on a specified host and it will offer you an X version of the login prompt for that host.
  3. xdm can be run in a mode where just like above, you contact your specified remote xdm server, but ask it not just to offer you a login on that host — instead it will broadcast to the network for any other xdm servers running and for each one that responds, it offers you the choice of logging-in via them instead.

Because we run several hosts that I would like to be able to use, I decided to run xdm in the last of the modes listed, the one that broadcasts for other xdm servers. To do this meant editing the /tftpboot/lts/ltsroot/etc/rc.local file on the boot server for the X terminal: here is the crucial (changed) line:

echo "/ltsbin/${XSERVER} -ac -indirect ${XDM_SERVER}" >/tmp/start_ws

To get xdm on my chosen server to respond correctly, here is my Xaccess file (it lives in /etc/X11/xdm on standard Red Hat configurations) with comments and blank lines stripped:

*               #any host can get a login window
*               CHOOSER BROADCAST

The standard chooser screen (the one that lists the hosts which responded) sits on a nasty grey background and is as ugly as you can find. To fix it, I renamed chooser to realchooser and created this executable shell script under the name of chooser:

/usr/X11R6/bin/xsetroot -solid skyblue4
exec /etc/X11/xdm/realchooser $*   

and then modified the Xresources file in the directory:

Chooser*geometry:            600x500+300+225
Chooser*allowShellResize:    false
Chooser*ShapeStyle:          Oval
Chooser*viewport.forceBars:  true
Chooser*label.font:          *-*-bold-i-normal-*-240-*
-misc-fixed-medium-r-semicondensed--13-120-75-75 -c-60-iso8859-1
Chooser*Command.font:        *-*-bold-r-normal-*-180-*
#ifdef COLOR
Chooser*Form.background:     gray80
Chooser*label.foreground:    white
Chooser*label.background:    midnightblue
Chooser*Command.background:  gray80
Chooser*internalBorderColor: black
Chooser*Command.font:        -adobe-helvetica-bold-r-*-*-12-*
Chooser*viewport.useRight:   true 

I'd love to pretend that I came up with all that myself, but in reality it's all plagiarised from either Rich Kaszeta's Linux X Terminal Pages or the XDM-Xterm mini-HOWTO — a big vote of thanks to both those authors.

This is being written using a Linux X Terminal running on the old 486 / fanless PSU combination mentioned earlier. Here it is prior to having a case made for it, in naked glory (you can see that the fan isn't spinning):

X Terminal minus box

There is currently 40MB of RAM on the board, but it does seem to work just as well with 16MB.

So What's it Like?

Most of the time it's a delight to work with. It boots up silently, runs cool mostly (the right-hand heatsink in the PSU does get just a bit too hot for my taste, running somewhere in the region of 120°F) and is proving successful after a severe hiccup that almost had me abandoning the project.

What was the hiccup? Everything was working well until our network got busy; at that point the performance of the terminal collapsed, rendering it unusable. The slightest hint of network congestion caused minute-long delays in screen refreshes, even characters wouldn't echo in terminal windows. I knew that X was greedy in terms of network resources, but that was a nasty shock. Fortunately I was able to talk to some people who were using X terminals at local Universities and it did seem that my problem was unusual. Eventually it was traced to a network card problem. The first network card was just faulty — even on an idle network, every fifth ping or so would have a round-trip time of 1 second rather than milliseconds. The replacement card, a PCI Realtek 8029 derivative had been configured with ‘full duplex’ enabled. Whatever else full duplex is supposed to do, it wrecked performance. Other identical cards with the default non-full-duplex configuration were fine, and so was the errant card when it was reset. The moral of the story is not to give up! Although we haven't tried it over a period of months yet, some initial tests with the network artificially loaded up to about 80% of capacity show the X terminal still performing acceptably, though there is some evidence of sluggishness at that kind of load.

On the other side: if you are pushing lots of images over your network, then 10Mb/s doesn't goo very far. Running a single remote copy of Netscape on a site that is rich in animated images chews up some 30-40% of our old Ethernet network. Stopping the images (press ‘ESC’) causes the load to drop off instantly. Yet another reason for browsing with ‘Load Images’ turned off. The Linux Terminal Server Project has support for running applications locally and of course a prime candidate would be Netscape ... but so far that hasn't been necessary.

As an experiment I dug out an ancient 386 DX/33 with 8MB RAM. It booted and ran adequately, though the performance wasn't great once you started dragging windows around (the video card didn't help, I had to turn off acceleration to get rid of some pixel problems, but the 386 wasn't to blame). I used it for a few hours and started to get used to it. It would make a serviceable email terminal if you didn't ask too much of the graphics.

As a side note: I found it difficult to get hold of a ROM burner for the boot chips so ended up buying one. If anyone in the UK (it's not worth the hassle of shipping overseas) wants a boot ROM making, get in touch and I'll do it at a modest price.

Mike Banahan, 30/September/2000

Useful Links

Serverbox Clientbox

First of all, give clientbox authority to access your X server: type

xhost +clientbox

to the shell prompt. Then telnet over to the clientbox.

telnet clientbox



Now you have telnetted to clientbox. Your DISPLAY environment variable has probably been set by the telnet/login combination, so this should work:


If not, try

DISPLAY=serverbox xclock&
All being well, you will see a clock (presuming xclock is installend on clientbox)