LPI Certification 102 Exam Prep, Part 1
LPI Certification 102 Exam Prep, Part 1
Table of Contents
If you're viewing this document online, you can click any of the topics below to link directly to that section.
By the end of this series of tutorials (eight in all), you'll have the knowledge you need to
become a Linux Systems Administrator and will be ready to attain an LPIC Level 1
certification from the Linux Professional Institute if you so choose.
If you are new to Linux, we recommend that you first complete the LPI certification 101 exam
prep series of tutorials, which includes Part 1: Linux fundamentals, Part 2: Basic
administration, Part 3: Intermediate administration, and Part 4: Advanced administration
before continuing.
Daniel Robbins lives in Albuquerque, New Mexico, and is the President/CEO of Gentoo
Technologies, Inc., the creator of Gentoo Linux, an advanced Linux for the PC, and the
Portage system, a next-generation ports system for Linux. He has also served as a
contributing author for the Macmillan books Caldera OpenLinux Unleashed, SuSE Linux
Unleashed, and Samba Unleashed. Daniel has been involved with computers in some
fashion since the second grade, when he was first exposed to the Logo programming
language as well as a potentially dangerous dose of Pac Man. This probably explains why he
has since served as a Lead Graphic Artist at Sony Electronic Publishing/Psygnosis. Daniel
enjoys spending time with his wife, Mary, and their daughter, Hadassah.
Chris Houser, known to many of his friends as "Chouser," has been a UNIX proponent since
1994 when he joined the administration team for the computer science network at Taylor
University in Indiana, where he earned his Bachelor's degree in Computer Science and
Mathematics. Since then, he has gone on to work in Web application programming, user
interface design, professional video software support, and now Tru64 UNIX device driver
programming at Compaq. He has also contributed to various free software projects, most
recently to Gentoo Linux. He lives with his wife and two cats in New Hampshire.
Aron Griffis graduated from Taylor University with a degree in Computer Science and an
award that proclaimed, "Future Founder of a Utopian UNIX Commune." Working towards that
goal, Aron is employed by Compaq writing network drivers for Tru64 UNIX and spending his
spare time plunking out tunes on the piano or developing Gentoo Linux. He lives with his
wife, Amy (also a UNIX engineer), in Nashua, New Hampshire.
The second are dynamically linked executables. We'll get into those in the next panel.
# ldd /sbin/sln
not a dynamic executable
"not a dynamic executable" is ldd's way of saying that sln is statically linked. Now, let's take
a look at sln's size in comparison to its non-static cousin, ln:
# ls -l /bin/ln /sbin/sln
-rwxr-xr-x 1 root root 23000 Jan 14 00:36 /bin/ln
-rwxr-xr-x 1 root root 381072 Jan 14 00:31 /sbin/sln
As you can see, sln is over ten times the size of ln. ln is so much smaller than sln
because it is a dynamic executable. Dynamic executables are incomplete programs that
depend on external shared libraries to provide many of the functions that they need to run.
# ldd /bin/ln
libc.so.6 => /lib/libc.so.6 (0x40021000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
As you can see, ln depends on the external shared libraries libc.so.6 and
ld-linux.so.2. As a rule, dynamically linked programs are much smaller than their
statically-linked equivalents. However, statically-linked programs come in handy for certain
low-level maintenance tasks. For example, sln is the perfect tool to modify various library
symbolic links that exist in /lib. But in general, you'll find that nearly all executables on a
Linux system are of the dynamically linked variety.
the job of loading them along with any necessary shared libraries so that they can execute
correctly? The answer is something called the dynamic loader, which is actually the
ld-linux.so.2 library that you see listed as a shared library dependency in ln's ldd
listing. The dynamic loader takes care of loading the shared libraries that dynamically linked
executables need in order to run. Now, let's take a quick look at how the dynamic loader
finds the appropriate shared libraries on your system.
ld.so.conf
The dynamic loader finds shared libraries thanks to two files -- /etc/ld.so.conf and
/etc/ld.so.cache. If you cat your /etc/ld.so.conf file, you'll probably see a listing
that looks something like this:
$ cat /etc/ld.so.conf
/usr/X11R6/lib
/usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3
/usr/lib/mozilla
/usr/lib/qt-x11-2.3.1/lib
/usr/local/lib
The ld.so.conf file contains a listing of all directories (besides /lib and /usr/lib,
which are automatically included) in which the dynamic loader will look for shared libraries.
ld.so.cache
But before the dynamic loader can "see" this information, it must be converted into an
ld.so.cache file. This is done by running the ldconfig command:
# ldconfig
When ldconfig completes, you now have an up-to-date /etc/ld.so.cache file that reflects
any changes you've made to /etc/ld.so.conf. From this point forward, the dynamic
loader will look in any new directories that you specified in /etc/ld.so.conf when looking
for shared libraries.
ldconfig tips
To view all the shared libraries that ldconfig can "see," type:
# ldconfig -p | less
There's one other handy trick you can use to configure your shared library paths. Sometimes,
you'll want to tell the dynamic loader to try to use shared libraries in a specific directory
before trying any of your /etc/ld.so.conf paths. This can be handy in situations where
you are running an older application that doesn't work with the currently-installed versions of
your libraries.
LD_LIBRARY_PATH
To instruct the dynamic loader to check a certain directory first, set the LD_LIBRARY_PATH
variable to the directories that you would like searched. Separate multiple paths using
commas; for example:
# export LD_LIBRARY_PATH="/usr/lib/old:/opt/lib"
After LD_LIBRARY_PATH has been exported, any executables started from the current shell
will use libraries in /usr/lib/old or /opt/lib if possible, falling back to the directories
specified in /etc/ld.so.conf if some shared library dependencies are still unsatisfied.
We've completed our coverage of Linux shared libraries. To learn more about shared
libraries, type man ldconfig and man ld.so.
Whatever the reason, whether of necessity or simply just because you want to compile the
program from its sources, this section will show you how.
Downloading
Your first step will be to locate and download the sources that you want to compile. They'll
probably be in a single archive with a trailing .tar.gz, tar.Z, tar.bz2, or .tgz extension. Go
ahead and download the archive with your favorite browser or ftp program. If the program
happens to have a Web page, this would be a good time to visit it to familiarize yourself with
any installation documentation that may be available.
The program you're installing could depend on the existence of any number of other
programs that may or may not be currently installed on your system. If you know for sure that
your program depends on other programs or libraries that are not currently installed, you'll
need to get these packages installed first (either from a binary package like rpm or by
compiling them from their sources also.) Then, you'll be in a great position to get your original
source file successfully installed.
Unpacking
Unpacking the source archive is relatively easy. If the name of your archive ends with
.tar.gz, .tar.Z, or .tgz, you should be able to unpack the archive by typing:
(x is for extract, z is for gzip decompression, v is for verbose (print the files that are
extracted), and f means that the filename will appear next on the command line.)
Nearly all "source tarballs" will create one main directory that contains all the program's
sources. This way, when you unpack the archive, your current working directory isn't
cluttered with lots of files -- instead, all files are neatly organized in a single directory and
don't get in the way.
Listing archives
Every now and then, you may come across an archive that, when decompressed, creates
tons of files in your current working directory. While most tarballs aren't created this way, it's
been known to happen. If you want to verify that your particular tarball was put together
correctly and creates a main directory to hold the sources, you can view its contents by
typing:
If there is no common directory listed on the left-hand side of the archive listing, you'll want to
create a new directory, move the tarball inside it, enter the directory, and only then extract
the tarball. Otherwise, you'll be in for a mess!
Because bzip2 has been gaining popularity, many Linux distributions come with versions of
tar that have been patched so that passing a y or i option will inform tar that the archive is in
bzip2 format and needs to be automatically decompressed with the bzip2 program. To see if
you have a patched version of tar, try typing:
or
If neither of these commands work (and tar complains of an invalid argument), there is still
hope -- read on.
bzip2 pipelines
So, your version of tar doesn't recognize those handy bzip2 shortcuts -- what can be done?
Fortunately, there's an easy way to extract the contents of bzip2 tarballs that will work on
nearly all UNIX systems, even if the system in question happens to have a non-GNU version
of tar. To view the contents of a bzip2 file, we can create a pipeline:
If you used the pipeline method to try to extract the contents of your archive and your system
complained that bzip2 couldn't be found, it's possible that bzip2 isn't installed on your system.
You can download the sources to bzip2 from http://sourceware.cygnus.com/bzip2. After
installing the bzip2 sources (by following this tutorial), you'll then be able to unpack and
install the application you wanted to install in the first place :)
Inspecting sources
Once you've unpacked your sources, you'll want to enter the unpacked directory and check
things out. It's always a good idea to locate any installation-related documentation. Typically,
this information can be found in a README or INSTALL file located in the main source
directory. Additionally, look for README.platform and INSTALL.platform files, where
platform is the name of your particular operating system.
Configuration
Many modern sources contain a configure script in the main source directory. This script
(typically generated by the developers using the GNU autoconf program) is specially
designed to set up the sources so that they compile perfectly on your system. When run, the
configure script probes your system, determining its capabilities, and creates Makefiles,
which contain instructions for building and installing the sources on your system.
The configure script is almost always called "configure." If you find a configure script in the
main source directory, odds are good that it was put there for your use. If you can't find a
configure script, then your sources probably come with a standard Makefile that has been
designed to work across a variety of systems -- this means that you can skip the following
configuration steps, and resume this tutorial where we start talking about "make."
Using configure
Before running the configure script, it's a good idea to get familiar with it. By typing
./configure --help, you can view all the various configuration options that are available
for your program. Many of the options you see, especially the ones listed at the top of the
--help printout, are standard options that will be found in nearly every configure script. The
options listed near the end are often related to the particular package you're trying to
compile. Take a look at them and note any you'd like to enable or disable.
Using --prefix
If you'd like the sources to install somewhere else, say in ./usr, you'll want to pass the
--prefix=/usr option to configure. Likewise, you could also tell configure to install to your
/opt tree, by using the --prefix=/opt option.
This capability comes in very handy, since most source archives aren't yet FHS-compliant.
Nearly always, you'll need to add a --mandir=/usr/share/man and a
--infodir=/usr/share/info to the configure command line in order to make your
source package FHS-compliant.
Time to configure
Once you've taken a look at the various configure options and determined which ones you'd
like to use, it's time to run configure. Please note that you may not need to include any
command-line options when you run configure -- in the majority of situations, the defaults will
work (but may not be exactly what you want).
$ ./configure <options>
$ ./configure
or
The options you need will depend on the particular package you're configuring. When you
run configure, it will spend a minute or two detecting what particular features or tools are
available on your system, printing out the results of its various configuration checks as it
goes.
config.cache
Once the configuration process completes, the configure script stores all its configuration
data in a file called config.cache. This file lives in the same directory as the configure
script itself. If you ever need to run ./configure again after you've updated your system
configuration, make sure you rm config.cache first; otherwise, configure will simply use
the old settings without rechecking your system.
Makefile intro
Makefiles are typically named makefile or Makefile. There will normally be one makefile
in each directory that contains source files, in addition to one that sits in the main source
directory. The autoconf-generated Makefiles contain instructions (officially called rules) that
specify how to build certain targets, like the program you want to install. make figures out the
order in which all the rules should run.
Invoking make
Invoking make is easy; just type "make" in the current directory. The make program will then
find and interpret a file called makefile or Makefile in the current directory. If you type
"make" all by itself, it will build the default target. Developers normally set up their makefiles
so that the default target compiles all the sources:
$ make
Some makefiles won't have a default target, and you'll need to specify one in order to get the
compilation started:
$ make all
After typing one of these commands, your computer will spend several minutes compiling
your program into object code. Presuming it completes with no errors, you'll be ready to
install the compiled program onto your system.
Installation
After the program is compiled, there's one more important step: installation. Although the
program is compiled, it's not yet ready for use. All its components need to be copied from the
source directory to the correct "live" locations on your filesystem. For example, all binaries
need to be copied to /usr/local/bin, and all man pages need to be installed into
/usr/local/man, etc.
Before you can install the software, you'll need to become root. This is typically done by
either logging in as root on a separate terminal or typing "su," at which point you'll be
prompted for root's password. After typing it in, you'll have root privileges until you exit from
your current shell session by typing "exit" or hitting control-D. If you're already root, you're
ready to go!
make install
Installing sources is easy. In the main source directory, simply type:
# make install
Typing "make install" will tell make to satisfy the "install" target; this target is traditionally used
to copy all the freshly created source files to the correct locations on disk so that your
program can be used. If you didn't specify a --prefix option, it's very likely that quite a few
files and directories will be copied to your /usr/local tree. Depending on the size of the
program, the install target may take anywhere from several seconds to a few minutes to
complete.
In addition to simply copying files, make install will also make sure the installed files have the
correct ownership and permissions. After make install completes successfully, the
program is installed and ready (or almost ready) for use!
$ man programname
It's possible that a program may require additional configuration steps. For example, if you
installed a Web server, you'll need to configure it to start automatically when your system
boots. You may also need to customize a configuration file in /etc before your application
will run.
Ta da!
Now that you've fully installed a particular software package from its sources, you can now
run it! To start the program, type:
$ programname
Congratulations!
Possible problems
It's very possible that configure or make, or possibly even make install, aborted with some
kind of error code. The next several panels will help you correct common problems.
Missing libraries
Every now and then, you may experience a problem where configure bombs out because
you don't have a certain library installed. In order for you to continue the build process, you'll
need to temporarily put your current program configuration on hold and track down the
sources or binary package for the library that your program needs. Once the correct library is
installed, configure or make should be happy and complete successfully.
Other problems
Sometimes, you'll run into some kind of error that you simply don't know how to fix. As your
experience with UNIX/Linux grows, you'll be able to diagnose more and more seemingly
cryptic error conditions that you encounter during the configure and make process.
Sometimes, errors occur because an installed library is too old (or possibly even too new!).
Other times, the problem you're having is actually the fault of the developers, who may not
have anticipated their program running on a system such as yours -- or maybe they just
made a typo :)
There is some truth to these statements, but the general consensus among Linux users is
that the advantages outweigh the disadvantages. Additionally, each stumbling block listed
above has a corresponding rebuttal: Multiple packages can be built to optimize for different
systems; package managers can be augmented to resolve dependencies automatically;
databases can be rebuilt based on other files; and the initial effort expended in creating a
package is mitigated by the ease of upgrading or removing that package later.
The rpm program has a command-line interface by default, although there are GUIs and
Web-based tools to provide a friendlier interface. In this section we'll introduce the most
common command-line operations, using the Xsnow program for the examples. If you would
like to follow along, you can download rpm below, which should work on most rpm-based
distributions.
• xsnow-1.41-1.i386.rpm
Note: If you find the various uses of the term "rpm" confusing in this section, keep in mind
that "rpm" usually refers to the program, whereas "an rpm" or "the rpm" usually refers to an
rpm package.
Installing an rpm
To get started, let's install our Xsnow rpm using rpm -i:
# rpm -i xsnow-1.41-1.i386.rpm
If this command produced no output, then it worked! You should be able to run Xsnow to
enjoy a blizzard on your X desktop. Personally, we prefer to have some visual feedback
when we install an rpm, so we like to include the -h (hash marks to indicate progress) and
-v (verbose) options:
Re-installing an rpm
If you were following along directly, you might have seen the following message from rpm in
the previous example:
There may be occasions when you wish to re-install an rpm, for instance if you were to
accidentally delete the binary /usr/X11R6/bin/xsnow. In that case, you should first
remove the rpm with rpm -e, then re-install it. Note that the information message from rpm
in the following example does not hinder the removal of the package from the system:
# rpm -e xsnow
removal of /usr/X11R6/bin/xsnow failed: No such file or directory
# rpm -e xsnow
error: removing these packages would break dependencies:
/usr/X11R6/bin/xsnow is needed by x-amusements-1.0-1
In that case, you could re-install Xsnow using the --force option:
You can also use --nodeps when installing an rpm. To re-iterate what was said above,
using --nodeps is not recommended, however it is sometimes necessary:
Upgrading packages
Eventually there will probably be an rpm of Xsnow version 1.42, which is available on the
Xsnow author's Website. When that occurs, you'll want to upgrade your existing Xsnow
installation. If you were to use rpm -ivh --force, it would appear to work, but rpm's
internal database would list both versions as being installed. Instead, you should use rpm
-U to upgrade your installation:
Here's a little trick: we rarely use rpm -i at all, because rpm -U will simply install an rpm if
it doesn't exist yet on the system. This is especially useful if you specify multiple packages on
the command-line, where some are currently installed and some are not:
# rpm -q xsnow
xsnow-1.41-1
In fact, rpm knows even more about the installed package than just the name and version.
We can ask for a lot more information about the Xsnow rpm using rpm -qi:
Combined with the -c option or the -d option, you can restrict the output to configuration or
documentation files, respectively. This type of query is more useful for larger rpms with long
file lists, but we can still demonstrate using the Xsnow rpm:
# rpm -qa | wc -l
287
# rpm -qal | wc -l
45706
Here's a quick tip: Using rpm -qa can ease the administration of multiple systems. If you
redirect the sorted output to a file on one machine, then do the same on the other machine,
you can use the diff program to see the differences.
# rpm -qa | while read p; do rpm -ql $p | grep -q '^/usr/X11R6/bin/xsnow$' && echo $p; d
xsnow-1.41-1
Since this takes a long time to type, and even longer to run (1m50s on one of our Pentiums),
the rpm developers thoughtfully included the capability in rpm. You can query for the owner
of a given file using rpm -qf:
Even on the Pentium, that only takes 0.3s to run. And even fast typists will enjoy the
simplicity of rpm -qf compared to the complex shell construction :)
Showing dependencies
Unless you employ options such as --nodeps, rpm normally won't allow you to install or
remove packages that break dependencies. For example, you can't install Xsnow without first
having the X libraries on your system. Once you have Xsnow installed, you can't remove the
X libraries without removing Xsnow first (and probably half of your installed packages).
This is a strength of rpm, even if it's frustrating sometimes. It means that when you install an
rpm, it should just work. You shouldn't need to do much extra work, since rpm has already
verified that the dependencies exist on the system.
You can also query the installed database for the same information by omitting the -p:
Wait a minute! According to that output, the GPG signature is NOT OK. Let's add some
verbosity to see what's wrong:
So, the problem is that we couldn't retrieve the author's public key. After we retrieve the
public key from the package author's Website (shown in the output from rpm -qi), the
signature checks out:
# rpm -V xsnow
Normally this command displays no output to indicate a clean bill of health. Let's spice things
up and try again:
# rm /usr/X11R6/man/man1/xsnow.1x.gz
# cp /bin/sh /usr/X11R6/bin/xsnow
# rpm -V xsnow
S.5....T /usr/X11R6/bin/xsnow
missing /usr/X11R6/man/man1/xsnow.1x.gz
This output shows us that the Xsnow binary fails MD5 sum, file size, and mtime tests. And
the man page is missing altogether! Let's repair this broken installation:
# rpm -e xsnow
removal of /usr/X11R6/man/man1/xsnow.1x.gz failed: No such file or directory
Configuring rpm
Rpm rarely needs configuring. It simply works out of the box. In older versions of rpm, you
could change things in /etc/rpmrc to affect run-time operation. In recent versions, that file
has been moved to /usr/lib/rpm/rpmrc, and is not meant to be edited by system
administrators. Mostly it just lists flags and compatibility information for various platforms
(e.g. i386 is compatible with all other x86 architectures).
If you wish to configure rpm, you can do so by editing /etc/rpm/macros. Since this is
rarely necessary, we'll let you read about it in the rpm bundled documentation. You can find
the right documentation file with the following command:
Skimming through this output, you can see that Xsnow was to be installed, then it was
fetched it from the Web, unpacked, and finally set up.
Simulated install
If apt-get notices that the package you are trying to install depends on other packages, it will
automatically fetch and install those as well. In the last example, only Xsnow was installed,
because all of it's dependencies were already satisfied.
Sometimes, however, the list of packages apt-get needs to fetch can be quite large, and it is
often useful to see what is going to installed before you let it start. The -s option does
exactly this. For example, on one of our systems if we try to install the graphical e-mail
program balsa:
It then goes on to list the order in which the packages will be installed and configured (or set
up).
# apt-setup
This tool walks you through the process of finding places to get Debian packages, such as
CDROMs, Web sites, and ftp sites. When you're done, it writes out changes to your
/etc/apt/sources.list file, so that apt-get can find packages when you ask for them.
apt-get also has many other commands besides the install command we've used so far.
One of these is apt-get dselect-upgrade, which obeys the Status set for each package
on your Debian system.
Starting dselect
The Status for each package is stored in the file /var/lib/dpkg/status, but it is best
updated using another interactive tool:
# dselect
Debian GNU/Linux `dselect' package handling frontend.
Move around with ^P and ^N, cursor keys, initial letters, or digits;
Press <enter> to confirm selection. ^L redraws screen.
You can view and change each package's Status by choosing the Select option. It will then
display a screenful of help. When you're done reading this, press space. Now you will see a
list of packages that looks something like this:
To change the Mark, just press the key for the code you want (equal, dash, or underline), but
if you want to change the Mark to * (asterisk), you have to press + (plus).
When you are done, use an upper-case Q to save your changes and exit the Select screen. If
you need help at any time in dselect, type ? (question mark). Type a space to get back out
of a help screen.
There are other ways to run these steps. For example, you can choose each step individually
from the main dselect menu.
Some packages use a system called debconf for their Configure step. Those that do can
ask their setup questions in a variety of ways, such as in a text terminal, through a graphical
interface, or through a Web page. To configure one of these packages, use the
dpkg-reconfigure command. You can even use it to make sure all debconf packages
have been completely configured:
# dpkg-reconfigure --all
debconf: package "3c5x9utils" is not installed or does not use debconf
debconf: package "3dchess" is not installed or does not use debconf
debconf: package "9menu" is not installed or does not use debconf
debconf: package "9wm" is not installed or does not use debconf
debconf: package "a2ps" is not installed or does not use debconf
debconf: package "a2ps-perl-ja" is not installed or does not use debconf
debconf: package "aalib-bin" is not installed or does not use debconf
This will produce a very long list of packages that do not use debconf, but it will also find
some that do and present easy-to-use forms for you to answer the questions that each
package asks.
For example, to get the complete status and description of a package, use the -s option:
# dpkg -s xsnow
Package: xsnow
Status: install ok installed
Priority: optional
Section: non-free/x11
Installed-Size: 41
Maintainer: Martin Schulze <[email protected]>
Version: 1.40-6
Depends: libc6, xlib6g (>= 3.3-5)
Description: Brings Christmas to your desktop
Xsnow is the X-windows application that will let it snow on the
root window, in between and on windows. Santa and his reindeer
will complete your festive-season feeling.
# dpkg -L xsnow
/.
/usr
/usr/doc
/usr/doc/xsnow
/usr/doc/xsnow/copyright
/usr/doc/xsnow/readme.gz
/usr/doc/xsnow/changelog.Debian.gz
/usr/X11R6
/usr/X11R6/bin
/usr/X11R6/bin/xsnow
/usr/X11R6/man
/usr/X11R6/man/man6
/usr/X11R6/man/man6/xsnow.6.gz
To go the other way around, and find which package contains a specific file, use the -S
option:
# dpkg -S /usr/doc/xsnow/copyright
xsnow: /usr/doc/xsnow/copyright
The name of the package is listed just to the left of the colon.
If you do find and download a .deb file, you can install it using the -i option:
# dpkg -d /tmp/dl/xsnow_1.40-6_i386.deb
If you can't find the package you're looking for as a .deb file, but you find a .rpm or some
other type of package, you may be able to use alien. The alien program can convert
packages from various formats into .debs.
The Linux System Administrators guide, available from Linuxdoc.org's "Guides" section, is a
good complement to this series of tutorials -- give it a read! You may also find Eric S.
Raymond's Unix and Internet Fundamentals HOWTO to be helpful.
In the Bash by example article series, we show you how to use bash programming
constructs to write your own bash scripts. This series (particularly parts one and two) will be
excellent additional preparation for the LPIC Level 1 exam:
• Bash by example, part 1: Fundamental programming in the Bourne-again shell
• Bash by example, part 2: More bash programming fundamentals
• Bash by example, part 3: Exploring the ebuild system
We highly recommend the Technical FAQ for Linux users by Mark Chapman, a 50-page
in-depth list of frequently asked Linux questions, along with detailed answers. The FAQ itself
is in PDF (Acrobat) format. If you're a beginning or intermediate Linux user, you really owe it
to yourself to check this FAQ out. We also recommend Linux glossary for Linux users, also
from Mark.
If you're not too familiar with the vi editor, we strongly recommend that you check out IBM's
Vi -- the cheat sheet method tutorial . This tutorial will give you a gentle yet fast-paced
introduction to this powerful text editor. Consider this must-read material if you don't know
how to use vi.
Your feedback
We look forward to getting your feedback on this tutorial. Additionally, you are welcome to
contact Daniel Robbins directly at [email protected].
Colophon
This tutorial was written entirely in XML, using the developerWorks Toot-O-Matic tutorial
generator. The open source Toot-O-Matic tool is an XSLT stylesheet and several XSLT
extension functions that convert an XML file into a number of HTML pages, a zip file, JPEG
heading graphics, and two PDF files. Our ability to generate multiple text and binary formats
from a single source file illustrates the power and flexibility of XML. (It also saves our
production team a great deal of time and effort.)