old-www/LDP/LG/issue01to08/keys-n-consoles.html

825 lines
27 KiB
HTML

<HTML>
<!-- BEGIN HTML HEAD ==================================================== -->
<HEAD>
<TITLE>Linux Gazette Article -- Keyboards and Consoles</TITLE>
</HEAD>
<!-- END HTML HEAD ====================================================== -->
<!-- BEGIN HTML BODY ==================================================== -->
<BODY>
<H1><IMG ALIGN=MIDDLE SRC="../gx/lg_logo.gif">Keys &amp; Consoles</H1>
<H2>A Member of the Linux Documentation Project</H2>
<H4>&quot;The Linux Gazette...<I>making Linux just a little more fun...!</I>
&quot;</H4>
<H5>Copyright (c) 1996 John M. Fisk <I>fiskjm@ctrvax.vanderbilt.edu</I><BR>
The LINUX GAZETTE is a member of the LINUX DOCUMENTATION PROJECT.<BR></H5>
<HR>
<!-- ==================================================================== -->
<!-- ARTICLE ============================================================ -->
<H2><IMG ALIGN=BOTTOM SRC="../gx/text.gif">Of Keyboards and Consoles...</A></H2>
<P>
(The following article was submitted to the <A HREF="http://www.ssc.com">
Linux Journal</A> for publication and is being presented here with the permission
of the publisher of the Linux Journal -- John M. Fisk)
<P><HR><P>
<CENTER>
<H3>Keyboards, Consoles, and VT Cruising</H3>
by<BR>
John M. Fisk &lt;fiskjm@ctrvax.vanderbilt.edu&gt;<BR>
July 1, 1996<BR>
</CENTER>
<P>
&quot;It's a GUI, GUI, GUI, GUI world!&quot; -- or so the major OS
manufacturers would have you belief. Truth is, that while this is
increasingly the case, there are times when the command line interface
(CLI) is still a very good choice for getting things done. It's fast,
generally efficient, and is a good choice on memory or CPU constrained
machines. And don't forget that there are still a lot of very nifty
things that can be done &quot;at the console.&quot;
<P>
In this spirit, I'd like to start by following up on a delightful and
informative article written by Allesandro Rubini entitled &quot;The Best
Without X&quot; that appeared in the November, 1995 (Issue 19) edition
of the Linux Journal. Among a wealth of helpful ideas, Allesandro
suggested converting the numeric keypad into a &quot;console-switch
scratch pad&quot; to allow single key switching from one virtual
terminal (VT) to another. We'll begin by looking at how this can be
done. We'll also look at:
<UL>
<LI> Getting from Here to There: handy methods for VT cruising
<LI> The Useful Unused VT: where to put all that logging information
and where X Window really ends up
</UL>
<P>
By the time that you get through tinkering around with these things I
think you'll agree that the CLI isn't such a bad place after all :-)
Also, the good news is that the programs you'll need for this are
standard inclusions in most recent Linux distributions and include:
<UL>
<LI> kbd 0.91 (keyboard font and utility programs)
<LI> utils 2.5 (Rik Faith's huge collection of utilities)
<LI> GNU shell-utils 1.12 (shell utilities which includes
the 'stty' program
</UL>
<P>
A listing of Linux FTP archives where these may be found is included at
the end of this article.
<H3>THE KEYPAD VT-SWITCHER</H3>
<P>
The numeric keypad is an ideal candidate for remapping into a virtual
terminal (VT) switching scratch pad as most of us have never learned to
&quot;touch type&quot; using the keypad. In addition, on a 101-key
keyboard, its non-numeric functions are already duplicated by the Home,
End, Page Up, Page Down, Insert, Delete, and arrow keys. Since there
may be occasions in which we still want to use the keypad for numeric
input let's see how to set it up as a VT switcher while retaining
numeric input ability.
<P>
To do this you'll need to have the kbd package installed on your system.
The two programs we'll be using for this are the 'showkey' and 'loadkey'
programs. To check whether they are installed on your system you can
type in:
<PRE>
% type loadkeys showkey
</PRE>
<P>
if you're using the BASH shell, or:
<PRE>
% which loadkeys showkey
</PRE>
<P>
The 'which' program or the BASH shell built-in function 'type' will both
print the path to the executable if they exist in the PATH search path.
On my machine this produces:
<PRE>
~$ type showkey loadkeys
showkey is /usr/bin/showkey
loadkeys is /usr/bin/loadkeys
~$ which showkey loadkeys
/usr/bin/showkey
/usr/bin/loadkeys
</PRE>
<P>
If you don't have these programs installed you'll need to get the
sources for the kbd package and install it yourself. (This comes as
source only but installation is as simple as unachiving it into a
temporary directory and typing in 'make && make install').
<P>
Converting the keypad into VT switcher involves defining a keyboard
mapping and then using loadkeys to actually load this information into
the kernel keyboard translation tables. It's a whole lot easier than it
sounds although you must keep in mind that indiscriminate tinkering can
render your keyboard useless (requiring one of those dreaded cold
reboots) and that changing the keyboard translation tables affects ALL
VT's, not just the one you're working on.
<P>
The kbd package default installation location is under /usr/lib/kbd with
the key mapping files in the keytables subdirectory. Change to this
directory and make a copy of the defkeymap.map file. This is the
default keyboard mapping and is a useful place to start. You can call
the new file anything you'd like - e.g.,
<PRE>
cp defkeymap.map custom.map
</PRE>
<P>
Use your favorite editor and load up this file. At this point it's
probably helpful to stop for a moment and have a look around. It's
rather like visiting one of those fine old curio shops -- look, but
don't touch! The first few lines may look something like this:
<PRE>
keycode 1 = Escape Escape
alt keycode 1 = Meta_Escape
keycode 2 = one exclam
alt keycode 2 = Meta_one
shift alt keycode 2 = Meta_exclam
keycode 3 = two at at
control keycode 3 = nul
shift control keycode 3 = nul
alt keycode 3 = Meta_two
shift alt keycode 3 = Meta_at
</PRE>
<P>
I won't go into all the gory details of how to remap the keyboard except
to say that the basic format that we'll use is:
<PRE>
keycode keynumber = keysym
modifier keycode keynumber = keysym
</PRE>
<P>
in which 'keynumber' is the internal identification number of the key
and 'keysym' represents the action to take. Now before you bail out on
me let's put this into simple terms. Each key on the keyboard is
identified by a unique number which is represented by 'keynumber'. When
a key is pressed or released these events are passed to the operating
system which responds by performing the appropriate action --
represented here by 'keysym'. The 'modifier' is a key which is held
down at the same time that the key is pressed. These 'modifier' keys
include the well known control, alt, and shift keys. Being able to
define multi-key combinations extends the mapping available for each
key.
<P>
So, using the example above, pressing the key associated with keynumber
3 actually causes the number '2' to be printed to the screen. If the
shift key is held down at the same time as the key is pressed, the '@'
sign is printed to the screen, and if the three key combination
Shift+Alt+keynumber 3 is pressed, the output is the Meta_at (whatever
one of those looks like).
<P>
Getting back to the task at hand, what we want to do is change to a
specified VT when we press one of the keypad keys: pressing keypad 1
should switch to VT number 1, pressing keypad 2 should switch to VT
number 2, and so forth. In your customized key map file find the
section that defines the keypad keys -- it should look similar to this:
<PRE>
keycode 71 = KP_7
alt keycode 71 = Ascii_7
keycode 72 = KP_8
alt keycode 72 = Ascii_8
keycode 73 = KP_9
alt keycode 73 = Ascii_9
[...]
</PRE>
<P>
Now, edit this section so that it reads something like:
<PRE>
# NUMERIC KEYPAD MAPPING
#
# The section remaps the keypad keys so that they act as a
# VT-switcher: keypad 1 switches to VT 1, keypad 2 to VT 2,
# and so forth. Note that pressing Shift+key switches to a VT
# which is 10+ the number of the key (Shift+3 = VT 13) and that
# pressing Alt+key (when Num Lock is on) causes numeric output.
#
# Keypad number 7
#
keycode 71 = Console_7
shift keycode 71 = Console_17
alt keycode 71 = KP_7
alt control keycode 71 = Console_7
#
# Keypad number 8
#
keycode 72 = Console_8
shift keycode 72 = Console_18
alt keycode 72 = KP_8
alt control keycode 72 = Console_8
#
# Keypad number 9
#
keycode 73 = Console_9
shift keycode 73 = Console_19
alt keycode 73 = KP_9
alt control keycode 73 = Console_9
keycode 74 = KP_Subtract
#
# Keypad number 4
#
keycode 75 = Console_4
shift keycode 75 = Console_14
alt keycode 75 = KP_4
alt control keycode 75 = Console_4
#
# Keypad number 5
#
keycode 76 = Console_5
shift keycode 76 = Console_15
alt keycode 76 = KP_5
alt control keycode 76 = Console_5
#
# Keypad number 6
#
keycode 77 = Console_6
shift keycode 77 = Console_16
alt keycode 77 = KP_6
alt control keycode 77 = Console_6
keycode 78 = KP_Add
#
# Keypad number 1
#
keycode 79 = Console_1
shift keycode 79 = Console_11
alt keycode 79 = KP_1
alt control keycode 79 = Console_1
#
# Keypad number 2
#
keycode 80 = Console_2
shift keycode 80 = Console_12
alt keycode 80 = KP_2
alt control keycode 80 = Console_2
#
# Keypad number 3
#
keycode 81 = Console_3
shift keycode 81 = Console_13
alt keycode 81 = KP_3
alt control keycode 81 = Console_3
#
# Keypad number 0
#
keycode 82 = Last_Console
shift keycode 82 = Console_10
alt keycode 82 = KP_0
#
# Keypad '.' key
#
keycode 83 = KP_Period
altgr control keycode 83 = Boot
control alt keycode 83 = Boot
keycode 84 = Last_Console
</PRE>
<P>
Before going on let's make a couple observations. First, it's not a bad
idea to comment the file as you go. What's seems so clear and obvious
now quickly fades into obscurity as the weeks pass. Adding comments
will help prevent your having to pour back over manual pages, program
documentation, and magazine articles looking for the correct syntax or
usage.
<P>
Second, notice that with each entry there are &quot;sub-stanzas&quot; if
you will, that begin with the words &quot;alt keycode&quot; &quot;shift
keycode&quot; etc. These are the stanzas that define multi-key
combinations in which a &quot;modifier&quot; key is pressed at the same
time as the key being defined. A common example of this is the
&quot;Ctrl-C&quot; combination that is used to terminate a program in
execution.
<P>
Finally, you may be asking yourself how you're supposed to know which
keynumber is associated with a key. Anyone know off hand what keynumber
goes with the &quot; key? The way you find this out is using the
'showkey' program. After you invoke the program, showkey prints the
keynumber for any key that you hit (and quits after 10 seconds of no
input). So, now that we've already edited the pertinent section in the
'custom.map' file, let's see how we'd arrive at this &quot;from
scratch.&quot;
<P>
The basic steps we'd need to take would be to:
<UL>
<LI> find the keynumber for the keypad keys
<LI> edit the customized mapping for the keys so that pressing
them would change to the appropriate VT
<LI> edit the customized mapping for the keys so that the keypad
could still be used for numeric input (using a modifier key
combination in this case)
<LI> load the customized mapping and see whether it works
<LI> (optionally) having the default key mapping loaded at system
boot
</UL>
<P>
To do this, let's begin by using the 'showkey' program which can be
invoked using:
<PRE>
% showkey
</PRE>
<P>
Now, any key that you press causes showkey to print the keynumber. On
my machine, invoking showkey and pressing keypad keys 1 through 9
results in the following output:
<PRE>
~$ showkey
kb mode was XLATE
press any key (program terminates after 10s of last key press)...
keycode 79 press
keycode 79 release
keycode 80 press
keycode 80 release
keycode 81 press
keycode 81 release
keycode 75 press
keycode 75 release
keycode 76 press
keycode 76 release
keycode 77 press
keycode 77 release
keycode 71 press
keycode 71 release
keycode 72 press
keycode 72 release
keycode 73 press
keycode 73 release
</PRE>
<P>
You can see that both key press and key release events are detected.
Also note that the numbering of the keypad keys is not sequential. The
numeric keys have the following format:
<PRE>
Actual Key: Keynumber:
7 8 9 71 72 73
4 5 6 75 76 77
1 2 3 79 80 81
</PRE>
<P>
So that keypad number 1 has keynumber 79, keypad number 2 has keynumber
80, and so forth. Knowing this, we can now set up the appropriate key
map entry for each of these keys. The keysym event that we're
interested in is Console_x, in which 'x' is the number of the VT to
which the view is switched. So, a simple entry to map keypad number 1
to switching to VT 1 would look like:
<PRE>
keycode 79 = Console_1
</PRE>
<P>
If you look at the example given above, you'll notice that this is what
we've done. Suppose, however, that we wanted to switch to a VT greater
than 9, how are we to do that? The solution to this is to use a
modifier key combination. Looking again at the example above, using the
Shift key with the keypad allows us to use Console_10 through
Console_19.
<P>
We also wanted to be able to use the numeric keypad as just that -- a
means of entering numeric data. In the example above, notice that the
modifier 'alt' was used to do this:
<PRE>
keycode 71 = Console_7
shift keycode 71 = Console_17
alt keycode 71 = KP_7
alt control keycode 71 = Console_7
</PRE>
<P>
In this stanza for the keypad 7 key, the first entry maps the keypad 7
key to switch to VT 7. The second line maps Shift+keypad 7 to switch to
VT 17 and the third line maps the Alt+keypad 7 combination to KP_7 which
is the keysym for numeric output when Num Lock is 'on'. Thus, to use
the keypad as a numeric keypad, hit the Num Lock key so that it toggles
to 'on' and then hold down the Alt key while you enter numbers at the
keypad.
<P>
Note, too, that in this example, Alt+Ctrl+keypad was defined to switch
to the same console as simply pressing the keypad key itself. In this
case, it acts in exactly the same fashion as occurs when the the Alt+Fn
(Alt + Function key) or Alt+Ctrl+Fn (Alt + Ctrl + Function key)
combination is used. The intuitive will immediately have noticed that
this is how one is typically instructed to switch from one VT to
another. Looking at the stanzas for the function keys you'll notice
entries such as the following:
<PRE>
keycode 59 = F1 F13 Console_13
control keycode 59 = F25
shift control keycode 59 = F37
alt keycode 59 = Console_1
control alt keycode 59 = Console_1
</PRE>
<P>
Note that both Alt+F1 and Alt+Ctrl+F1 are used to switch to VT 1. Those
of you using X will probably already have found that switching to a VT
from X requires the three key Alt+Ctrl+Fn key combination while the two
key Alt+Fn key combination is used at the console. Obviously, while you
can change this default behavior it's best to leave this as is.
<P>
So, at this point, we've defined mappings for the keypad keys such that
each key acts as a switch to the VT of the same number. Using
Shift+keypad key switches to VT (10 + keypad number) and using
Alt+keypad key with the Num Lock 'on' outputs the numeric value of the
key. The final step is to actually load the new mapping and give it a
try. This is done using 'loadkeys' and can be done without having to
log in as root. To load the customized keymap enter:
<PRE>
% loadkeys /usr/lib/kbd/keytables/custom.map
</PRE>
<P>
This will print a message indicating that the 'custom.map' file is being
loaded. After this, you're all set! Give it a try. To revert back to
the default mapping simply enter:
<PRE>
% loadkeys /usr/lib/kbd/keytables/defkeymap.map
</PRE>
<P>
and the default mappings will be loaded once again. You can use this
edit -&gt; load customized map -&gt; test -&gt; load default map cycle
to get the mapping that you want. Once you've created a custom map file
and wish to have it loaded at boot, you can add an entry to one of the
rc.* files, such as rc.local, to have loadkeys automatically load your
customized mapping:
<PRE>
if [ -r /usr/lib/kbd/keytables/custom.map ]; then
loadkeys /usr/lib/kbd/keytables/custom.map
fi
</PRE>
<P>
This ensures that the file is present and readable and then invokes
loadkeys to load the file. Again, keep in mind that loading a key
mapping changes the keytable information for ALL VT's, not just the one
you are working on.
<H3>GETTING FROM HERE TO THERE</H3>
Now that we're on a bit of a roll, let's see how else we can move from
one VT to another. The utility of being able to quickly switch from one
VT to another should be obvious: you can be compiling a program on VT
1, editing a file on VT 2, reading program documentation on VT 3, and
have a manual page displayed on VT 4. Now that you've remapped the
keypad, switching from one VT to the next is as simple as pressing the
keypad keys. But there are other handy means of getting around as well
and these include:
<UL>
<LT> using the keysym functions Last_Console, Incr_Console, and Decr_Console
<LT> using the 'chvt' program (which is part of the kbd package)
</UL>
<P>
The Incr_Console and Decr_Console keysym do as their names might imply:
they switch to (VT + 1) or (VT - 1) respectively. So, if you were
currently working at VT 3, the Incr_Console keysym would switch you to
VT 4 while the Decr_Console keysym would switch you to VT 2. The
Last_Console keysym also does as its name might imply: it switches to
the last VT that you were previously at. If you were working at VT 3
and switched to VT 6, the Last_Console keysym would switch you back to
VT 3.
<P>
You can map a key or modifier+key combination to invoke any of these
keysyms. I've mapped these to:
<PRE>
Ctrl+left arrow = Decr_Console
Ctrl+right arrow = Incr_Console
keypad 0 = Last_Console
</PRE>
<P>
Obviously, you can map these in any manner you wish, but the relevant
entries to map the above actions would be:
<PRE>
#keycode 82 = KP_0
keycode 82 = Last_Console
shift keycode 82 = Console_10
alt keycode 82 = KP_0
[...]
keycode 105 = Left
alt keycode 105 = Decr_Console
keycode 106 = Right
alt keycode 106 = Incr_Console
</PRE>
<P>
These entries map the keypad 0 key to the Last_Console keysym and the
Alt+ left or right arrows to Decr_Console or Incr_Console keysyms. The
good news is that these last two are already the default so that you
only have to edit the stanza for the keypad 0 key. Now, you can quickly
cycle through all the VT's by holding down the Alt key and repeatedly
pressing the left or right arrow. To alternate between two VT's you
have only to repeatedly hit the keypad 0 key. I've found these mappings
to be quite useful but, as has been mentioned before, they can be
customized to anything that you find helpful.
<P>
The last bit of VT cruising magic is the 'chvt' program which is
included with the kbd package. It's use is quite simple:
<PRE>
% chvt 3
</PRE>
<P>
would change to VT 3. Substituting another number for '3' allows you to
change to that VT. A foreshortened version of this can be set up using
a shell alias:
<PRE>
% alias vt='chvt'
</PRE>
<P>
so that entering:
<PRE>
% vt 3
</PRE>
<P>
would switch you to VT 3.
<P>
So, now that we've defined several methods of getting from VT to VT it
is important to note that works only at the console and not under the X
Window system. Under X, the X server takes control of the keyboard,
mouse, and display: setting up customized keyboard mappings is
performed using the ~/.Xmodmap file or the program 'xkeycaps' and is a
subject for some later article :-)
<H3>THE USEFUL UNUSED VT</H3>
Having the capacity to open multiple VT's and have programs running on
these in the foreground or background is one of the things that makes
running Linux such a huge amount of fun. As the old Surgery Prof used
to harangue against his interns, &quot;Help me, help me! If I had
another set of hands I'd help myself!&quot; Linux gives you that extra
&quot;set of hands.&quot; Generally, most VT's, to be useful, must have
a 'getty' running on it in order to log in. A 'getty' is a program
which is associated with a terminal and which:
<UL>
<LI> opens the tty line and sets its mode
<LI> prints the login prompt and gets the user's name
<LI> initiates the login process for the user
</UL>
<P>
Without going into all the details of this (again, a subject for a later
article) suffice it to say that this is set up in the /etc/inittab file.
A sample entry for this might look like:
<PRE>
# The getties in multi user mode on consoles an serial lines.
#
# NOTE NOTE NOTE adjust this to your getty or you will not be
# able to login !!
#
# Note: for 'agetty' you use linespeed, line.
# for 'getty_ps' you use line, linespeed and also use 'gettydefs'
c1:1235:respawn:/sbin/agetty 38400 tty1 linux
c2:1235:respawn:/sbin/agetty 38400 tty2 linux
c3:5:respawn:/sbin/agetty 38400 tty3 linux
c4:5:respawn:/sbin/agetty 38400 tty4 linux
c5:5:respawn:/sbin/agetty 38400 tty5 linux
c6:45:respawn:/sbin/agetty 38400 tty6 linux
</PRE>
<P>
The important thing to note here is that the 'agetty' program is run on
each of the tty devices from tty1 to tty6. Thus, at system startup
there are a total of six getty's running allowing you to log in to VT 1
through 6. So what about VT 7 and beyond? Are they still usable in any
way?
<P>
If you've remapped you keyboard, try pressing keypad 7 -- alternatively,
hit Alt-F7 -- and see what happens. In general, the screen is blank
with the cursor positioned at the upper left corner. You can type in at
the keyboard and the output is displayed on the screen. Despite this,
there is no way to execute programs at this terminal. Now you see the
purpose of the 'getty' program: without being able to log in at a
terminal it really isn't much use. There are, however, two important
exceptions to this.
<H3>SO WHERE DID X GO...?</H3>
The first is to note that when the X Window system starts, it is
displayed on the first unused tty -- one that doesn't have a getty
running on it. Since the first six tty's had getty's running on them, X
would, in the example above, start on tty 7. This is the solution to
the great riddle of, &quot;so where is X ?!&quot; when you switch from X
to a console. Hitting Ctrl+Alt+F1 in X would switch you to VT 1. If
you wanted to get back to X simply:
<UL>
<LI> hit keypad 0 if you've mapped this to the Last_Console keysym
<LI> hit keypad 7 to switch to VT 7 on which X is running
<LI> hit Alt+F7 to switch to Vt 7
</UL>
<P>
You get the idea.
<H3>PUTTING THAT UNUSED VT TO WORK...</H3>
<P>
The other thing to note is that while you can't run programs on a VT
without logging in, you can still send output there. As a simple
experiment try the following:
<PRE>
% echo &quot;This is a test&quot; &gt; /dev/tty7
</PRE>
<P>
Switching to VT 7, you'll see the words, &quot;This is a test&quot;
displayed. This becomes useful with system logging. Without going into
an exhaustive discussion of system logging and configuration, it is
worth noting that the output of all logging facilities can be
&quot;dumped&quot; to an unused VT which allows quick perusal for events
such as login's, kernel messages, mail logging, and so forth.
<P>
To do this simply add the following line to the /etc/syslog.conf file
(after logging in as root):
<PRE>
# this one will log ALL messages to the /dev/tty9 terminal
# since this is an unused terminal at the moment. This way, we
# don't need to hang a getty on it or take up a lot of system resources.
*.* /dev/tty9
</PRE>
<P>
Once you've added this stanza to /etc/syslog.conf, you'll need to either
kill and restart the syslog daemon or else send it the HUP (hang up)
signal. Since this latter method is fairly easy let's do it:
<PRE>
% ps -x | grep syslog
28 ? S 0:01 /usr/sbin/syslogd
</PRE>
<P>
will output the PID (process ID number) of the syslog daemon which in
this case is 28. Now, just type in:
<PRE>
% kill -HUP 28
</PRE>
<P>
in which '28' is the PID number. The syslog daemon will then re-read
its initialization files. From here on, all logging that occurs,
regardless of its source, will be output to tty9 (or whichever tty
device you specify).
<P>
Switching to VT 9 you might see something like the following:
<PRE>
Jul 1 10:11:37 FiskHaus kernel: Max size:342694 Log zone size:2048
Jul 1 10:11:38 FiskHaus kernel: First datazone:68 Root inode number 139264
Jul 1 10:11:38 FiskHaus kernel: ISO9660 Extensions: RRIP_1991A
Jul 1 12:21:50 FiskHaus login: ROOT LOGIN ON tty2
Jul 1 17:26:56 FiskHaus login: 1 LOGIN FAILURE ON tty5, fiskjm
</PRE>
<P>
The first three lines represent kernel messages that occur when a CD was
mounted. Root logins are noted by the 'login' program as well as login
failures -- in this last case I purposely entered an incorrect password.
<P>
The value of all of this logging may not be immediately evident, but if
you've ever noticed that your machine begins thrashing about and
swapping like crazy or that, while online, your hard drive lights begin
to light up when you're not doing anything -- a quick switch to VT 9 can
often give you an idea about what's going on.
<P>
Well, all of this should get you going! The manual pages for
'loadkeys', 'showkey', and 'keytables' have much more complete technical
descriptions of key mapping. Also, the kbd package comes with a good
deal of helpful documentation in its /doc subdirectory. And finally,
don't forget the Keyboard-HOWTO which can be found amongst the growing
number of Linux HOWTO's.
<P><HR><P>
<H3>APPENDIX:</H3>
FTP sites where programs can be found:
<P>
kbd-0.91.tar.gz:<BR>
ftp://ftp.cc.gatech.edu/pub/linux/systems/Keyboards/kbd-0.91.tar.gz<BR><BR>
util-linux-2.5.tar.gz<BR>
ftp://ftp.cc.gatech.edu/pub/linux/systems/Misc/util-linux-2.5.tar.gz<BR><BR>
sh-utils-1.12-bin.ELF.tar.gz<BR>
sh-utils-1.12-bin.tar.gz<BR>
ftp://ftp.cc.gatech.edu/pub/linux/utils/shell/sh-utils-1.12-bin.ELF.tar.gz<BR>
ftp://ftp.cc.gatech.edu/pub/linux/utils/shell/sh-utils-1.12-bin.tar.gz<BR><BR>
Keyboard-HOWTO<BR>
ftp://ftp.cc.gatech.edu/pub/linux/docs/HOWTO/Keyboard-HOWTO
<P>
Note that the FTP site is GA Tech -- a Sunsite mirror. Please check the
MIRRORS file in the /pub/Linux subdirectory for a site nearest you.
<P>
<HR>
<!-- ===================================================================== -->
<!-- FOOTER ============================================================== -->
<BR>
<H3><A HREF="./lg_issue8.html">Back to Linux Gazette #8 </A></H3>
<I>This page written and maintained by:</I><BR>
<ADDRESS>
<A HREF="./jmf.html">John M. Fisk</A> at <A HREF="mailto:fiskjm@ctrvax.vanderbilt.edu">
fiskjm@ctrvax.vanderbilt.edu</A>
</ADDRESS>
<!-- END HTML BODY ======================================================= -->
</BODY>
</HTML>