Debian Policy Manual - chapter 3
The Operating System


3.1 Filesystem hierarchy


3.1.1 Linux Filesystem Structure

The location of all installed files and directories must comply fully with the Linux Filesystem Structure (FSSTND). The latest version of this document can be found alongside this manual or on tsx-11.mit.edu in /pub/linux/docs/linux-standards/fsstnd/. Specific questions about following the standard may be asked on debian-devel, or referred to Daniel Quinlan, the FSSTND coordinator, at quinlan@pathname.com.


3.1.2 Site-specific programs

As mandated by the FSSTND no package should place any files in /usr/local, either by putting them in the filesystem archive to be unpacked by dpkg or by manipulating them in their maintainer scripts.

However, the package should create empty directories below /usr/local so that the system administrator knows where to place site-specific files. These directories should be removed on package removal if they are empty.

Note, that this applies only to directories below /usr/local, not in /usr/local. The directory /usr/local itself may only contain the sub-directories listed in FSSTND, section 4.8. However, you may create directories below them as you wish. You may not remove any of the directories listed in 4.8, even if you created them.

Since /usr/local may be mounted read-only from a remote server, these directories have to be created and removed by the postinst and prerm maintainer scripts. These scripts must not fail if either of these operations fail. (In the future, it will be possible to tell dpkg not to unpack files matching certain patterns, so that the directories can be included in the .deb packages and system administrators who do not wish these directories in /usr/local do not need to have them.)

For example, the emacs package will contain

   mkdir -p /usr/local/lib/emacs/site-lisp || true
in the postinst script, and
   rmdir /usr/local/lib/emacs/site-lisp && \
   rmdir /usr/local/lib/emacs || \
      true
in the prerm script.

If you do create a directory in /usr/local for local additions to a package, you must ensure that settings in /usr/local take precedence over the equivalents in /usr.

The /usr/local directory itself and all the subdirectories created by the package should have permissions 2775 (group-writable and set-group-id) and be owned by root.staff.


3.2 Users and groups

The Debian system can be configured to use either plain or shadow passwords.

Some user ids (UIDs) and group ids (GIDs) are reserved globally for use by certain packages. Because some packages need to include files which are owned by these users or groups, or need the ids compiled into binaries, these ids must be used on any Debian system only for the purpose for which they are allocated. This is a serious restriction, and we should avoid getting in the way of local administration policies. In particular, many sites allocate users and/or local system groups starting at 100.

Apart from this we should have dynamically allocated ids, which should by default be arranged in some sensible order--but the behaviour should be configurable.

No package except base-passwd may modify /etc/passwd, /etc/shadow, or /etc/group.

The UID and GID ranges are as follows:

0-99:
Globally allocated by the Debian project, must be the same on every Debian system. These ids will appear in the passwd and group files of all Debian systems, new ids in this range being added automatically as the base-passwd package is updated.

Packages which need a single statically allocated uid or gid should use one of these; their maintainers should ask the base-passwd maintainer for ids.

100-999:
Dynamically allocated system users and groups. Packages which need a user or group, but can have this user or group allocated dynamically and differently on each system, should use `adduser --system' to create the group and/or user. adduser will check for the existence of the user or group, and if necessary choose an unused id based on the ranged specified in adduser.conf.

1000-29999:
Dynamically allocated user accounts. By default adduser will choose UIDs and GIDs for user accounts in this range, though adduser.conf may be used to modify this behaviour.

30000-59999:
Reserved.

60000-64999:
Globally allocated by the Debian project, but only created on demand. The ids are allocated centrally and statically, but the actual accounts are only created on users' systems on demand.

These ids are for packages which are obscure or which require many statically-allocated ids. These packages should check for and create the accounts in /etc/passwd or /etc/group (using adduser if it has this facility) if necessary. Packages which are likely to require further allocations should have a `hole' left after them in the allocation, to give them room to grow.

65000-65533:
Reserved.

65534:
User `nobody.'

65535:
(uid_t)(-1) == (gid_t)(-1). NOT TO BE USED, because it is the error return sentinel value.


3.3 Files


3.3.1 Binaries

It is not allowed that two packages install programs with different functionality but with the same filenames. (The case of two programs having the same functionality but different implementations is handled via `alternatives.') If this case happens, one of the programs has to be renamed. The maintainers should report this to the developers' mailing and try to find a consensus about which package will have to be renamed. If a consensus can not be reached, both programs must be renamed.

Generally the following compilation parameters should be used:

   CC = gcc 
   CFLAGS = -O2 -g -Wall # sane warning options vary between programs 
   LDFLAGS = # none 
   install -s # (or use strip on the files in debian/tmp)

Note that all installed binaries should be stripped, either by using the -s flag to install, or by calling strip on the binaries after they have been copied into debian/tmp but before the tree is made into a package.

The -g flag is useful on compilation so that you have available a full set of debugging symbols in your built source tree, in case anyone should file a bug report involving (for example) a core dump.

The -N flag should not be used. On a.out systems it may have been useful for some very small binaries, but for ELF it has no good effect.

It is up to the package maintainer to decide what compilation options are best for the package. Certain binaries (such as computationally-intensive programs) may function better with certain flags (-O3, for example); feel free to use them. Please use good judgment here. Don't use flags for the sake of it; only use them if there is good reason to do so. Feel free to override the upstream author's ideas about which compilation options are best--they are often inappropriate for our environment.


3.3.2 Libraries

All libraries must have a shared version in the lib package and a static version in the lib-dev package. The shared version must be compiled with -fPIC, and the static version must not be. In other words, each *.c file is compiled twice.

You have to specify the gcc option -D_REENTRANT when building a library (either static or shared) to make the library compatible with LinuxThreads.

Note that all installed shared libraries should be stripped with

   strip --strip-unneeded <your-lib>
(The option `--strip-unneeded' makes strip remove only the symbols which aren't needed for relocation processing.) Shared libraries can function perfectly well when stripped, since the symbols for dynamic linking are in a separate part of the ELF object file.

Note that under some circumstances it may be useful to install a shared library unstripped, for example when building a separate package to support debugging.

Please make sure that you use only released versions of shared libraries to build your packages; otherwise other users will not be able to run your binaries properly. Producing source packages that depend on unreleased compilers is also usually a bad idea.


3.3.3 Shared libraries

Packages involving shared libraries should be split up into several binary packages.

For a straightforward library which has a development environment and a runtime kit including just shared libraries you need to create two packages: librarynamesoname (soname is the shared object name of the shared library--it's the thing that has to match exactly between building an executable and running it for the dynamic linker to be able run the program; usually the soname is the major number of the library) and librarynamesoname-dev.

If you prefer only to support one development version at a time you may name the development package libraryname-dev; otherwise you may wish to use dpkg's conflicts mechanism to ensure that the user only installs one development version at a time (after all, different development versions are likely to have the same header files in them, causing a filename clash if both are installed). Typically the development version will also need an exact version dependency on the runtime library, to make sure that compilation and linking happens correctly.

Packages which use the shared library should have a dependency on the name of the shared library package, librarynamesoname. When the soname changes you can have both versions of the library installed while moving from the old library to the new.

If your package has some run-time support programs which use the shared library you must not put them in the shared library package. If you do that then you won't be able to install several versions of the shared library without getting filename clashes. Instead, either create a third package for the runtime binaries (this package might typically be named libraryname-runtime--note the absence of the soname in the package name) or if the development package is small include them in there.

If you have several shared libraries built from the same source tree you can lump them all together into a single shared library package, provided that you change all their sonames at once (so that you don't get filename clashes if you try to install different versions of the combined shared libraries package).

Follow the directions in the Debian Packaging Manual for putting the shared library in its package, and make sure you include a shlibs control area file with details of the dependencies for packages which use the library.

Shared libraries should not be installed executable, since ld.so does not require this and trying to execute a shared library results in a core dump.


3.3.4 Scripts

All command scripts, including the package maintainer scripts inside the package and used by dpkg, should have a #! line naming the shell to be used to interpret them.

In the case of Perl scripts this should be #!/usr/bin/perl.

Shell scripts (sh and bash) should almost certainly start with set -e so that errors are detected. Every script must use set -e or check the exit status of every command.

The standard shell interpreter `/bin/sh' may be a symbolic link to any POSIX compatible shell. Thus, shell scripts specifying `/bin/sh' as interpreter may only use POSIX features. If a script requires non-POSIX features from the shell interpreter, the appropriate shell has to be specified in the first line of the script (e.g., `#!/bin/bash') and the package has to depend on the package providing the shell (unless the shell package is marked `Essential', e.g., in the case of bash).

Restrict your script to POSIX features when possible so that it may use /bin/sh as its interpreter. If your script works with ash, it's probably POSIX compliant, but if you are in doubt, use /bin/bash.

Perl scripts should check for errors when making any system calls, including open, print, close, rename and system.

csh and tcsh should be avoided as scripting languages. See Csh Programming Considered Harmful, one of the comp.unix.* FAQs. It can be found on rtfm.mit.edu in /pub/usenet-by-group/comp.unix.programmer/Csh_Programming_Considered_Harmful. If an upstream package comes with csh scripts then you must make sure that they start with #!/bin/csh and make your package depend on the c-shell virtual package.

Any scripts which create files in world-writable directories (e.g., in /tmp) have to use a mechanism which will fail if a file with the same name already exists.

The Debian base distribution provides the tempfile and mktemp utilities for use by scripts for this purpose.


3.3.5 Symbolic links

In general, symbolic links within a toplevel directory should be relative, and symbolic links pointing from one toplevel directory into another should be absolute. (A toplevel directory is a sub-directory of the root directory `/'.)

In addition, symbolic links should be specified as short as possible, i.e., link targets like `foo/../bar' are depreciated.

Note that when creating a relative link using ln it is not necessary for the target of the link to exist relative to the working directory you're running ln from; nor is it necessary to change directory to the directory where the link is to be made. Simply include the string that should appear as the target of the link (this will be a pathname relative to the directory in which the link resides) as the first argument to ln.

For example, in your Makefile or debian/rules, do things like:

   ln -fs gcc $(prefix)/bin/cc 
   ln -fs gcc debian/tmp/usr/bin/cc 
   ln -fs ../sbin/sendmail $(prefix)/bin/runq 
   ln -fs ../sbin/sendmail debian/tmp/usr/bin/runq

A symbolic link pointing to a compressed file should always have the same file extension as the referenced file. (For example, if a file `foo.gz' is referenced by a symbolic link, the filename of the link has to end with `.gz' too, as in `bar.gz.')


3.3.6 Device files

No package may include device files in the package file tree.

If a package needs any special device files that are not included in the base system, it has to call makedev in the postinst script, after asking the user for permission to do so.

No package should remove any device files in the postrm or any other script. This is left to the system administrator.

Debian uses the serial devices /dev/tty*. Programs using the old /dev/cu* devices should be changed to use /dev/tty*.


3.3.7 Configuration files

Any configuration files created or used by your package should reside in /etc. If there are several you should consider creating a subdirectory named after your package.

It is almost certain that any file in /etc that is in your package's filesystem archive should be listed in dpkg's conffiles control area file. (See the Debian Packaging Manual).

Only packages that are tagged conflicting with each other may specify the same file as conffile. A package may not modify a configuration file of another package.

If two or more packages use the same configuration file, one of these packages has to be defined as owner of the configuration file, i.e., it has to list the file as conffile and has to provide a program that modifies the configuration file.

The other packages have to depend on the owner package and use that program to update the configuration file.

Sometimes it's appropriate to build a new package, which just provides the basic infrastructure for the other packages and which manages the shared configuration files. (Check out the sgml-base package as an example.)

Files in /etc/skel will automatically be copied into new user accounts by adduser. They should not be referenced there by any program.

Therefore, if a program needs a dotfile to exist in advance in $HOME to work sensibly that dotfile should be installed in /etc/skel (and listed in conffiles, if it is not generated and modified dynamically by the package's installation scripts).

However, programs that require dotfiles in order to operate sensibly (dotfiles that they do not create themselves automatically, that is) are a bad thing, and programs should be configured by the Debian default installation as close to normal as possible.

Therefore, if a program in a Debian package needs to be configured in some way in order to operate sensibly that configuration should be done in a site-wide global configuration file elsewhere in /etc. Only if the program doesn't support a site-wide default configuration and the package maintainer doesn't have time to add it should a default per-user file be placed in /etc/skel.

/etc/skel should be as empty as we can make it. This is particularly true because there is no easy mechanism for ensuring that the appropriate dotfiles are copied into the accounts of existing users when a package is installed.

Ideally the sysadmin should not have to do any configuration other than that done (semi-)automatically by the postinst script.


3.3.8 Permissions and owners

The rules in this section are guidelines for general use. If necessary you may deviate from the details below. However, if you do so you must make sure that what is done is secure and you must try to be as consistent as possible with the rest of the system. You should probably also discuss it on debian-devel first.

Files should be owned by root.root, and made writable only by the owner and universally readable (and executable, if appropriate).

Directories should be mode 755 or (for group-writability) mode 2775. The ownership of the directory should be consistent with its mode--if a directory is mode 2775, it should be owned by the group that needs write access to it.

Setuid and setgid executables should be mode 4755 or 2755 respectively, and owned by the appropriate user or group. They should not be made unreadable (modes like 4711 or 2711 or even 4111); doing so achieves no extra security, because anyone can find the binary in the freely available Debian package--it is merely inconvenient. For the same reason you should not restrict read or execute permissions on non-set-id executables.

Some setuid programs need to be restricted to particular sets of users, using file permissions. In this case they should be owned by the uid to which they are set-id, and by the group which should be allowed to execute them. They should have mode 4754; there is no point in making them unreadable to those users who must not be allowed to execute them.

Do not arrange that the system administrator can only reconfigure the package to correspond to their local security policy by changing the permissions on a binary. Ordinary files installed by dpkg (as opposed to conffiles and other similar objects) have their permissions reset to the distributed permissions when the package is reinstalled. Instead you should consider (for example) creating a group for people allowed to use the program(s) and making any setuid executables executable only by that group.

If you need to create a new user or group for your package there are two possibilities. Firstly, you may need to make some files in the binary package be owned by this user or group, or you may need to compile the user or group id (rather than just the name) into the binary (though this latter should be avoided if possible). In this case you need a statically allocated id.

You must ask for a user or group id from the base system maintainer, and must not release the package until you have been allocated one. Once you have been allocated one you must make the package depend on a version of the base system with the id present in /etc/passwd or /etc/group, or alternatively arrange for your package to create the user or group itself with the correct id (using adduser) in its pre- or post-installation script (the latter is to be preferred if it is possible).

On the other hand, the program may able to determine the uid or gid from the group name at runtime, so that a dynamic id can be used. In this case you must choose an appropriate user or group name, discussing this on debian-devel and checking with the base system maintainer that it is unique and that they do not wish you to use a statically allocated id instead. When this has been checked you must arrange for your package to create the user or group if necessary using adduser in the pre- or post-installation script (again, the latter is to be preferred if it is possible).

Note that changing the numeric value of an id associated with a name is very difficult, and involves searching the filesystem for all appropriate files. You need to think carefully whether a static or dynamic id is required, since changing your mind later will cause problems.


3.4 System run levels


3.4.1 Introduction

The /etc/init.d directory contains the scripts executed by init at boot time and when init state (or `runlevel') is changed (see init(8)).

These scripts are being referenced by symbolic links in the /etc/rcn.d directories. When changing runlevels, init looks in the directory /etc/rcn.d for the scripts it should execute, where n is the runlevel that is being changed to, or `S' for the boot-up scripts.

The names of the links all have the form Smmscript or Kmmscript where mm is a two-digit number and script is the name of the script (this should be the same as the name of the actual script in /etc/init.d. When init changes runlevel first the targets of the links whose names starting with a K are executed, each with the single argument stop, followed by the scripts prefixed with an S, each with the single argument start. The K links are responsible for killing services and the S link for starting services upon entering the runlevel.

For example, if we are changing from runlevel 2 to runlevel 3, init will first execute all of the K prefixed scripts it finds in /etc/rc3.d, and then all of the S prefixed scripts. The links starting with K will cause the referred-to file to be executed with an argument of stop, and the S links with an argument of start.

The two-digit number mm is used to decide which order to start and stop things in--low-numbered links have their scripts run first. For example, the K20 scripts will be executed before the K30 scripts. This is used when a certain service must be started before another. For example, the name server bind might need to be started before the news server inn so that inn can set up its access lists. In this case, the script that starts bind should have a lower number than the script that starts inn so that it runs first:

   /etc/rc2.d/S17bind
   /etc/rc2.d/S70inn

3.4.2 Writing the scripts

Packages can and should place scripts in /etc/init.d to start or stop services at boot time or during a change of runlevel. These scripts should be named /etc/init.d/package, and they should accept one argument, saying what to do:
start
start the service,

stop
stop the service,

restart
stop and restart the service,

reload
cause the configuration of the service to be reloaded without actually stopping and restarting the service,

force-reload
cause the configuration to be reloaded if the service supports this, otherwise restart the service.

The start, stop, restart, and force-reload options must be supported by all scripts in /etc/init.d, the reload option is optional.

The init.d scripts should ensure that they will behave sensibly if invoked with start when the service is already running, or with stop when it isn't, and that they don't kill unfortunately-named user processes. The best way to achieve this is usually to use start-stop-daemon.

If a service reloads its configuration automatically (as in the case of cron, for example), the reload option of the init.d script should behave as if the configuration has been reloaded successfully.

These scripts should not fail obscurely when the configuration files remain but the package has been removed, as the default in dpkg is to leave configuration files on the system after the package has been removed. Only when it is executed with the --purge option will dpkg remove configuration files. Therefore, you should include a test statement at the top of the script, like this:

   test -f program-executed-later-in-script || exit 0

3.4.3 Managing the links

A program is provided, update-rc.d, to make it easier for package maintainers to arrange for the proper creation and removal of /etc/rcn.d symbolic links from their postinst and postrm scripts.

You should use this script to make changes to /etc/rcn.d and never include any /etc/rcn.d symbolic links in the actual archive.

By default update-rc.d will start services in each of the multi-user state runlevels (2, 3, 4, and 5) and stop them in the halt runlevel (0), the single-user runlevel (1) and the reboot runlevel (6). The system administrator will have the opportunity to customize runlevels by simply adding, moving, or removing the symbolic links in /etc/rcn.d.

To get the default behaviour for your package, put in your postinst script

   update-rc.d package default >/dev/null
and in your postrm
   if [ purge = "$1" ]; then
       update-rc.d package remove >/dev/null
   fi

This will use a default sequence number of 20. If it does not matter when or in which order the script is run, use this default. If it does, then you should talk to the maintainer of the sysvinit package or post to debian-devel, and they will help you choose a number.

For more information about using update-rc.d, please consult its manpage update-rc.d(8).


3.4.4 Boot-time initialisation

There is another directory, /etc/rc.boot, which contains scripts which are run once per machine boot. This facility is provided for initialisation of hardware devices, cleaning up of leftover files, and so forth.

For example, the kbd package provides a script here for initialising the keyboard layout and console font and mode.

The files in /etc/rc.boot should not be links into /etc/init.d--they should be the scripts themselves.

rc.boot should not be used for starting general-purpose daemons and similar activities. This should be done using the rcn.d scheme, above, so that the services can be started and stopped cleanly when the runlevel changes or the machine is to be shut down or rebooted.


3.4.5 Notes

Do not include the /etc/rcn.d/* symbolic links in the .deb filesystem archive! This will cause problems! You should create them with update-rc.d, as above.

Do not include the /etc/rcn.d/* symbolic links in dpkg's conffiles list! This will cause problems! Do, however, include the /etc/init.d scripts in conffiles. (This is important since we want to give the local system administrator the chance to adapt the scripts to the local system--e.g., to disable a service without deinstalling the package, or to specify some special command line options when starting a service--while making sure her changes aren't lost during the next package upgrade.)


3.4.6 Example

The bind DNS (nameserver) package wants to make sure that the nameserver is running in multiuser runlevels, and is properly shut down with the system. It puts a script in /etc/init.d, naming the script appropriately bind. As you can see, the script interprets the argument reload to send the nameserver a HUP signal (causing it to reload its configuration); this way the user can say /etc/init.d/bind reload to reload the name server.

   #!/bin/sh
   #
   # Original version by Robert Leslie <rob@mars.org>, edited by iwj and cs

   test -x /usr/sbin/named || exit 0

   case "$1" in
     start)
       echo -n "Starting domain name service: named"
       start-stop-daemon --start --quiet --exec /usr/sbin/named
       echo "."
       ;;
     stop)
       echo -n "Stopping domain name service: named"
       start-stop-daemon --stop --quiet  \
           --pidfile /var/run/named.pid --exec /usr/sbin/named
       echo "."
       ;;
     restart)
       echo -n "Restarting domain name service: named"
       start-stop-daemon --stop --quiet  \
           --pidfile /var/run/named.pid --exec /usr/sbin/named
       start-stop-daemon --start --verbose --exec /usr/sbin/named
       echo "."
       ;;
     force-reload|reload)
       echo -n "Reloading configuration of domain name service: named"
       start-stop-daemon --stop --signal 1 --quiet  \
           --pidfile /var/run/named.pid --exec /usr/sbin/named
       echo "."
       ;;
     *)
       echo "Usage: /etc/init.d/bind {start|stop|restart|reload|force-reload}" >&2
       exit 1
       ;;
   esac

   exit 0

Another example on which to base your /etc/init.d scripts is in /etc/init.d/skeleton.

If this package is happy with the default setup from update-rc.d, namely an ordering number of 20 and having named running in all runlevels, it can say in its postinst:

   update-rc.d bind default >/dev/null
And in its postrm, to remove the links when the package is purged:
   if [ purge = "$1" ]; then
        update-rc.d acct remove >/dev/null
   fi


3.5 Cron jobs

Packages may not touch the configuration file /etc/crontab, nor may they modify the files in /var/spool/cron/crontabs.

If a package wants to install a job that has to be executed via cron, it should place a file with the name if the package in one of the following directories:

     /etc/cron.daily
     /etc/cron.weekly
     /etc/cron.monthly
As these directory names say, the files within them are executed on a daily, weekly, or monthly basis, respectively.

If a certain job has to be executed more frequently than `daily,' the package should install a file /etc/cron.d/<package-name> tagged as configuration file. This file uses the same syntax as /etc/crontab and is processed by cron automatically. (Note, that scripts in the /etc/cron.d directory are not handled by anacron. Thus, you should only use this directory for jobs which may be skipped if the system is not running.)

All files installed in any of these directories have to be scripts (shell scripts, Perl scripts, etc.) so that they can easily be modified by the local system administrator. In addition, they have to be registered as configuration file.

The scripts in these directories have to check, if all necessary programs are installed before they try to execute them. Otherwise, problems will arise when a package was removed (but not purged), since the configuration files are kept on the system in this situation.


3.6 Console messages

This section describes different formats for messages written to standard output by the /etc/init.d scripts. The intent is to improve the consistency of Debian's startup and shutdown look and feel.

Please look very careful at the details. We want to get the messages to look exactly the same way concerning spaces, punctuation, and case of letters.

Here is a list of overall rules that you should use when you create output messages. They can be useful if you have a non-standard message that isn't covered in the sections below.

The following formats must be used


3.7 Menus

The Debian menu packages provides a unique interface between packages providing applications and documents, and menu programs (either X window managers or text-based menu programs as pdmenu).

All packages that provide applications that need not be passed any special command line arguments for normal operation should register a menu entry for those applications, so that users of the menu package will automatically get menu entries in their window managers, as well in shells like pdmenu.

Please refer to the Debian Menu System document that comes with the menu package for information about how to register your applications and web documents.


3.8 Keyboard configuration

To achieve a consistent keyboard configuration (i.e., all applications interpret a keyboard event the same way) all programs in the Debian distribution have to be configured to comply with the following guidelines.

Here is a list that contains certain keys and their interpretation:

<--
delete the character to the left of the cursor

Delete
delete the character to the right of the cursor

Control+H
emacs: the help prefix

The interpretation of any keyboard events should be independent of the terminal that's used (either the console, X windows, rlogin/telnet session, etc.).

The following list explains how the different programs should be set up to achieve this:

This will solve the problem except for:


3.9 Environment variables

No program may depend on environment variables to get reasonable defaults. (That's because these environment variables would have to be set in a system-wide configuration file like /etc/profile, which is not supported by all shells.)

If a program should depend on environment variables for its configuration, the program has to be changed to fall back to a reasonable default configuration if these environment variables are not present. If this cannot be done easily (e.g., if the source code of a non-free program is not available), the program should be replaced by a small `wrapper' shell script which sets the environment variables and calls the original program.

Here is an example of a wrapper script for this purpose:

#!/bin/sh
BAR=/var/lib/fubar
export BAR
exec /usr/lib/foo/foo "$@"

Furthermore, as /etc/profile is a configuration file of the bash package, no other package may put any environment variables or other commands into that file.


Debian Policy Manual - Copyright ©1996,1997,1998 Ian Jackson and Christian Schwarz.
Contents; abstract; next; back.
version 2.4.1.2, 14 April 1998
Ian Jackson ijackson@gnu.ai.mit.edu
Christian Schwarz schwarz@debian.org
revised: David A. Morris bweaver@debian.org