I disclaim any responsibility for your actions as a result of reading this
Its March 2001. My brother has asked me to investigate a way to avoid having to upgrade a bunch of old PCs ... because they are starting to seem slow. Being a linux enthusiast I suggested the win4lin and vmware products that allow you to consolidate multiple virtual PCs on one server. This way the ancient client PCs can be used as dumb X terminals ... and there you go 'a solution'.
Of course, having said all this, I'd never actually tried win4lin or vmware. I kept on reading good things about the speed of win4lin and going to their website www.netraverse.com I found that they had only just put out a 25 user multi-user beta of their 2.02 product. The other initial good thing about win4lin was that license costs were US$50 each rather than US$80 or 90 that vmware charges. Having downloaded win4lin, I set about trialling it in a potential network computing environment.
Installing win4lin was a little problematic, but thanks to the versatility of UNIX, it was quite solvable. I use Slackware 7.1 as my distibution. win4lin needs to have a patched kernel for it to work. Usually, you would download an entire kernel for Red Hat, mandrake etc and the install would be simple. Alas, Netraverse do supply kernel patches for the last of the 2.2 series. I had been playing around with a 2.4.2 kernel but went back to 2.2.18 so that I could patch the kernel. Its actually easier if you get the patch, apply it, recompile your kernel and then run the
sh quickdownload.sh from their downlaod instructions.
Once the quickdownload.sh script is complete, you need to run
sh install-win4lin.sh. This doesn't work on Slackware. You need to hack it a bit (NB: the script is in /usr/bin). Find the following line:
rpm -i RPMS/i386/Win4Lin*.rpm
and change it to:
rpm --nodeps -i RPMS/i386/Win4Lin*.rpm
I think that should allow it to complete. Just follow the win4lin instructions to run
winsetup as root. I've tried both windows 95 and win98. (NB: When asked for the win95 boot floppy, a win98 one seems to go OK). Then you need to login as a regular user and run
win to actually install Windows for that user. Windows seems to install at a ballistic rate. One thing though; On Slackware I think the windows install fails early on because it looks for ncurses 4. I just created a soft link to ncurses 5 and it seemed relatively happy:
ln -s libncurses.so.5.0 libncurses.so.4
The install doesn't have a clue about Slackware's rc scripts. But after the install you should have a file
/etc/rc.d/init.d/Win4Lin. I just copied this to
/etc/rc.d/rc.win4lin and added a line to
/etc/rc.d/rc.local to run it.
Windows under win4lin
Running win4lin locally on your PC and using the local X display, everything goes at quite a good pace. Its quite amusing having several desktops open at once.
Some problems I had:
I still haven't tried many big apps, but so far things like IE 5 run seemlessly. Printing was dead easy to set (You can get it to print directly to the parallel port or to execute an arbitrary command like 'exec lpr').
- CDROM access denied. You have to make sure that your CDROM is not mounted in linux and that the device permissions allow your win4lin users to mount it (the easy option is something like
chmod 666 /dev/hdc).
- Sound didn't work. This turned out to the same problem as the CDROM. You need to
chmod 666 /dev/dsp in order for it to work.
- Unable to write to a DOS drive. I have /c and /d VFAT drives on my system which are usually mounted under linux. You have to unmount them for win4lin to use them as native DOS drives. but I always got this unable to write to drive D: blue screen. I tried doing a chmod 666 but that didn't seem to help. The easier option was to mount the drive again under linux and create a virtual network drive for it (like the default J: drive).
I have a simple 10mbps network using two PCs and a crossover cable. My first test was to hook up my old P133 laptop (also running Slackware) and try to run a windows session remotely. It seemed to start up OK, but there were certain windows screen elements that scrolled incredibly slowly. For example, running Windows Explorer and trying to scroll the left hand tree view seemed incredibly slow, but I think if you dragged the scroll bar it went OK. I have now (21.3.2001) tried win4lin remotely across a 100Mbps network and the results are fairly similar to running at 10Mbps. Screen updates work best using 8 bit colour, but certain scrollable regions seem to lag badly when you don't drag the scroll bar.
I wasn't satisfied with this simple test, so my next aim was to set up some diskless X terminals.
Diskless X terminals
There are quite a number of HOWTOs on the net giving instructions on how to set up diskless X terms. Sadly, many of these are for quite old kernels and each HOWTO seems to have very different ideas to the next one. Some good info I did find is:
Potato's Diskless X term HOWTO
These are the steps involved with setting up a diskless X term using kernel 2.2.18:
Too many steps right??
- Get Etherboot, compile it and create a boot floppy for your network card
- Get mknbi from the Etherboot site.
- Build a new 2.2.18 kernel with root NFS support and patch it for bootROM support using mknbi
- Set up bootpd so that your X terminal can get an initial IP address
- Set up tftp so that your new kernel can be downloaded to your diskless x term.
- Create a fake root filesystem and export it using NFS so our X terminal can have a root filesystem.
- Set up xdm
- Set up the X font server
- Set up a printer proxy for the X terminal
On Slackware 7.1 I had trouble building this. Basically the version of the GNU assembler is too old. So I ended up downloading BinUtils 4.0 (probably from ftp.gnu.org/gnu), building it, and finally building Etherboot as per the instructions. I wanted to just use bootp so I disabled DHCP support by adding the following to the src/Config file:
My test diskless X terminal is a P75 / 16mb RAM and a 3c509 ISA lan card (later tested with a 100Mbps RTL8139 card). So to make my boot floppy it was something like:
cat bin/boot1a.bin bin32/3c509.lzrom > /dev/fd0
cat bin/boot1a.bin bin32/rtl8139.lzrom > /dev/fd0
You can probably test this by booting off it. You should see some waiting for BOOTP request message and maybe some 'sleep' messages.
This is a simple compile.
Build the diskless kernel
I did this on kernel 2.2.18. You need to make sure you have the following set:
NB: You can leave out heaps of stuff. You obviously don't need any filesystem support except NFS. you don't really need IDE drivers or anything.
- Root on NFS
- Kernel autoconfiguration via BOOTP (or DHCP if you want to use DHCP)
- Make sure your network card is configured into the kernel (not a module).
I usually do a make bzImage
Once the kernel is built, run mknbi against it.
mknbi-linux --ip=rom --output =/tftpboot/xterm1.bootimage \
--ip=rom bit is meant to be only required for kernel 2.2.18 and up. It just means to get the IP address and subnet mask and stuff from the BootROM (or boot floppy). You could put
--ip=bootp which should force it to send another bootp request.
Slackware already comes with bootp so I just set it up to work through inetd. Make sure the following line is in /etc/inetd.conf:
bootps dgram udp wait root /usr/sbin/bootpd bootpd -i
Now add some lines to /etc/bootptab. I just set up one simple entry for my one PC (rather than having a sort of 'common' or 'default' grouping as well).
Make sure the following line is in /etc/inetd.conf (you probably just need to uncomment it):
tftp dgram udp wait root /usr/sbin/tcpd in.tftpd
By default it will serve out /tftpboot. There are apparently some more secure tftp servers around (I think one comes with Netboot). Now send a HUP to your inetd process. This should pick up the bootp and tftp services. Now go to the diskelss client and try booting off the floppy. You should get an answer to the BOOTP request and a kernel should download and probably panic when it tries to load the INIT process. So far so good.
Set up NFS and create a fake root
Slackware by default starts up the main NFS server processes (rpc.mountd and rpc.nfsd). They'll share out anything in /etc/exports. I added the following line:
/tftpboot/10.0.0.5 10.0.0.5 (rw,no_root_squash)
NB: Most notes say that the rootpath will normally be something like /tftpboot/< hostname > . However, i think my bootp server is too old and is not passing this info to the kernel OR its a name resolution problem.
Once you've changed /etc/exports you must send HUP signals to rpc.mountd and rpc.nfsd.
Our diskless client has IP address 10.0.0.5. Create the fake root directory:
So what do we need to put in our fake root. This is quite interesting really. Being a bit of a minimalist, I was quite annoyed that some of the HOWTO's out there suggested copying all of /bin, all of /lib .... etc. and then using the actual rc startup scripts from RedHat (with minor mods). Unbelievable. I took the 'just enough to make it work' approach.
First we need init. This is statically linked and lives in sbin. Then we obviously need an /etc/inittab and some startup scripts. I just put minimal ones in /etc/rc.S (for sysinit) and /etc/rc.5 (for my main run level 5 startup). You need a shell to run these (and probably libc for the shell). basically, any executable I needed, I just did an ldd on it to work out what libraries it required, copied them across to the fake root
Here's my complete directory tree (under /tftpboot/10.0.0.5):
-rwxr-xr-x 1 root root 3161092 Mar 17 11:57 XF86_SVGA
-rwxr-xr-x 1 root root 59628 Mar 19 17:08 ash
-rwxr-xr-x 1 root root 7584 Mar 17 11:44 echo
-rwxr-xr-x 1 root root 47876 Mar 17 11:57 ls
-rwxr-xr-x 1 root root 17621 Mar 25 09:06 p910nd
-rwxr-xr-x 1 root root 19340 Mar 17 11:57 rm
lrwxrwxrwx 1 root root 3 Mar 19 17:08 sh -> ash
-rw-r--r-- 1 root root 20521 Mar 18 11:43 XF86Config
-rw-r--r-- 1 root root 179 Mar 17 11:58 inittab
-rw-r--r-- 1 root root 22 Mar 25 09:02 nsswitch.conf
-rw-r--r-- 1 root root 42 Mar 25 09:01 protocols
-rwxr-xr-x 1 root root 106 Mar 25 09:06 rc.5
-rwxr-xr-x 1 root root 32 Mar 17 11:54 rc.S
crw--w--w- 1 root tty 5, 1 Mar 17 11:47 console
crw-rw---- 1 root uucp 5, 64 Jul 18 1994 cua0
crw-rw---- 1 root daemon 6, 0 Apr 28 1995 lp0
crw-rw---- 1 root daemon 6, 1 Apr 28 1995 lp1
crw-rw---- 1 root daemon 6, 2 Apr 28 1995 lp2
crw-r----- 1 root kmem 1, 1 Mar 17 11:46 mem
lrwxrwxrwx 1 root root 4 Mar 19 17:16 mouse -> cua0
crw-rw-rw- 1 root root 1, 3 Mar 17 11:46 null
crw--w--w- 1 root root 4, 0 Mar 17 11:47 tty0
crw-rw-rw- 1 root root 4, 2 Mar 17 11:47 tty2
crw-rw---- 1 root tty 4, 64 Jul 18 1994 ttyS0
-rwxr-xr-x 1 root root 79276 Mar 17 11:44 ld-2.1.3.so
lrwxrwxrwx 1 root root 11 Mar 17 11:44 ld-linux.so.2 -> ld-2.1.3.so
-rwxr-xr-x 1 root root 1013224 Mar 17 11:43 libc-2.1.3.so
lrwxrwxrwx 1 root root 13 Mar 17 11:43 libc.so.6 -> libc-2.1.3.so
-rwxr-xr-x 1 root root 9560 Mar 17 11:42 libdl-2.1.3.so
lrwxrwxrwx 1 root root 14 Mar 17 11:43 libdl.so.2 -> libdl-2.1.3.so
-rwxr-xr-x 1 root root 129824 Mar 17 11:56 libm-2.1.3.so
lrwxrwxrwx 1 root root 13 Mar 17 11:56 libm.so.6 -> libm-2.1.3.so
-rwxr-xr-x 1 root root 30480 Mar 25 09:03 libnss_files-2.1.3.so
lrwxrwxrwx 1 root root 21 Mar 25 09:04 libnss_files.so.2 -> libnss_files-2.1.3.so
-rwxr-xr-x 1 root root 339576 Mar 17 11:02 init
-rwxr-xr-x 1 root root 7576 Mar 17 12:41 reboot
-r--r--r-- 1 root root 17375 Mar 17 12:24 usr/X11R6/lib/X11/rgb.txt
You also need a /tmp directory, and a /var directory. /var needs to have a run and a lock/subsys directory. The root of the fake root looks like this:
drwxr-xr-x 2 root root 4096 Mar 19 17:08 bin/
drwxr-xr-x 2 root root 4096 Mar 19 17:26 dev/
drwxr-xr-x 2 root root 4096 Mar 17 11:59 etc/
drwxr-xr-x 2 root root 4096 Mar 19 17:37 lib/
drwxr-xr-x 2 root root 4096 Mar 17 12:41 sbin/
drwxrwxrwx 3 root root 4096 Mar 19 17:31 tmp/
drwxr-xr-x 3 root root 4096 Mar 17 12:04 usr/
drwxr-xr-x 4 root root 4096 Mar 25 08:45 var/
All the executable files and libraries were copied directly from a Slackware 7.1 distro. So too were the device files and the rgb.txt file. You will need to create an XF86Config file specific to the video card on your diskless X terminal. Just run xf86config on your server machine (make a backup of your /etc/XF86Config first), then copy /etc/XF86Config to the fakeroot area). You will need to change the FontPath in XF86Config. Basically , you should comment out all the FontPath lines and just have one:
In my case it was a Cirrus Logic GD5430 (which is part of the SVGA server). NB: Slackware 7.1 uses Xfree 3.3.something (ie. definately not 4.x)
I probably can still trim down the size of the fake root, most notably by using a slimmer init, but I'm happy with it for now. I also had to add quite a bit just to get the printer proxy (p910nd) to run. It requires libnss_files, /etc/protocols, /etc/nsswitch.conf and the /var/run and /var/lock/subsys directories. It could probably be modified to not require these.
The remaining files: inittab, rc.S and rc.5 were all created specifically for the X terminal build. They are tiny:
# Default runlevel. (Do not set to 0 or 6)
# System initialization (runs when system boots).
echo "System Startup"
/bin/XF86_SVGA -bpp 8 -query 10.0.0.1 >/tmp/log 2>&1
/sbin/reboot -n -f
The rc.S script isn't really required, but I left it in incase I need something specific in there later.
NB: The -query 10.0.0.1 above indicates the IP address of the server running xdm, which is my tftp, bootp ... etc server.
Setting up xdm
You may have xdm already running. Generally I boot up my server in console mode and run 'startx' if I want to use X. If you want to retain the ability to start in console mode, you need to edit /etc/X11/xdm/Xservers. There should be a line like:
:0 local /usr/X11R6/bin/X
Just put a # in front of it to comment it out. Now just start xdm. I have a line in /etc/rc.d/rc.local that just starts it when the machine boots up.
Set up the X font server
You may have to download xfs for Slackware or compile it yourself. You just need to run it usually (I find you need to put an & to background it). The config file is in /etc/X11/fs/config.
Set up a printer proxy
If you want to use the local printer attached to your diskless X terminal, you can use the p910nd proxy. It sets up a service to listen on port 9100 (or 9101, 2 ..) and just passes the data from any connections to the local printer. This is the same as old Jetdirect printers. Apparently, if you use the CUPS printer system then you simply configure the new remote printer in. However, Slackware still uses the old printcap style lpd which doesn't directly support these types of printers. However, p910nd comes with a perl script that you can set up as the input filter in a printcap definition which will do the socket connection to your remote printer for you. I just copied this script client.pl into /usr/local/bini, edited it to change the hostname it tries to contact and added a printcap entry like:
Stop and start lpd. Now copy p910nd under /bin in the fakeroot and add a line to rc.5 like:
Booting your diskless X terminal
It should now be a case of inserting the boot floppy and away you go. You should see the usual kernel console messages and then the screen shuold go black and hopefully you then get an xdm user/password prompt. Log in and voila! Wasn't such a chore was it.
I've now tried using 100Mbps LAN cards with my diskless workstations (as of 22.3.01) and sadly, there really isn't much of a speed improvement. 16 bit colour is not really that useable remotely. And I'd also recommend that you drag scroll bars rather than click the up and down icons (at the end of scroll bars).
Interestingly, I had a problem with starting X after I put in the 100Mbps cards. I had booted my P75 off its hard disk (so it wasn't acting as a diskless client) and then did a
X -query 10.0.0.1. Usually the xdm logon prompt on my server comes up almost immediately ... but not this time. The thing is I now had two LAN cards in my P75; a 10MBps card and a 10/100Mbps card. The 10Mbps card was not connected to any LAN but was configured as eth0, the 10/100 card was set up as eth1 and connected to my server. I think the problem is is that the X server was listening on eth0. xdm on the server somehow got a hold of this IP address and tried to connect to it ... but failed. My simple solution was to rearrange the order of the modprobe's in the OS startup so that the 10/100MBps card was probe'd first and hence became eth0.